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.