CPPFLAGS
seems to be an invention of GNU Make, referenced in some of its built-in recipes. Unlike CFLAGS
, it is used in recipes for multiple languages, including, for example, Fortran.
If your program is built by some Free software distributions, you may find that some of them require packages to interpolate this variable, using CPPFLAGS
for passing down options like -D_WHATEVER=1
for passing down a macro definition.
That said, I've never seen a project advertise CPPFLAGS
as something that is a good idea to use in order to customize its build behavior.
It seems uncommon for a distro to pass CPPFLAGS
to all packages, and requires them to handle it (as a matter of documented fact about that distro). I seem to remember Gentoo does this; I'd love to be informed about any other.
It's not uncommon for custom build rules in projects to neglect to interpolate $(CPPFLAGS)
into the $(CC)
command line. Neglecting to interpolate $(CPPFLAGS)
has no effect on a program being build by any of the common distros, from Debian to Yocto or what have you.
Furthermore, when preprocessor flags are passed, they appear in CFLAGS
. So even if you support CPPFLAGS
(whether by way of using built-in GNU Make rules, or imitating them) you cannot assume that only CPPFLAGS
will contain flags for preprocessing.
Separation of preprocessor flags from CFLAGS
is unnecessary because:
There is a way to run gcc
to do preprocessing only. That gcc
command can still take compiler options not related to preprocessing.
Conversely, the stand-alone GNU cpp
is tolerant to compiler options, such as -W
warnings that do not pertain to preprocessing and even code generation options like -fstrict-aliasing
and the linker-pass through like -Wl,--whatever
.
So generally speaking, build systems that need to call the stand-alone preprocessor for whatever reason on C code can just pass it $(CFLAGS)
.
It's easy enough for the application developers to write GNU Make code to separate preprocessor flags out of $(CFLAGS)
:
cpp_only_flags := $(foreach arg, \
$(CFLAGS), \
$(or $(filter -D%,$(arg)), \
$(filter -U%,$(arg)), \
$(filter -I%,$(arg)), \
$(filter -iquote%,$(arg)), \
$(filter -W%,$(arg)), \
$(filter -M%,$(arg)))) \
$(CPPFLAGS) # also pull this in
all:
@echo cpp_only_flags == $(cpp_only_flags)
Demo:
$ make CFLAGS="-Wall -I/path/to/include -W -UMAC -DFOO=bar -o foo.o -lm"
cpp_only_flags == -Wall -I/path/to/include -W -UMAC -DFOO=bar
In the case of the GNU compiler and preprocessor, this is probably unnnecessary; but it illustrates a technique that could be used for non-GNU compilers and preprocessors, in a build system based on GNU Make.
Nonetheless, interpolating $(CPPFLAGS)
into build rules seems like a good idea just because GNU Make does it in its own rules.
Also, as mentioned already, GNU Make pulls in the same CPPFLAGS
variable into build rules for different languages, whereas CFLAGS
is only for C. For instance if we have a project that has preprocessed Fortran, as well as C, then CPPFLAGS
will act globally across the C and Fortran, which could be something useful in that kind of project.
In summary,
there is no harm in supporting CPPFLAGS
;
some distros out there use it (Gentoo?) which makes it a good idea to support it in your Makefile, similarly to the GNU Make built-in recipes;
it's probably a bad idea to advertise the variable as something that should be used;
when building other people's projects, probably avoid relying on CPPFLAGS
to do anything that can be done with CFLAGS
.