Download cppp-2.9.tar.gz
Sourcehut page

A Partial Preprocessor for C

cppp is a "partial C preprocessor". It does a tiny fraction of the job of the C preprocessor — namely the application of a subset of the #ifdef statements. The user runs cppp with one more macro symbols defined, or undefined, on the command line. If any of those macro symbols appear in an #ifdef statement, its effects are applied. All other preprocessor symbols are treated as indeterminate, and do not affect the output. The term "#ifdef statements" actually refers to all forms of conditional inclusion in the preprocessor, and includes #ifdef, #ifndef, #if directives, as well as #elif, #elifdef, and #elifndef.

Here are some simple illustrative examples that should make cppp's effect clear:

Input file Output from
cppp -DFOO
Output from
cppp -DBAR
Output from
cppp -UFOO -UBAZ
/* Comments stand for code */
#ifdef FOO
/* FOO is defined */
# ifdef BAR
/* FOO & BAR are defined */
# else
/* BAR is not defined */
# endif
#else
/* FOO is not defined */
# ifndef BAZ
/* FOO & BAZ are undefined */
# endif
#endif
/* Comments stand for code */
/* FOO is defined */
# ifdef BAR
/* FOO & BAR are defined */
# else
/* BAR is not defined */
# endif
/* Comments stand for code */
#ifdef FOO
/* FOO is defined */
/* FOO & BAR are defined */
#else
/* FOO is not defined */
# ifndef BAZ
/* FOO & BAZ are undefined */
# endif
#endif
/* Comments stand for code */
/* FOO is not defined */
/* FOO & BAZ are undefined */

In addition to removing #ifdef statements, cppp understands complex expressions in #if statements that make use of the defined operator. In cases where an expression is only partly determined, cppp will output an edited test with just the indeterminate expression. Some more examples:

Input file Output from
cppp -UFOO
Output from
cppp -UFOO -UBAZ
/* Yet another illustrative example */
#if (defined(FOO) || defined(BAR))
/* FOO or BAR */
#elif !defined(FOO) && !defined(BAZ)
/* not FOO and not BAZ */
#endif
/* Yet another illustrative example */
#if defined(BAR)
/* FOO or BAR */
#elif !defined(BAZ)
/* not FOO and not BAZ */
#endif
/* Yet another illustrative example */
#if defined(BAR)
/* FOO or BAR */
#else
/* not FOO and not BAZ */
#endif

Finally, cppp will let you assign a numeric constant to a defined symbol, for situations where arithmetical tests are used:

Input file Output from
cppp -DMYLIB_VERSION=0x0102
Output from
cppp -DMYLIB_VERSION=0x0200
/* Test the library's API version */
#if MYLIB_VERSION >= ((1 << 8) | 13)
/* use the newer API */
#else
/* use the older API */
#endif
/* Test the library's API version */
/* use the older API */
/* Test the library's API version */
/* use the newer API */

It's worth noting, however, that cppp can't resolve comparisons with anything other than integral constants. In particular, a test that involves another macro value will remain indeterminate, unless those macro symbols are also defined on the command line.

cppp is mainly useful in dealing with legacy codebases, where #ifdef statements have crept in over time, to the general detriment of legibility. I originally created this program as a learning exercise, but several years later it proved its worth by saving me from what would have been a tedious and error-prone task. (Unfortunately, because of the nature of its origin, it's pretty unpleasant to look at in several places. I've managed to clean it up around the edges, but the central logic is messy and opaque. Use the program, not the source.)

cppp is distributed under the GNU General Public License, version 2 (or, at your option, any later version). Share and enjoy. Questions, comments, and bug reports should be directed to me.


Software
Brian Raiter