如何让 g++ 正确使用我自己的 glibc 构建的 headers?

How can get g++ to use my own glibc build's headers correctly?

如果上下文太多,最后会有一个 TL;DR!

上下文

我正在尝试将项目使用的 glibc 版本更新到 2.23(我知道它很旧,那是另一个问题)。为此,我需要换出库并使用关联的解释器。

我在换出看起来像是 ABI 更改的解释器时遇到了一些问题,所以我认为这可能是因为 header 文件以某种方式发生了更改,并开始着手将这些文件包含到项目中。

起初我尝试使用 -I 来包含 headers,但出现错误(见下文)。后来我尝试设置 --sysroot,但很快感觉这是错误的做事方式,因为我实际上是在重新发明 g++ 已经对系统 headers 所做的事情。后来我发现了另一种看起来更有希望的机制(参见问题部分)。

这会是 XY issue 吗?当然可以,但不管怎样,我看到的问题对我来说似乎很奇怪。

问题

我研究了在 gcc 和 g++ 中是否有不同的机制来为系统库(例如 glibc)包含 headers。我找到了标志 -isystem:

   -isystem dir
      Search dir for header files, after all directories specified by -I but before the standard system directories.  Mark it as a system directory, so that it gets the same special treatment as is applied to the standard system directories.  If dir begins with "=", then the "="
      will be replaced by the sysroot prefix; see --sysroot and -isysroot.

我认为这可能是需要的,并着手将此标志集成到项目的构建系统中。生成的 g++ 命令如下所示(已简化并分为多行):

> /path/to/gcc-6.3.0/bin/g++
  -c
  -Wl,--dynamic-linker=/path/to/glibc-2.23/build/install/lib/ld-linux-x86-64.so.2
  -Wl,--rpath=/path/to/glibc-2.23/build/install/lib
  -isystem /path/to/glibc-2.23/build/install/include
  -I.
  -I/project-foo/include
  -I/project-bar/include
  -o example.o 
  example.cpp

这会导致以下错误,然后是许多类似的错误:

In file included from /usr/include/math.h:71:0,
                 from /path/to/gcc-6.3.0/include/c++/6.3.0/cmath:45,
                 from example.cpp:42:
/path/to/glibc-2.23/build/install/include/bits/mathcalls.h:63:16: error: expected constructor, destructor, or type conversion before '(' token
 __MATHCALL_VEC (cos,, (_Mdouble_ __x));

对此进行调查,似乎这个特定的 math.h 与此版本的 glibc 不兼容。它试图使用它的事实让我感到惊讶,因为 math.h 文件存在于我指定的 glibc 目录中;为什么不使用它?以下是我验证文件是否存在的方法:

> ls /path/to/glibc-2.23/build/install/include/math.h 
/path/to/glibc-2.23/build/install/include/math.h

研究

我在互联网上搜索了有类似问题的人,发现了以下相关内容:

最后一个是最有希望的;它谈到为什么 -isystem 在这里不起作用,说明特殊的 #include_next 以不同的方式遍历包含路径。在这里,解决方案似乎是“不要在可以帮助的地方使用 -isystem”,但由于我尝试使用 -I 只会再次遇到同样的问题,我不确定如何我会在这里应用它。

原刊

当使用新的 glibc 编译时,我得到以下错误(我们的构建过程最终 运行 它编译的一些程序生成更多要编译的源代码,因此在编译时出现这个运行时错误):

Inconsistency detected by ld.so: get-dynamic-info.h: 143: elf_get_dynamic_info: Assertion `info[DT_RPATH] == NULL' failed!

我发现了一些与此相关的事情:

我看到的唯一解决方案是完全重新编译 gcc 以使用新的 glibc。如果可能的话,我想避免这种情况,这就是导致我走包含路线的原因。

消除复杂的构建系统

为了尝试消除“真实”项目上的复杂构建系统,我使用以下 test.cpp 文件重现了该问题:

#include <cmath>

int main() {

}

编译使用:

> /path/to/gcc-6.3.0/bin/g++ test.cpp -Wl,--dynamic-linker=/path/to/glibc-2.23/build/install/lib/ld-linux-x86-64.so.2 -Wl,--rpath=/path/to/glibc-2.23/build/install/lib

运行 产生相同的原始问题:

> ./a.out 
Inconsistency detected by ld.so: get-dynamic-info.h: 143: elf_get_dynamic_info: Assertion `info[DT_RPATH] == NULL' failed!

尝试使用较新的 headers 会产生相同的包含问题:

> /path/to/gcc-6.3.0/bin/g++ test.cpp -Wl,--dynamic-linker=/path/to/glibc-2.23/build/install/lib/ld-linux-x86-64.so.2 -Wl,--rpath=/path/to/glibc-2.23/build/install/lib -isystem /path/to/glibc-2.23/build/install/include
In file included from /usr/include/math.h:71:0,
                 from /path/to/gcc-6.3.0/include/c++/6.3.0/cmath:45,
                 from test.cpp:1:
/path/to/glibc-2.23/build/install/include/bits/mathcalls.h:63:16: error: expected constructor, destructor, or type conversion before '(' token
 __MATHCALL_VEC (cos,, (_Mdouble_ __x));

TL;DR

如何让 g++ 正确包含来自我的 glibc 构建的 headers,而不意外地包含来自 /usr/include 的不兼容文件?

在您的 GCC 版本中,<cmath> 使用 #include_next,这意味着您需要确保包含 cmath 文件的目录出现在 之前(在包含搜索路径上)具有正确 math.h 的目录,适用于您正在构建的 glibc 版本。

您可以使用g++ -v查看搜索路径。在你的情况下,它可能看起来像这样:

#include "..." search starts here:
#include <...> search starts here:
 .
 /project-foo/include
 /project-bar/include
 /path/to/glibc-2.23/build/install/include
 /usr/include/c++/6
 /usr/include/x86_64-linux-gnu/c++/6
 /usr/lib/gcc/x86_64-linux-gnu/6/include
 /usr/local/include
 /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed
 /usr/include/x86_64-linux-gnu
 /usr/include

如果您使用 --prefix=/usr 配置 glibc 并使用 DESTDIR=/path/to/glibc-2.23/build/install 安装它,它的头文件将安装到目录 /path/to/glibc-2.23/build/install/usr/include 中。这意味着您应该能够使用 -isysroot 选项,它会重写默认的 /usr/include 目录,从而使搜索路径的顺序正确:

#include "..." search starts here:
#include <...> search starts here:
 .
 /project-foo/include
 /project-bar/include
 /usr/include/c++/6
 /usr/include/x86_64-linux-gnu/c++/6
 /usr/include/c++/6/backward
 /usr/lib/gcc/x86_64-linux-gnu/6/include
 /usr/lib/gcc/x86_64-linux-gnu/6/include-fixed
 /path/to/glibc-2.23/build/install/usr/include