CFLAGS vs CPPFLAGS

我知道 CFLAGS (或 C + + 的 CXXFLAGS)是用于编译器的,而 CPPFLAGS 是由预处理器使用的。

但我还是不明白其中的区别。

我需要为包含在 # include 中的头文件指定一个 include 路径——因为 # include 是一个预处理器指令,预处理器(CPPFLAGS)是我唯一关心的事情吗?

在什么情况下我需要给编译器一个额外的包含路径?

通常,如果预处理程序找到并包含所需的头文件,为什么还需要告诉它额外的包含目录呢?CFLAGS 到底有什么用?

(在我的例子中,我实际上发现这些 都有允许我编译我的程序,这增加了困惑... 我可以使用 CFLAGS [俄语] CPPFLAGS 来完成我的目标(至少在 autoconf 上下文中)。怎么了?)

133752 次浏览

You are after 隐式制定规则.

CPPFLAGS宏是用来指定 #include目录的宏。

在这种情况下,CPPFLAGSCFLAGS都可以工作,因为 make(1)规则将预处理和编译结合在一个命令中(因此这两个宏都在命令中使用)。

如果使用表单 #include "...",则不需要将 .指定为 include-目录。您也不需要指定标准的编译器包含目录。您确实需要指定所有其他 include-目录。

The implicit make rule for compiling a C program is

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

其中 $()语法展开变量。由于在编译器调用中同时使用 CPPFLAGSCFLAGS,因此用于定义 include 路径是个人喜好的问题。例如,如果 ABc3是工作目录中的一个文件

make foo.o CPPFLAGS="-I/usr/include"
make foo.o CFLAGS="-I/usr/include"

将以完全相同的方式调用您的编译器,即

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"

那么这些汇编就是

g++ -I/usr/include -c -o bar.o bar.cpp
g++ -c -o bar.o bar.cpp

因为 C + + 隐式规则也使用 CPPFLAGS变量。

这个差异给了你一个很好的指南,如果你想标志被用于所有的语言把它放在 CPPFLAGS,如果它是一个特定的语言把它放在 CFLAGSCXXFLAGS等。后一种类型的示例包括标准遵从性或警告标志——您不会希望将 -std=c99传递给您的 C + + 编译器!

然后您的 makefile 中可能会出现类似的内容

CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++

To add to those who have mentioned the implicit rules, it's best to see what make has defined implicitly and for your env using:

make -p

例如:

%.o: %.c
$(COMPILE.c) $(OUTPUT_OPTION) $<

which expands

COMPILE.c = $(CXX) $(CXXFLAGS) $(CPPFLAGS) $(TARGET_ARCH) -c

这也将打印 # environment数据。在这里,你会发现海湾合作委员会的包括路径在其他有用的信息。

C_INCLUDE_PATH=/usr/include

在制作中,当涉及到搜索,路径是多的,光是一个... 或者类似的效果。

  1. C_INCLUDE_PATH是系统级的,将它设置在 shell 的 *.rc中。
  2. $(CPPFLAGS) is for the preprocessor include path.
  3. 如果需要为 make 添加通用搜索路径,请使用:
VPATH = my_dir_to_search

或者更具体一点

vpath %.c src
vpath %.h include

Make 使用 VPATH 作为一般搜索路径,因此要谨慎使用。如果一个文件存在于 VPATH 列出的多个位置,make 将采用列表中的第一个匹配项。

CPPFLAGS似乎是 GNUMake 的一个发明,在它的一些内置配方中被引用。

如果您的程序是由一些自由软件发行版构建的,您可能会发现其中一些程序需要包来插入这个变量,使用 CPPFLAGS来传递选项,如 -D_WHATEVER=1来传递宏定义。

这种分离是一个糟糕的想法,在 GNU 环境中完全没有必要,因为:

  • There is a way to run gcc to do preprocessing only (while ignoring compiler options unrelated to preprocessing).

  • 独立的 GNU cpp能够容忍编译器选项,比如与预处理无关的 -W警告,甚至包括像 -fstrict-aliasing这样的代码生成选项和像 -Wl,--whatever这样的链接器传递选项。

因此,一般来说,构建需要调用独立预处理器的系统时,不管出于什么原因,都可以将 $(CFLAGS)传递给它。

作为编写 Makefile的应用程序开发人员,您不能依赖于 CPPFLAGS的存在。在开源构建中不是内部专家的用户不会知道 CPPFLAGS,并且在构建程序时会做类似于 make CFLAGS=-Dfoo=bar的事情。如果这不起作用,他们会生气的。

As a distro maintainer, you cannot rely on programs to pull in CPPFLAGS; even otherwise well-behaved ones that pull in CFLAGS, LDFLAGS and LDLIBS.

对于应用程序开发人员来说,编写 GNU Make 代码将预处理器标志从 $(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)

演示:

$ 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

对于 GNU 编译器和预处理器来说,这可能是不必要的; 但是它说明了一种技术,可以在基于 GNU Make 的构建系统中用于非 GNU 编译器和预处理器。

我在 Ubuntu 18.04上安装了 httpd,使用了-DLINUX 标志的 CPPFLAGS 变量。当运行时,CPPFLAGS 从上到下,一个文件一个文件地扫描代码,在编译之前寻找指令,并且不会被其他有意义的事情扩展,比如大小优化,标志不会增加输出文件的大小; 在处理器类型下; 减少代码的大小和加速程序; 禁用除 case 之外的所有变量。CPPFLAGS 和 CFLAGS 之间的唯一区别是,可以将 CFLAGS 设置为指定要传递给编译器的其他开关。也就是说,CFLAGS 环境变量在安装路径(例如 CFLAGS=-i/opt/include)中创建一个目录,为可执行目标的路径添加调试信息: 包括一般警报信息、关闭警报信息、独立位置生成、显示编译器驱动程序、预处理器、编译器版本号。

Standard way to set CPPFLAGS:

sudo ./configure --enable-unixd=DLINUX #for example

列出一些已知的变量:

CPPFLAGS - is the variable name for flags to the C preprocessor.
CXXFLAGS - is the standard variable name for flags to the C++ compiler.
CFLAGS is - the standard name for a variable with compilation flags.
LDFLAGS - should be used for search flags/paths (-L) - i.e. -L/usr/lib (/usr/lib are library binaries).
LDLIBS - for linking libraries.