CPPTags: A Context Aware C/C++ tagger

Abstract:

CPPTags plugs into event handlers for text editors such as Vim, Jed and SciTE, and utilises standard tools such as Exuberant Ctags and the C Preprocessor (CPP) to produce a tag file. Tag files are used by these editors to implement call tips, source location and symbol completion.

Why do I need it?

If you have become used to call tips, symbol completion and symbol location as a means of navigating through code, and find the use of tag files in unix editors to be just a bit clunky then this tool might be for you.

Typically, to use symbol location from within vi, the main unix source editor, you are expected to generate the tags file as a project-wide index to the symbols used in your project. You can then use a key binding from within your editor to locate the tag for the symbol over your current curser position.

The general recommendation is to run ctags -R (recursive) on the whole of your project source, by including a make tags rule in your makefile.

What makes it rather useless in practice, is that the tag file quickly gets out of synch with the file you are editing, and quite often refers you to symbol definitions which have no bearing or relationship to the context of your current edited source. Furthermore, the tag file you generated seldom includes symbol references for the system headers referenced by your source file, and so is unable to locate symbols from included libraries.

To make the location of symbols relevant to your current source file, you need the tags file to be dynamic. Whenever the editor switches to a new buffer, or whenever you load or save a source file, you effectively need the tags file to change to reflect your current symbol space.

How does it work?

CPPTags is a small C program that ties together a few common unix utilities, and interprets their output so as to produce a context aware tag file. The first stage is to send the current source file to the GNU C Preprocessor, CPP. This produces a single C source file, containing any files referenced by #include directives, and with any macros expanded. This file also contains line number references to the original included source files.

After producing the preprocessed file, we run exuberant ctags against that file, which generates a complete list of all symbols and where they may be found in the preprocessed file. Note that these locations are now relative to the preprocessed file, and no longer relative to the edited or included source.

The last stage is to read the output of the ctags program, match the tag locations back to the locations in the preprocessed file, and from there back to locations in the original source files. We re-read the source files where appropriate to extract the definitions as they appear before macro expansion, and re-produce the tag file to accurately reflect the current context.

The cpptags program is then bound to editor events such as file load or buffer switching through their normal plugin mechanisms.

Which editors are supported?

At the time of this writing, the project includes plugins for the Vim, Jed and SciTE text editors.

Since the tool is externally dependent only on common tools, and is a simple command line, it is quite easily integrated with any editor which supports the tag file format. Notably, SciTE uses it's own .API file format, which is produced directly by cpptags through means of a command line switch. At present, cpptags contains no support for the etags format as used by GNU emacs.

How do I use it?

CPPTags depends on a bash script, the C preprocessor (/usr/bin/cpp) and the exuberant ctags application. First ensure that these are all available. Next, install the cpptags binary and the mkctags shell script in your path. The mkctags script must then be edited to ensure that it accurately matches your compile time environment; private include paths, macro definitions for conditional compilation, and so forth to be specified.

The mkctags bash shell script is called from cpptags to interface with and execute both the cpp and ctags programs. The options are mostly configurable to suit your needs. The idea is to ensure that you have control over the eventual format of the tag file without having to dig into C source code.

It works well to keep a specialised mkctags script in the same directory as your source, and have your execution path include current working directory as the first search path.

Once all of that is set up, use one of the provided plugin scripts for your editor to tie in the cpptags application, and you are ready to roll. Just edit your C/C++ source, and the rest should be automatic. The plugin scripts invoke the application to produce a tags file on demand as required. There is a [usually] negligible delay on file load/save or buffer switch whilst the application does it's work. The amount of delay one may expect clearly depends on the complexity of the current source, but is generally sub-second.

Full installation instructions are available in the README file.

How can I contribute?

Use it!

If you have to do anything special to get it to work, contribute your fix back to the project. This includes any editor plugins, as well as any possible code changes needed. For example, if you decide to add code to generate etags, format, please contribute your patch (hint, hint).

Suggestions for improvements always welcome.

Final words

CPPTags was primarily written to fill a personal need. As such I have found it to be useful. Since I have been using open source software for over a decade in both my personal as well as my business capacity, with only infrequent contributions in the way of bug fixes or feedback, it is high time that I contribute something a little more substantial.

I sincerely hope that you similarly find the tool to be useful.

Best wishes

Paul Sephton