Feb 2020

By default, running ctags on a C source file only generates tags for symbols defined inside that very file. I usually find it more convenient to generate tags for all the symbols in the included header files as well.

To do this, we can use our C preprocessor’s ability to generate make targets: cc -M foo.c. I use a very simple search pattern to filter out only the .c and .h file names and pipe that into ctags.

The whole incantation is relatively simple:

tags() {
    ${CC:-cc} $CFLAGS -M $@ \
    |grep -o '[^ ]*\.[ch]' \
    |ctags -L - --kinds-c=+px
}

I put $CFLAGS there to pick up includedirs if necessary (although that requires the variable to be set appropriate from whatever context this gets called). ctags requires the -L - option to take filenames from STDIN. The option --kinds-c=+px adds function prototypes and external variables to the tagfile.

NOTE: You need to set $CC to a C compiler that supports dependency generation in Makefile format, like GCC and Clang. GCC’s standalone preprocessor executable cpp also works.

NOTE: This method will only pickup on conditionally defined symbols and conditionally included files if the conditions are met. E.g. you could export a CFLAGS variable, defining the constants that are checked by those ifdefs.

See also: