CFLAGS vs CPPFLAGS
Solution 1
The implicit make rule for compiling a C program is
%.o:%.c
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
where the $()
syntax expands the variables. As both CPPFLAGS
and CFLAGS
are used in the compiler call, which you use to define include paths is a matter of personal taste. For instance if foo.c
is a file in the current directory
make foo.o CPPFLAGS="-I/usr/include"
make foo.o CFLAGS="-I/usr/include"
will both call your compiler in exactly the same way, namely
gcc -I/usr/include -c -o foo.o foo.c
The difference between the two comes into play when you have multiple languages which need the same include path, for instance if you have bar.cpp
then try
make bar.o CPPFLAGS="-I/usr/include"
make bar.o CFLAGS="-I/usr/include"
then the compilations will be
g++ -I/usr/include -c -o bar.o bar.cpp
g++ -c -o bar.o bar.cpp
as the C++ implicit rule also uses the CPPFLAGS
variable.
This difference gives you a good guide for which to use - if you want the flag to be used for all languages put it in CPPFLAGS
, if it's for a specific language put it in CFLAGS
, CXXFLAGS
etc. Examples of the latter type include standard compliance or warning flags - you wouldn't want to pass -std=c99
to your C++ compiler!
You might then end up with something like this in your makefile
CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++
Solution 2
The CPPFLAGS
macro is the one to use to specify #include
directories.
Both CPPFLAGS
and CFLAGS
work in your case because the make
(1) rule combines both preprocessing and compiling in one command (so both macros are used in the command).
You don't need to specify .
as an include-directory if you use the form #include "..."
. You also don't need to specify the standard compiler include directory. You do need to specify all other include-directories.
Solution 3
You are after implicit make rules.
Related videos on Youtube
EBM
Updated on July 08, 2022Comments
-
EBM almost 2 years
I understand that CFLAGS (or CXXFLAGS for C++) are for the compiler, whereas CPPFLAGS is used by the preprocessor.
But I still don't understand the difference.
I need to specify an include path for a header file that is included with #include -- because #include is a preprocessor directive, is the preprocessor (CPPFLAGS) the only thing I care about?
Under what circumstances do I need to give the compiler an extra include path?
In general, if the preprocessor finds and includes needed header files, why does it ever need to be told about extra include directories? What use is CFLAGS at all?
(In my case, I actually found that BOTH of these allow me to compile my program, which adds to the confusion... I can use CFLAGS OR CPPFLAGS to accomplish my goal (in autoconf context at least). What gives?)
-
Michael Mrozek about 14 yearspossible duplicate of stackoverflow.com/questions/495598/…
-
-
EBM about 14 yearsThis makes more sense, but I still don't see what CFLAGS does, then. If, as you seem to imply, compilation in more complex projects is done in a separate step from preprocessing, will preprocessing succeed but compilation fail if CFLAGS doesn't add the same paths that CPPFLAGS added for the preprocessor? I guess I don't understand what the compiler does with include paths if the preprocessor already processed the #include directives?
-
Scott Wales about 14 years@EB If you're compiling preprocessed files then include paths are unnecessary - the required headers have already been added to the preprocessed source (Have a look at the output when you run
gcc -E
on a file - there are no #includes). Most modern compilers combine the pre-processing and compilation steps, so you don't have to worry about this. -
Jed over 11 yearsNote that you cannot run stand-alone
cpp
usingCPPFLAGS
and expect any reasonable result because-std=c99
affects which symbols are defined (especially in lieu of feature test macros). Instead, you need$(CC) $(CPPFLAGS) $(CFLAGS) -E
. -
kelvin almost 3 years"The implicit make rule for compiling a C program is" "
$(CC) $(CPPFLAGS) $(CFLAGS) -c -o $@ $<
" Not sure if it makes a difference, but on gmake, currentlyCPPFLAGS
appears afterCFLAGS
:$ make --version | head -n 1
->GNU Make 4.3
;$ make -p 2>/dev/null | grep -F 'COMPILE.c ='
->COMPILE.c = $(CC) $(CFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c