【问题标题】:gcc: local include path hides system header filegcc:本地包含路径隐藏系统头文件
【发布时间】:2016-10-18 18:36:38
【问题描述】:

我有一个本地文件endian.h,它声明了一些字节交换函数。

#pragma once
#include <cstdint>

inline uint16_t bswap(uint16_t val) { return __builtin_bswap16(val); }
inline uint32_t bswap(uint32_t val) { return __builtin_bswap32(val); }
...

似乎 CMake 在我的 makefile 中生成的包含路径导致 /usr/include/endian.h/usr/include/ctype.h 隐藏,而不是解析为 ./src/foo/endian.h

In file included from /usr/include/ctype.h:39:0,
                 from /usr/include/c++/5/cctype:42,
                 ...
                 from ./src/foo/session.h:3

./endian.h: In function ‘uint32_t bswap(uint32_t)’:
./endian.h:17:36: error: conflicting declaration of C function ‘uint32_t bswap(uint32_t)’
  inline uint32_t bswap(uint32_t val) { return __builtin_bswap32(val); }

包含路径之一是当前目录,与我的endian.h 文件所在的目录相同:-I ./src/foo

正是这条路径导致/usr/include/endian.h被隐藏

作品:

g++ -I./src ./src/foo/session.cpp

破碎:

g++ -I./src -I./src/foo ./src/foo/session.cpp

我的印象是(明显错误的)尖括号包括搜索的系统路径,而quote包括搜索使用-I指定的路径。

使用包含路径-I./src,如果我来自./src/foo/foo.h#include "bar/bar.h",即使它不是foo 子目录的本地(即:它使用-I./src 包含路径找到bar/bar.h ),我想这解释了我对每个包含类型含义的印象。

但是,这些似乎也会影响系统包含的查找方式(或者至少,尖括号包含的查找方式)。对吗?

在不强制我重命名本地 endian.h 文件的情况下,解决此问题的唯一方法是删除该包含路径吗?

【问题讨论】:

  • "" 相对于当前源文件, 相对于包含路径中的所有条目。
  • endian.h 是 Linux 的一部分,也许可以使用更合理的名称。
  • @usr1234567 当我将"" 用于相对于当前源文件的文件时,它是如何工作的?
  • @usr1234567 您是否建议只有一个文件实例的名称才能被认为是正常的?恕我直言,这听起来比理智更疯狂?
  • 避免名称冲突是明智的。它排除了一大堆可能难以检测的错误。

标签: c++ gcc makefile cmake g++


【解决方案1】:

这是 gcc 手册中关于包含搜索顺序的内容:

查找顺序如下:

  1. 对于include指令的引用形式,首先搜索当前文件的目录。
  2. 对于 include 指令的引用形式,由 -iquote 选项指定的目录按从左到右的顺序搜索,如 它们出现在命令行上。
  3. 使用 -I 选项指定的目录按从左到右的顺序扫描。
  4. 使用 -isystem 选项指定的目录按从左到右的顺序扫描。
  5. 扫描标准系统目录。
  6. 使用 -idirafter 选项指定的目录按从左到右的顺序扫描。

如您所见,-I 选项 (3) 包含的文件在标准系统目录 (5)(包括 /usr/include)之前搜索。

因此,一般而言,您使用-I 添加的目录中的文件将隐藏同名的系统标头,无论它们是否包含在&lt;&gt;"" 中。

""&lt;&gt; 之间的区别在于"" 中包含的文件首先 搜索当前目录(以及-iquote 目录,但这更加模糊)。因此,如果您包含像#include "foo/bar.h" 这样的文件并且该文件包含“endian.h”,那么如果存在foo/endian.h,它将被使用,而不是标准包含目录中的同名文件。但是,如果您#include &lt;endian.h&gt; 将使用系统版本。这样一来,如果您使用正确的引用,在两个方向上都会减少意外的名称冲突。

【讨论】:

    【解决方案2】:

    最初""&lt;&gt; 之间确实存在区别。但是,目前,据我所知,所有主要编译器都一视同仁。就编译器如何处理它们而言,它们之间确实没有区别。按照惯例,人们使用这些符号。 endian.h 是标准标头,通用名称。您可能应该将其向下移动一个文件夹以避免名称冲突,例如 "myProject/endian.h" 或将名称更改为更明确的名称。

    【讨论】:

    • 它们根本不相等:"" 包含的文件将首先在当前目录中查找,因此一旦包含特定文件,它就可以找到它的所有兄弟姐妹(以及“侄子”等)如果您使用"" 表单,则会自动生成。 &lt;&gt; 禁用它,因此它适用于您希望从标准搜索路径中找到的系统头文件。
    猜你喜欢
    • 2014-10-21
    • 2010-11-01
    • 1970-01-01
    • 2021-07-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-24
    相关资源
    最近更新 更多