CFLAGS 与 CPPFLAGS

发布于 2024-08-30 22:14:45 字数 420 浏览 6 评论 0原文

据我所知,CFLAGS(或 CXXFLAGS for C++)用于编译器,而 CPPFLAGS 由预处理器使用。

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

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

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

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

(就我而言,我实际上发现两者都允许我编译我的程序,这增加了混乱......我可以使用 CFLAGS OR< /strong> CPPFLAGS 来实现我的目标(至少在 autoconf 上下文中)。

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?)

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(6

七分※倦醒 2024-09-06 22:14:45

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

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

$() 语法扩展变量的地方。由于 CPPFLAGSCFLAGS 都在编译器调用中使用,因此您用来定义包含路径的方式取决于个人喜好。例如,如果 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 中code>、CXXFLAGS 等。后一种类型的示例包括标准合规性或警告标志 - 您不会希望将 -std=c99 传递给 C++ 编译器!

然后你的 makefile 中可能会出现类似这样的内容

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

The implicit make rule for compiling a C program is

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

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++
作妖 2024-09-06 22:14:45

CPPFLAGS 宏用于指定#include 目录。

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

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

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.

笑,眼淚并存 2024-09-06 22:14:45

CPPFLAGS 似乎是 GNU Make 的一项发明,在它的一些内置配方中被引用。与 CFLAGS 不同,它用于多种语言的配方中,包括 Fortran 等。

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

也就是说,我从未见过一个项目将 CPPFLAGS 宣传为自定义其构建行为的好主意。

发行版将 CPPFLAGS 传递给所有包并要求它们处理它(作为有关该发行版的记录事实)似乎并不常见。我似乎记得 Gentoo 是这样做的;我很想了解任何其他信息。

项目中的自定义构建规则忽略将 $(CPPFLAGS) 插入 $(CC) 命令行的情况并不罕见。忽略插值 $(CPPFLAGS) 对于任何常见发行版(从 Debian 到 Yocto 或其他发行版)构建的程序都没有影响。

此外,当传递预处理器标志时,它们会出现在 CFLAGS 中。因此,即使您支持 CPPFLAGS(无论是通过使用内置 GNU Make 规则,还是模仿它们),您也不能假设只有 CPPFLAGS 会包含用于预处理的标志。

没有必要将预处理器标志与 CFLAGS 分开,因为:

  • 有一种方法可以运行 gcc 仅进行预处理。该 gcc 命令仍然可以采用与预处理无关的编译器选项。

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

所以一般来说,无论出于何种原因需要在 C 代码上调用独立预处理器的构建系统都可以直接传递 $(CFLAGS)

对于应用程序开发人员来说,编写 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 编译器和预处理器的技术。

尽管如此,将 $(CPPFLAGS) 插入构建规则似乎是一个好主意,因为 GNU Make 是按照自己的规则进行的。

另外,正如已经提到的,GNU Make 将相同的 CPPFLAGS 变量引入到不同语言的构建规则中,而 CFLAGS 仅适用于 C。例如,如果我们有一个项目已经对 Fortran 和 C 进行了预处理,那么 CPPFLAGS 将在 C 和 Fortran 中全局作用,这在此类项目中可能会很有用。

总而言之,

  • 支持CPPFLAGS没有什么坏处;

  • 一些发行版使用它(Gentoo?),这使得在 Makefile 中支持它是一个好主意,类似于 GNU Make 内置配方;

  • 将变量宣传为应该使用的东西可能是一个坏主意;

  • 在构建其他人的项目时,可能会避免依赖 CPPFLAGS 来完成任何可以使用 CFLAGS 完成的事情。

CPPFLAGS seems to be an invention of GNU Make, referenced in some of its built-in recipes. Unlike CFLAGS, it is used in recipes for multiple languages, including, for example, Fortran.

If your program is built by some Free software distributions, you may find that some of them require packages to interpolate this variable, using CPPFLAGS for passing down options like -D_WHATEVER=1 for passing down a macro definition.

That said, I've never seen a project advertise CPPFLAGS as something that is a good idea to use in order to customize its build behavior.

It seems uncommon for a distro to pass CPPFLAGS to all packages, and requires them to handle it (as a matter of documented fact about that distro). I seem to remember Gentoo does this; I'd love to be informed about any other.

It's not uncommon for custom build rules in projects to neglect to interpolate $(CPPFLAGS) into the $(CC) command line. Neglecting to interpolate $(CPPFLAGS) has no effect on a program being build by any of the common distros, from Debian to Yocto or what have you.

Furthermore, when preprocessor flags are passed, they appear in CFLAGS. So even if you support CPPFLAGS (whether by way of using built-in GNU Make rules, or imitating them) you cannot assume that only CPPFLAGS will contain flags for preprocessing.

Separation of preprocessor flags from CFLAGS is unnecessary because:

  • There is a way to run gcc to do preprocessing only. That gcc command can still take compiler options not related to preprocessing.

  • Conversely, the stand-alone GNU cpp is tolerant to compiler options, such as -W warnings that do not pertain to preprocessing and even code generation options like -fstrict-aliasing and the linker-pass through like -Wl,--whatever.

So generally speaking, build systems that need to call the stand-alone preprocessor for whatever reason on C code can just pass it $(CFLAGS).

It's easy enough for the application developers to write GNU Make code to separate preprocessor flags out of $(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)

Demo:

$ 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

In the case of the GNU compiler and preprocessor, this is probably unnnecessary; but it illustrates a technique that could be used for non-GNU compilers and preprocessors, in a build system based on GNU Make.

Nonetheless, interpolating $(CPPFLAGS) into build rules seems like a good idea just because GNU Make does it in its own rules.

Also, as mentioned already, GNU Make pulls in the same CPPFLAGS variable into build rules for different languages, whereas CFLAGS is only for C. For instance if we have a project that has preprocessed Fortran, as well as C, then CPPFLAGS will act globally across the C and Fortran, which could be something useful in that kind of project.

In summary,

  • there is no harm in supporting CPPFLAGS;

  • some distros out there use it (Gentoo?) which makes it a good idea to support it in your Makefile, similarly to the GNU Make built-in recipes;

  • it's probably a bad idea to advertise the variable as something that should be used;

  • when building other people's projects, probably avoid relying on CPPFLAGS to do anything that can be done with CFLAGS.

抠脚大汉 2024-09-06 22:14:45

要补充那些提到隐式规则的人,最好查看 make 已隐式定义并针对您的环境使用:

make -p

例如:

%.o: %.c
    $(COMPILE.c) $(OUTPUT_OPTION) 
lt;

它扩展为

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

This will also print #environment data。在这里,您将找到 GCC 的包含路径以及其他有用的信息。

C_INCLUDE_PATH=/usr/include

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

  1. C_INCLUDE_PATH 是系统范围的,请在 shell 的 *.rc 中设置它。

  2. $(CPPFLAGS) 用于预处理器包含路径。

  3. 如果需要添加 make 的通用搜索路径,请使用:

    VPATH = my_dir_to_search
    

    ...或者更具体

    vpath %.c src
    vpath %.h 包含
    

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

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

make -p

For instance:

%.o: %.c
    $(COMPILE.c) $(OUTPUT_OPTION) 
lt;

which expands to

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

This will also print # environment data. Here, you will find GCC's include path among other useful information.

C_INCLUDE_PATH=/usr/include

In make, when it comes to search, the paths are many, the light is one... or something to that effect.

  1. C_INCLUDE_PATH is system-wide, set it in your shell's *.rc.

  2. $(CPPFLAGS) is for the preprocessor include path.

  3. If you need to add a general search path for make, use:

    VPATH = my_dir_to_search
    

    ... or even more specific

    vpath %.c src
    vpath %.h include
    

make uses VPATH as a general search path, so use it cautiously. If a file exists in more than one location listed in VPATH, make will take the first occurrence in the list.

最好是你 2024-09-06 22:14:45

我在 HTTPd 上安装了 HTTPd /Ubuntu_version_history#Ubuntu_18.04_LTS_.28Bionic_Beaver.29" rel="nofollow noreferrer">Ubuntu 18.04 (Bionic Beaver) 使用 CPPFLAGS 变量作为 -DLINUX 标志。

运行时,CPPFLAGS 从上到下逐个文件扫描代码,在编译前查找指令,并且不会通过其他有意义的事情进行扩展,例如大小优化、不会增加输出文件大小的标志;根据处理器类型;减少代码大小并加快程序速度;禁用除大小写之外的所有变量。

CPPFLAGS 和 CFLAGS 之间的唯一区别是 CFLAGS 可以设置为指定要传递给编译器的附加开关。也就是说,CFLAGS环境变量在安装路径中创建一个目录(例如CFLAGS=-i/opt/include),以将调试信息添加到可执行目标的路径中:包括一般警报消息;关闭报警信息;独立位置生成;显示编译器驱动程序、预处理器、编译器版本号。

设置 CPPFLAGS 的标准方法:

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

一些已知变量的列表:

  • CPPFLAGS - 是 C 预处理器标志的变量名称。
  • CXXFLAGS - 是 C++ 编译器标志的标准变量名称。
  • CFLAGS 是 - 带有编译标志的变量的标准名称。
  • LDFLAGS - 应用于搜索标志/路径 (-L) - 即 -L/usr/lib (/usr /lib 是库二进制文件)。
  • LDLIBS - 用于链接库。

I installed HTTPd on Ubuntu 18.04 (Bionic Beaver) using the CPPFLAGS variable for the -DLINUX flag.

When run, CPPFLAGS scans the code from top to bottom, file by file, looking for directives before compiling, and will not be extended by other meaningful things like size optimization, flags that do not increase the size of the output file; under the type of processor; to reduce the size of the code and speed up the program; disable all variables except case.

The only difference between CPPFLAGS and CFLAGS is that CFLAGS can be set to specify additional switches to be passed to the compiler. That is, the CFLAGS environment variable creates a directory in the installation path (eg CFLAGS=-i/opt/include) to add debugging information to the executable target's path: include general alarm messages; turning off alarm information; independent location generation; display compiler driver, preprocessor, compiler version number.

Standard way to set CPPFLAGS:

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

List of some known variables:

  • 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.
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文