考虑到危险,为什么项目要使用 -I include 开关?
Why do projects use the -I include switch given the dangers?
阅读 GCC 中 -I
开关的细则,我很震惊地发现在命令行上使用它会覆盖系统包含。来自 preprocessor docs
"You can use -I
to override a system header file, substituting your own version, since these directories are searched before the standard system header file directories."
他们好像没有说谎。在带有 GCC 7 的两个不同 Ubuntu 系统上,如果我创建一个文件 endian.h
:
#error "This endian.h shouldn't be included"
...然后在同一目录下创建一个main.cpp
(或main.c,区别相同):
#include <stdlib.h>
int main() {}
然后用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"
所以 stdlib.h 包括这个 types.h 文件,它在第 194 行只是说 #include <endian.h>
。我明显的误解(也许其他人的误解)是尖括号会阻止这种情况,但是 -I 比我想象的要强大。
虽然不够强,因为你甚至无法通过先在命令行上粘贴 /usr/include 来修复它,因为:
"If a standard system include directory, or a directory specified with -isystem
, is also specified with -I
, the -I
option is ignored. The directory is still searched but as a system directory at its normal position in the system include chain."
确实,g++ -v main.cpp -I/usr/include -I. -o main
的详细输出将 /usr/include 留在列表底部:
#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
让我感到惊讶。我想提出这个问题:
考虑到这个极其严重的问题,大多数项目使用 -I
的正当理由是什么? 您可以根据偶然情况在系统上覆盖任意 headers名称冲突。几乎每个人不应该改用 -iquote
吗?
-I
超过 -iquote
有什么正当理由? -I
是标准化的(至少 POSIX 是),而 -iquote
不是。 (实际上,我使用 -I
因为 tinycc(我希望我的项目编译的编译器之一)不支持 -iquote
。)
考虑到危险,项目如何管理 -I
?您将包含包含在目录中并使用 -I 添加包含该目录的目录。
- 文件系统:
includes/mylib/endian.h
- 命令行:
-Iincludes
- C/C++ 文件:
#include "mylib/endian.h" //or <mylib/endian.h>
因此,只要不在 mylib
名称上发生冲突,就不会发生冲突(至少就 header 名称而言)。
回顾 GCC 手册,看起来 -iquote
和其他选项仅在 GCC 4 中添加:https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Directory-Options.html#Directory%20Options
所以 "-I"
的使用可能是以下因素的结合:习惯、懒惰、向后兼容性、对新选项的无知、与其他编译器的兼容性。
解决方案是 "namespace" 您的 header 文件,将它们放在子目录中。例如,将字节序 header 放在 "include/mylib/endian.h"
中,然后将 "-Iinclude"
添加到命令行,这样就可以 #include "mylib/endian.h"
,这不应与其他库或系统库冲突。
一个明显的例子是cross-compilation。 GCC 有点受历史 UNIX 假设的影响,即您总是为本地系统或至少是非常接近的系统进行编译。这就是编译器的 header 文件位于系统根目录中的原因。缺少干净的界面。
相比之下,Windows 假定没有编译器,并且 Windows 编译器不假定您的目标是本地系统。这就是为什么您可以安装一组编译器和一组 SDK。
现在 cross-compilation,GCC 的行为更像 Windows 的编译器。它不再假定您打算使用本地系统 headers,而是让您准确指定所需的 headers。显然,您 link 在其中的库也是如此。
现在请注意,当您执行此操作时,替换集 headers 旨在继续基本系统的 top。如果它们的实现相同,您可以在替换集中省略 headers。例如。 <complex.h>
很可能是相同的。复数实现没有太多变化。但是,您不能随意替换 <endian.h>
等内部实现位。
TL,DR :此选项适用于知道自己在做什么的人。 "Being unsafe" 不是针对目标受众的论点。
我认为你认为 -I
很危险的前提是错误的。该语言通过充分实现定义的 #include
形式来搜索头文件,因此使用与标准头文件名称冲突的头文件是不安全的。简单地避免这样做。
阅读 GCC 中 -I
开关的细则,我很震惊地发现在命令行上使用它会覆盖系统包含。来自 preprocessor docs
"You can use
-I
to override a system header file, substituting your own version, since these directories are searched before the standard system header file directories."
他们好像没有说谎。在带有 GCC 7 的两个不同 Ubuntu 系统上,如果我创建一个文件 endian.h
:
#error "This endian.h shouldn't be included"
...然后在同一目录下创建一个main.cpp
(或main.c,区别相同):
#include <stdlib.h>
int main() {}
然后用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"
所以 stdlib.h 包括这个 types.h 文件,它在第 194 行只是说 #include <endian.h>
。我明显的误解(也许其他人的误解)是尖括号会阻止这种情况,但是 -I 比我想象的要强大。
虽然不够强,因为你甚至无法通过先在命令行上粘贴 /usr/include 来修复它,因为:
"If a standard system include directory, or a directory specified with
-isystem
, is also specified with-I
, the-I
option is ignored. The directory is still searched but as a system directory at its normal position in the system include chain."
确实,g++ -v main.cpp -I/usr/include -I. -o main
的详细输出将 /usr/include 留在列表底部:
#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
让我感到惊讶。我想提出这个问题:
考虑到这个极其严重的问题,大多数项目使用 -I
的正当理由是什么? 您可以根据偶然情况在系统上覆盖任意 headers名称冲突。几乎每个人不应该改用 -iquote
吗?
-I
超过 -iquote
有什么正当理由? -I
是标准化的(至少 POSIX 是),而 -iquote
不是。 (实际上,我使用 -I
因为 tinycc(我希望我的项目编译的编译器之一)不支持 -iquote
。)
考虑到危险,项目如何管理 -I
?您将包含包含在目录中并使用 -I 添加包含该目录的目录。
- 文件系统:
includes/mylib/endian.h
- 命令行:
-Iincludes
- C/C++ 文件:
#include "mylib/endian.h" //or <mylib/endian.h>
因此,只要不在 mylib
名称上发生冲突,就不会发生冲突(至少就 header 名称而言)。
回顾 GCC 手册,看起来 -iquote
和其他选项仅在 GCC 4 中添加:https://gcc.gnu.org/onlinedocs/gcc-3.4.6/gcc/Directory-Options.html#Directory%20Options
所以 "-I"
的使用可能是以下因素的结合:习惯、懒惰、向后兼容性、对新选项的无知、与其他编译器的兼容性。
解决方案是 "namespace" 您的 header 文件,将它们放在子目录中。例如,将字节序 header 放在 "include/mylib/endian.h"
中,然后将 "-Iinclude"
添加到命令行,这样就可以 #include "mylib/endian.h"
,这不应与其他库或系统库冲突。
一个明显的例子是cross-compilation。 GCC 有点受历史 UNIX 假设的影响,即您总是为本地系统或至少是非常接近的系统进行编译。这就是编译器的 header 文件位于系统根目录中的原因。缺少干净的界面。
相比之下,Windows 假定没有编译器,并且 Windows 编译器不假定您的目标是本地系统。这就是为什么您可以安装一组编译器和一组 SDK。
现在 cross-compilation,GCC 的行为更像 Windows 的编译器。它不再假定您打算使用本地系统 headers,而是让您准确指定所需的 headers。显然,您 link 在其中的库也是如此。
现在请注意,当您执行此操作时,替换集 headers 旨在继续基本系统的 top。如果它们的实现相同,您可以在替换集中省略 headers。例如。 <complex.h>
很可能是相同的。复数实现没有太多变化。但是,您不能随意替换 <endian.h>
等内部实现位。
TL,DR :此选项适用于知道自己在做什么的人。 "Being unsafe" 不是针对目标受众的论点。
我认为你认为 -I
很危险的前提是错误的。该语言通过充分实现定义的 #include
形式来搜索头文件,因此使用与标准头文件名称冲突的头文件是不安全的。简单地避免这样做。