ifdex — report C macro names that might be configuration symbols or port guards


ifdex [-c] [-i groups]
      [-e extension]… [-x exclude]… [-X excludefile]…
      [-E] [-?] [file-or-dir…]


The purpose of this tool is to walk through a C codebase and generate a report listing symbols used as conditionals in #if/#ifdef/#ifndef/#elif lines.

This is useful information to have if you are trying to identify configuration symbols intended to be set by a build system. The use case this tool was originally built for was prying 227 KLOC of C loose from the clammy grip of a 31KLOC pile of autoconf.

It is also useful for identifying and listing port guards - that is, conditionals around platform specific header includes or port code.

Finally, it it useful for catching unused and broken conditionalizing symbols; any sufficiently large codebase has a few and they are notoriously difficult to notice by eyeball.

By default, there are several internal lists of symbols to be ignored. These are:

Macros defined in POSIX.1-2001 or in accepted RFCs on IPv6.
Macros associated with standards extensions in a particular compiler or C library (usually GNU), or in a common service library such as OpenSSL that is not part of POSIX.
Macros specific to particular OSes.
Macros specific to tools like lint, Yacc/Bison, and static checkers
Compiler/platform symbols that commonly show up in guards on portability shims.

The -i option lets you specify a comma-separated list of groups to restrict your report to.

Give it any number of file or directory names. Directories are recursed into. If no file or directory names are given, the tool accepts a path list on standard input, such as might be generated by find(1).

When recursing into a directory or taking filenames from standard input it by default processes files with the extensions .c, .h, .cpp, .y, and .l. This filter is not applied to filename arguments on the command line.

By default the tool emits a sorted list of symbol names. It can be told to emit output like C compiler error messages, one per symbol occurrence; this can be stepped through in Emacs’s compilation mode.

The -X option can be used to pass ifdex a file of exclusions. Each line is interpreted as follows:

  1. The strings /* and */ are removed, then leading and trailing whitesspace stripped.
  2. Blank lines are ignored.
  3. If the line befins with #define or #undef, the symbol after it is extracted and will be ignored.
  4. Otherwise all lines beginning with # are ignored.

Remaining lines are stripped of #-led comments and leading/trailing whitespace; what’s left is treated as an anchored Python regexp (that is, as though surrounded by ^ $) which selects symbols to be excluded.

The effect of these rules is to allow you to both (a) use a config.h in the form generated by autotools or waf to exclude symbols the configuration system knows already how to set, and (b) write your own list of exclusion regexps, with explanatory comments.


Report in a compiler-like format, with file and line number per symbol occurrence.
-e ext
Add a file extension to the default list (.c, .h, .cpp, .y, .l) of files to be scanned.
Dump the internal list of ignored symbols, with explanations. May be restricted by -i.
Specify a comma-separated list of groups to ignore. The default is all groups.
-x regexp
Add a Python regular expression to the list of exclusions. If a symbol matches an exclusion it will be ignored. A common thing you might want to specify is, for example, "^DEBUG$"
-X file
Look in each line of the specified file for an exclusion regexp.
Issue a usage summary.


The full perversity of cpp’s rules - which treat comments as whitespace - is not quite captured.

When using -E, any -i option after -E on the command line rather than before it will be ignored.

The list of symbols to be ignored is incomplete - perhaps inevitably so.


Report bugs to Eric S. Raymond <>. The project page is at