117

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

但我仍然不明白其中的区别。

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

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

一般来说,如果预处理器找到并包含所需的头文件,为什么需要告诉它额外的包含目录?CFLAGS 到底有什么用?

(在我的情况下,我实际上发现这两者都允许我编译我的程序,这增加了混乱......我可以使用 CFLAGSCPPFLAGS 来实现我的目标(至少在 autoconf 上下文中)。什么给了?)

4

6 回答 6

164

编译 C 程序的隐式 make 规则是

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

其中$()语法扩展了变量。CPPFLAGS和都CFLAGS在编译器调用中使用,用于定义包含路径是个人喜好问题。例如,如果foo.c是当前目录中的文件

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

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

gcc -I/usr/include -c -o foo.o foo.c

当您有多种语言需要相同的包含路径时,两者之间的差异就会发挥作用,例如,如果您bar.cpp尝试过

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,如果它用于特定语言,则放入CFLAGS等等CXXFLAGS。后一种类型的示例包括标准合规性或警告标志- 你不想传递-std=c99给你的 C++ 编译器!

然后你可能会在你的makefile中得到类似的东西

CPPFLAGS=-I/usr/include
CFLAGS=-std=c99
CXXFLAGS=-Weffc++
于 2010-05-03T07:29:16.323 回答
11

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

两者都CPPFLAGS适用CFLAGS于您的情况,因为make(1) 规则将预处理和编译结合在一个命令中(因此两个宏都在命令中使用)。

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

于 2010-05-02T21:45:29.763 回答
4

你在隐式制定规则之后。

于 2010-05-02T21:07:52.850 回答
0

要添加到那些提到隐式规则的人,最好查看 make 隐式定义的内容以及您的环境使用:

make -p

例如:

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

扩大

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

这也将打印# environment数据。在这里,您会发现 GCC 的包含路径以及其他有用的信息。

C_INCLUDE_PATH=/usr/include

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

  1. C_INCLUDE_PATH是系统范围的,将它设置在你的 shell 的*.rc.
  2. $(CPPFLAGS)用于预处理器包含路径。
  3. 如果您需要为 make 添加通用搜索路径,请使用:
VPATH = my_dir_to_search

...甚至更具体

vpath %.c src
vpath %.h include

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

于 2020-07-28T20:22:37.993 回答
0

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

设置 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. 
于 2022-01-17T21:56:40.213 回答
-1

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

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

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

  • 有一种方法可以运行gcc只进行预处理(同时忽略与预处理无关的编译器选项)。

  • 独立的 GNUcpp可以容忍编译器选项,例如-W与预处理无关的警告,甚至代码生成选项(如-fstrict-aliasing和链接器传递)-Wl,--whatever

所以一般来说,构建系统无论出于何种原因需要调用独立的预处理器都可以通过它$(CFLAGS)

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

作为发行版维护者,您不能依赖程序来参与CPPFLAGS;即使在其他方面表现良好的人也会加入CFLAGS,LDFLAGSLDLIBS

应用程序开发人员很容易编写 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 编译器和预处理器的技术。

于 2022-01-05T20:37:50.683 回答