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

Tom*_*ire 4 gcc

以下代码是怎么回事?

#include <cmath>

int
main(int argc, char *argv[])
{
}
Run Code Online (Sandbox Code Playgroud)

在最近的带有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.
Run Code Online (Sandbox Code Playgroud)

这是一个非常简化的示例;原始命令行为:

$ g++ ... -isystem `llvm-config -includedir` ...
Run Code Online (Sandbox Code Playgroud)

使用LLVM的程序的一部分。在Arch Linux上,LLVM软件包安装时带有其标头目录/usr/include,该标头目录为llvm-config。...包括了-Wextra-Wconversion,它们在LLVM标头中引起警告。与-isystem标志相反-I,该标志通过将LLVM目录视为“系统头” 来防止警告。有关更多信息,请参见GNU C预处理程序文档

但是,如果升级到GCC 6.1.1,则上述错误会显示在内部版本中。

Tom*_*ire 5

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

如(至少)GCC 6.1.1的,一些C ++头如cmath使用#include_next到猴的贴剂C ++支持标准C头。有关更多信息,请参见为什么<cstdlib>比您想象的复杂。例如,cmath具有以下行:

#include_next <math.h>
Run Code Online (Sandbox Code Playgroud)

#include_next与普通#include语句不同,它在包含目录搜索路径中的下一个条目而不是搜索路径的顶部开始搜索文件。由于-isystem /usr/include移动/usr/include搜索路径的目录包含之前cmathmath.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
Run Code Online (Sandbox Code Playgroud)

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

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

/usr/include/math.h
/usr/include/c++/6.1.1/math.h
Run Code Online (Sandbox Code Playgroud)

使用#include_next <math.h>in cmath可以确保跳过math.hin 的副本,/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
Run Code Online (Sandbox Code Playgroud)

在搜索路径中,#include_next <math.h>现在使用now跳过,/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
Run Code Online (Sandbox Code Playgroud)

这根据实际是否需要将make变量llvm.include设置为要么为空要么-isystem <dir>为空。