CFLAGS,CCFLAGS,CXXFLAGS-这些变量到底控制什么?

我正在使用 GNUmake 来编译我的 C + + 代码,我想了解如何使我的编译可定制。

我在不同的地方读到,CFLAGSCCFLAGSCXXFLAGS都用于这个目的。那我该怎么用呢?如果我有额外的命令行参数到编译器,我应该追加到 CFLAGS或预置它们?有什么常见的做法吗?

为什么是三个不同的变量?我认为 C 编译器应该得到 CFLAGSCCFLAGS,而 C + + 编译器应该得到 CFLAGSCXXFLAGS-我做对了吗?

人类用户是否应该设置这些变量?有没有自动工具(automakeautoconf等)来设置它们?我应该使用的 linux 系统没有定义任何这些变量-这是典型的吗?

目前我的 Makefile 看起来像这样,我觉得它有点脏:

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 $@

我非常肯定这里没有 bug; Makefile 工作得非常好。但是有没有什么东西是违反惯例的(比如 CCFLAGSINT-我是不是应该改写 CCFLAGS呢?或者 CXXFLAGS?FUD!)

很抱歉有这么多问题,你显然不会全部回答,但我希望这些答案能帮助我理解这些设置背后的大致思路。

168769 次浏览

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.

    BTW, the SCons build system for example uses CCFLAGS for flags that are common to C and C++, which is a convention I sometimes follow on my custom make rules.

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.

Related: CFLAGS vs CPPFLAGS

This is an addition to all the existing answers, which mostly describe how these make variables affect the compilation process. In this answer, I describe a suggested way to use these variables, and any surrounding considerations. It is partly inspired by an answer to a similar question.

How should I use them? Should I append or prepend?

Compilation flags are of two types:

  1. Those which are required to make the compilation work (example: -I, which tells the compiler where to find h-files).
  2. Those which customize the compilation (example: -O, optimization level).

Only type 2 (customization) should go into CCFLAGS, and if the user specifies them, they should override whatever is defined in the Makefile. Use ?= syntax for that in your Makefile:

CCFLAGS ?= -O3

Type 1 settings should go into a new made-up variable, which should aggregate them all, and also include the standard variables, like CCFLAGS:

INC_FLAGS := -Istuff -Imore_stuff -Ietc


CCFLAGS_INTERNAL := $(INC_FLAGS) $(CCFLAGS)

Is there a common practice?

No, it doesn't seem so. Stuff I described above is one option, which looks good, but it's not standard.

Is the human user supposed to set these variables at all? The linux system that I use doesn't define any of these variables - is this typical?

Yes, these are for specifying options using the command line. The environment variables usually don't exist.

Is there anything that goes against conventions? (like CCFLAGSINT - should I just overwrite CCFLAGS instead? Or CXXFLAGS? FUD!)

No, the idea of this Makefile is correct: append CCFLAGS and other flags to the compiler's command-line; don't update CCFLAGS.