如何让 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
研究
我在互联网上搜索了有类似问题的人,发现了以下相关内容:
- https://github.com/riscv/riscv-gnu-toolchain/issues/105
- https://askubuntu.com/questions/806220/building-ucb-logo-6-errors-in-mathcalls-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!
我发现了一些与此相关的事情:
- https://www.linuxquestions.org/questions/linux-software-2/how-to-get-local-gcc-to-link-with-local-glibc-404087/
- https://www.linuxquestions.org/questions/programming-9/inconsistency-detected-by-ld-so-dynamic-link-h-62-elf_get_dynamic_info-assertion-621701/
我看到的唯一解决方案是完全重新编译 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
如果上下文太多,最后会有一个 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
研究
我在互联网上搜索了有类似问题的人,发现了以下相关内容:
- https://github.com/riscv/riscv-gnu-toolchain/issues/105
- https://askubuntu.com/questions/806220/building-ucb-logo-6-errors-in-mathcalls-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!
我发现了一些与此相关的事情:
- https://www.linuxquestions.org/questions/linux-software-2/how-to-get-local-gcc-to-link-with-local-glibc-404087/
- https://www.linuxquestions.org/questions/programming-9/inconsistency-detected-by-ld-so-dynamic-link-h-62-elf_get_dynamic_info-assertion-621701/
我看到的唯一解决方案是完全重新编译 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