[gcc] CFLAGS, CCFLAGS, CXXFLAGS - what exactly do these variables control?

I am using GNU make to compile my C++ code, and i would like to understand how to make my compilations customizable.

I read in different places that CFLAGS, CCFLAGS and CXXFLAGS are used for this purpose. So how should i use them? If i have additional command-line arguments to the compiler, should i append them to CFLAGS or prepend them? Is there a common practice?

Why the three different variables? I suppose the C compiler should get CFLAGS and CCFLAGS, while the C++ compiler should get CFLAGS and CXXFLAGS - did i get it right?

Is the human user supposed to set these variables at all? Do any automatic tools (automake, autoconf, etc) set them? The linux system that i am supposed to use doesn't define any of these variables - is this typical?

Currently my Makefile looks like this, and i feel it's a bit dirty:

ifdef code_coverage
    GCOV_FLAG := -fprofile-arcs -ftest-coverage
else
    GCOV_FLAG :=
endif

WFLAGS := -Wall

INC_FLAGS := -Istuff -Imore_stuff -Ietc

CCFLAGSINT := -O3 $(WFLAGS) $(INC_FLAGS) $(CCFLAGS)

... (somewhere in the makefile, the command-line for compilation looks like this)
    $(CC) $(CCFLAGSINT) -c $< -o $@

... (somewhere in the makefile, the command-line for linking looks like this)
    $(CC) $(GCOV_FLAG) $(CCFLAGSINT) $(OBJLIST) $(LDFLAGS) -o $@

I am pretty sure there are no bugs here; the Makefile works very well. But is there anything that goes against conventions (like CCFLAGSINT - should i just overwrite CCFLAGS instead? Or CXXFLAGS? FUD!)

Sorry for so many questions; you will obviously not answer them all but i hope the answers will help me understand the general idea behind these settings.

This question is related to gcc naming-conventions makefile

The answer is


As you noticed, these are Makefile {macros or variables}, not compiler options. They implement a set of conventions. (Macros is an old name for them, still used by some. GNU make doc calls them variables.)

The only reason that the names matter is the default make rules, visible via make -p, which use some of them.

If you write all your own rules, you get to pick all your own macro names.

In a vanilla gnu make, there's no such thing as CCFLAGS. There are CFLAGS, CPPFLAGS, and CXXFLAGS. CFLAGS for the C compiler, CXXFLAGS for C++, and CPPFLAGS for both.

Why is CPPFLAGS in both? Conventionally, it's the home of preprocessor flags (-D, -U) and both c and c++ use them. Now, the assumption that everyone wants the same define environment for c and c++ is perhaps questionable, but traditional.


P.S. As noted by James Moore, some projects use CPPFLAGS for flags to the C++ compiler, not flags to the C preprocessor. The Android NDK, for one huge example.


According to the GNU make manual:

CFLAGS: Extra flags to give to the C compiler.
CXXFLAGS: Extra flags to give to the C++ compiler.
CPPFLAGS: Extra flags to give to the C preprocessor and programs that use it (the C and Fortran compilers).

src: https://www.gnu.org/software/make/manual/make.html#index-CFLAGS
note: PP stands for PreProcessor (and not Plus Plus), i.e.

CPP: Program for running the C preprocessor, with results to standard output; default ‘$(CC) -E’.

These variables are used by the implicit rules of make

Compiling C programs
n.o is made automatically from n.c with a recipe of the form
‘$(CC) $(CPPFLAGS) $(CFLAGS) -c’.

Compiling C++ programs
n.o is made automatically from n.cc, n.cpp, or n.C with a recipe of the form
‘$(CXX) $(CPPFLAGS) $(CXXFLAGS) -c’.
We encourage you to use the suffix ‘.cc’ for C++ source files instead of ‘.C’.

src: https://www.gnu.org/software/make/manual/make.html#Catalogue-of-Rules


Minimal example

And just to make what Mizux said as a minimal example:

main_c.c

#include <stdio.h>

int main(void) {
    puts("hello");
}

main_cpp.cpp

#include <iostream>

int main(void) {
    std::cout << "hello" << std::endl;
}

Then, without any Makefile:

make CFLAGS='-g -O3' \
     CXXFLAGS='-ggdb3 -O0' \
     CPPFLAGS='-DX=1 -DY=2' \
     CCFLAGS='--asdf' \
     main_c \
     main_cpp

runs:

cc -g -O3 -DX=1 -DY=2   main_c.c   -o main_c
g++ -ggdb3 -O0 -DX=1 -DY=2   main_cpp.cpp   -o main_cpp

So we understand that:

  • make had implicit rules to make main_c and main_cpp from main_c.c and main_cpp.cpp
  • CFLAGS and CPPFLAGS were used as part of the implicit rule for .c compilation
  • CXXFLAGS and CPPFLAGS were used as part of the implicit rule for .cpp compilation
  • CCFLAGS is not used

Those variables are only used in make's implicit rules automatically: if compilation had used our own explicit rules, then we would have to explicitly use those variables as in:

main_c: main_c.c
    $(CC) $(CFLAGS) $(CPPFLAGS) -o $@ $<

main_cpp: main_c.c
    $(CXX) $(CXXFLAGS) $(CPPFLAGS) -o $@ $<

to achieve a similar affect to the implicit rules.

We could also name those variables however we want: but since Make already treats them magically in the implicit rules, those make good name choices.

Tested in Ubuntu 16.04, GNU Make 4.1.


Examples related to gcc

Can't compile C program on a Mac after upgrade to Mojave Compiling an application for use in highly radioactive environments Make Error 127 when running trying to compile code How to Install gcc 5.3 with yum on CentOS 7.2? How does one set up the Visual Studio Code compiler/debugger to GCC? How do I set up CLion to compile and run? CMake error at CMakeLists.txt:30 (project): No CMAKE_C_COMPILER could be found How to printf a 64-bit integer as hex? Differences between arm64 and aarch64 Fatal error: iostream: No such file or directory in compiling C program using GCC

Examples related to naming-conventions

How to name Dockerfiles What is the difference between .yaml and .yml extension? Is there a naming convention for git repositories? What's the name for hyphen-separated case? Should I use "camel case" or underscores in python? Is there a naming convention for MySQL? What is the javascript filename naming convention? REST URI convention - Singular or plural name of resource while creating it What is the standard naming convention for html/css ids and classes? What are naming conventions for MongoDB?

Examples related to makefile

MINGW64 "make build" error: "bash: make: command not found" "No rule to make target 'install'"... But Makefile exists How to overcome "'aclocal-1.15' is missing on your system" warning? How to install and use "make" in Windows? How to get a shell environment variable in a makefile? Using local makefile for CLion instead of CMake Difference between using Makefile and CMake to compile the code How to set child process' environment variable in Makefile Windows 7 - 'make' is not recognized as an internal or external command, operable program or batch file Debugging the error "gcc: error: x86_64-linux-gnu-gcc: No such file or directory"