gcc - 系统上的 -isystem 包含目录会导致错误

标签 gcc

下面的代码是怎么回事?

#include <cmath>

int
main(int argc, char *argv[])
{
}

当在最近安装的 Arch Linux 上使用 GCC 6.1.1 和标志 -isystem/usr/include 进行编译时,它会生成:

$ g++ -isystem /usr/include math.cc 
In file included from math.cc:1:0:
/usr/include/c++/6.1.1/cmath:45:23: fatal error: math.h: No such file or directory
 #include_next <math.h>
                       ^
compilation terminated.

这是一个非常简单的例子;原来的命令行是:

$ g++ ... -isystem `llvm-config -includedir` ...

用于使用 LLVM 的程序的一部分。在 Arch Linux 上,LLVM 包安装时其头目录位于 /usr/include 中,这是 llvm-config 报告的目录。 ...包括 -Wextra-Wconversion,它们会在 LLVM header 中引起警告。与 -I 不同,-isystem 标志通过将 LLVM 目录视为“系统头”来防止出现警告。请参阅GNU C preprocessor documentation了解更多信息。

但是升级到 GCC 6.1.1 后,构建中会出现上述错误。

最佳答案

除了考虑目录包含“系统头文件”之外,-isystem更改 header 搜索列表,将目录参数放在系统 header 目录的顶部。如果该目录已存在于搜索列表中,则会将其从当前位置删除。

(至少)从 GCC 6.1.1 开始,一些 C++ 头文件,例如 cmath使用#include_next为标准 C 头文件提供猴子补丁 C++ 支持。请参阅Why < cstdlib > is more complicated than you might think了解更多信息。例如,cmath有行:

#include_next <math.h>

#include_next ,与正常的 #include 不同语句,在包含目录搜索路径的下一个条目开始搜索文件,而不是在搜索路径的顶部。自 -isystem /usr/include移动/usr/include在包含 cmath 的目录之前的搜索路径中, math.h找不到。

详细来说,命令g++ -I /usr/include的搜索路径是

 /usr/include/c++/6.1.1
 /usr/include/c++/6.1.1/x86_64-pc-linux-gnu
 /usr/include/c++/6.1.1/backward
 /usr/lib/gcc/x86_64-pc-linux-gnu/6.1.1/include
 /usr/local/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/6.1.1/include-fixed
 /usr/include

( /usr/include 是系统目录; -I 参数不执行任何操作。)

cmath位于路径 /usr/include/c++/6.1.1/cmath ,这是搜索路径的第一个元素。 math.h可以在

中找到
/usr/include/math.h
/usr/include/c++/6.1.1/math.h

使用#include_next <math.h>cmath确保 math.h 的副本在/usr/include/c++/6.1.1被跳过并且使用的副本是 /usr/include/math.h .

g++ -isystem /usr/include ,搜索路径为

 /usr/include
 /usr/include/c++/6.1.1
 /usr/include/c++/6.1.1/x86_64-pc-linux-gnu
 /usr/include/c++/6.1.1/backward
 /usr/lib/gcc/x86_64-pc-linux-gnu/6.1.1/include
 /usr/local/include
 /usr/lib/gcc/x86_64-pc-linux-gnu/6.1.1/include-fixed

使用#include_next <math.h>现在跳过/usr/include/c++/6.1.1还有/usr/include ,它位于搜索路径的上方。因此,编译器无法找到 math.h任何副本。 .

总而言之,请谨慎使用 -isystem因为它有消除错误的副作用;如果包含的目录已经在搜索路径中,则路径的顺序可能会被修改,GCC 可能会报告错误。

类似于下面的Makefile解决方法应该足够了:

llvm.include.dir := $(shell $(LLVM_CONFIG) --includedir)
include.paths := $(shell echo | cc -v -E - 2>&1)
ifeq (,$(findstring $(llvm.include.dir),$(include.paths)))
# LLVM include directory is not in the existing paths;
# put it at the top of the system list
llvm.include := -isystem $(llvm.include.dir)
else
# LLVM include directory is already on the existing paths;
# do nothing
llvm.include :=
endif

这设置了 make变量llvm.include-isystem <dir>或者什么都不做,取决于是否确实需要。

关于gcc - 系统上的 -isystem 包含目录会导致错误,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46129786/

相关文章:

macos - 如何使用brew链接到新的gcc版本?

c++ - 将 xvalue 转换为非常量左值引用时,为什么 gcc 和 clang 中的编译器错误不一致?

macos - 如何从 x86_64-apple-darwin 主机构建 i386-apple-darwin 目标的交叉编译器?

c++ - 在 Windows 10 中运行 gcc 插件时出现问题

c - 在 Windows 上诊断 C 应用程序崩溃的工具/技术

c - 以跨平台方式导出共享库符号?

linux - 包含路径错误?

c - C中的引用计数

gcc - 无法通过 valgrind-3.11 运行 gcc-5 二进制文件

c - 由于移植到不同的 gcc 版本而导致的问题