以下代码是怎么回事?
#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,则上述错误会显示在内部版本中。
除了考虑目录包含“系统头”之外,还-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
搜索路径的目录包含之前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
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.h
in 的副本,/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>
为空。