- 系统上的系统包括目录导致错误

时间:2016-05-13 20:36:02

标签: gcc

使用以下代码了解什么?

#include <cmath>

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

在使用GCC 6.1.1的最新Arch Linux安装上编译时,它会生成标志-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标头中引发警告。与-isystem相反,-I标志通过将LLVM目录视为&#34;系统标头&#34;来阻止警告。有关详细信息,请参阅GNU C preprocessor documentation

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

1 个答案:

答案 0 :(得分:3)

除了考虑包含&#34;系统标题&#34;的目录外,-isystem还会更改标题搜索列表,将目录参数放在系统标题目录的顶部。如果该目录已存在于搜索列表中,则会将其从当前位置删除。

从(至少)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,这是搜索路径的第一个元素。 <{1}}可以在

中找到
math.h

/usr/include/math.h /usr/include/c++/6.1.1/math.h 中使用#include_next <math.h>可确保跳过cmathmath.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来解决其错误的副作用;如果包含的目录已经在搜索路径上,则路径的顺序可能会被修改,GCC可能会报告错误。

类似以下-isystem解决方法应该足够了:

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或不设置任何内容,具体取决于实际是否需要它。