使用以下代码了解什么?
#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后,上面的错误会出现在构建中。
答案 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>
可确保跳过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
来解决其错误的副作用;如果包含的目录已经在搜索路径上,则路径的顺序可能会被修改,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
或不设置任何内容,具体取决于实际是否需要它。