Hos*_*ork 32 c c++ gcc clang include-path
-I在GCC中读取开关的精细打印,我很震惊地发现在命令行上使用它会覆盖系统包含.来自预处理器文档
"您可以使用
-I覆盖系统头文件,替换您自己的版本,因为这些目录是在标准系统头文件目录之前搜索的."
他们似乎并不撒谎.在具有GCC 7的两个不同的Ubuntu系统上,如果我创建一个文件endian.h:
#error "This endian.h shouldn't be included"
Run Code Online (Sandbox Code Playgroud)
...然后在同一目录中创建一个main.cpp(或main.c,相同的区别):
#include <stdlib.h>
int main() {}
Run Code Online (Sandbox Code Playgroud)
然后编译g++ main.cpp -I. -o main(或clang,相同的差异)给我:
In file included from /usr/include/x86_64-linux-gnu/sys/types.h:194:0,
from /usr/include/stdlib.h:394,
from /usr/include/c++/7/cstdlib:75,
from /usr/include/c++/7/stdlib.h:36,
from main.cpp:1:
./endian.h:1:2: error: #error "This endian.h shouldn't be included"
Run Code Online (Sandbox Code Playgroud)
所以stdlib.h包含了这个types.h文件,在194行就是这么说的#include <endian.h>.我明显的误解(也许是其他人的误解)是尖括号会阻止这一点,但是 - 我比我想象的更强.
虽然不强足够在命令行上,因为你甚至不能通过症结修复/ usr/include目录在第一位,这是因为:
"如果标准系统包括目录或指定的目录
-isystem,也指定了-I,-I则忽略该选项.目录仍然被搜索,但作为系统目录在系统包含链中的正常位置."
实际上,g++ -v main.cpp -I/usr/include -I. -o mainleaves/usr/的详细输出包含在列表的底部:
#include "..." search starts here:
#include <...> search starts here:
.
/usr/include/c++/7
/usr/include/x86_64-linux-gnu/c++/7
/usr/include/c++/7/backward
/usr/lib/gcc/x86_64-linux-gnu/7/include
/usr/local/include
/usr/lib/gcc/x86_64-linux-gnu/7/include-fixed
/usr/include/x86_64-linux-gnu
/usr/include
Run Code Online (Sandbox Code Playgroud)
让我惊讶的颜色.我想这是一个问题:
-I考虑到这个极其严重的问题,大多数项目使用的正当理由是什么? 您可以根据偶然名称冲突覆盖系统上的任意标头.不应该每个人都使用-iquote相反?
Ala*_*les 19
回顾GCC手册,它看起来像-iquote其他选项只在GCC 4中添加:https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Directory-Options.html#Directory%20Options
所以使用"-I"可能是一些组合:习惯,懒惰,向后兼容性,对新选项的无知,与其他编译器的兼容性.
解决方案是通过将头文件放在子目录中来"命名"头文件.例如,将您的endian标头"include/mylib/endian.h"添加"-Iinclude"到命令行,您可以将#include "mylib/endian.h"其与其他库或系统库冲突.
R..*_*R.. 15
我这是你的前提,那-I就是危险是假的.该语言使用任何形式的#include充分实现定义来搜索头文件,使用与标准头文件的名称冲突的头文件是不安全的.简单地避免这样做.
MSa*_*ers 11
一个明显的例子是交叉编译.GCC在历史上的UNIX假设中遇到了一些问题,即您总是在为本地系统编译,或者至少是非常接近的东西.这就是编译器的头文件在系统根目录中的原因.缺少干净的界面.
相比之下,Windows假设没有编译器,Windows编译器不假设您的目标是本地系统.这就是为什么你可以安装一组编译器和一组SDK.
现在在交叉编译中,GCC的行为更像是Windows的编译器.它不再假定您打算使用本地系统标头,而是允许您准确指定所需的标头.显然,您链接的库也是如此.
现在请注意,当您执行此操作时,替换标头集旨在置于基本系统之上.如果它们的实现相同,您可以在替换集中省略标题.例如,机会是<complex.h>相同的.复数实现没有那么多变化.但是,您不能随意替换内部实现位<endian.h>.
TL,DR:这个选项适用于那些知道自己在做什么的人."不安全"不是目标受众的论据.