将 Clang 与内置的 libstdc++ 一起使用会产生未定义的符号 _ZSt15__once_callable

Using Clang with built libstdc++ produces undefined symbol _ZSt15__once_callable

我构建了 libstdc++,还没有修改:

cd gccsrcdir/libstdc++-v3/build
../configure --prefix=$PWD/../install
make && make install

我正在使用 Ubuntu 21.10 并设置了以下环境变量:

export LIBRARY_PATH=gccsrcdir/libstdc++-v3/install/lib
export LD_LIBRARY_PATH=gccsrcdir/libstdc++-v3/install/lib
export CPLUS_INCLUDE_PATH=gccsrcdir/libstdc++-v3/install/include/c++/13.0.0

然后当我使用系统的GCC时,我没有遇到任何问题。当我使用系统的 Clang 时,它会产生符号查找错误 - 即使没有参数:

clang++
clang++: symbol lookup error: /lib/x86_64-linux-gnu/libicuuc.so.67: undefined symbol: _ZSt15__once_callable, version GLIBCXX_3.4.11

其实我只需要更新LD_LIBRARY_PATH就可以到达这里。我做错了什么?

符号 -- std::__once_callable 在您的系统 libstdc++.so.6 中定义(它在我的构建中有版本 GLIBCXX_3.4.11means 它是在 GCC-4.4 中添加的.0).

您的 libstdc++.so.6 构建也应该 定义此符号,但由于某些原因没有。 一个问题——任何使用此符号的二进制文件在使用 libstdc++.so.6 的构建时都会在 运行 时失败(这是因为你指出LD_LIBRARY_PATH 到它)。

注意:在您的情况下,clang++ 二进制文件未能 运行 -- 您添加到其中的任何标志(例如 -femulated-tls)都是 irrelevant——它们只会影响如果clang++本身没有失败就会生成的二进制文件。


我只是重复了你的 configure && make 步骤,而这样构建的库 没有定义这个符号。

然后我重复了 configure && make,但是从 top-level GCC 目录开始,libstdc++.so.6 以这种方式构建 定义了符号。

结论:libstdc++ 在“正常”GCC 构建期间配置不同。

定义来自 mutex.o,它是从 ./libstdc++-v3/src/c++11/mutex.cc 构建的,并且有这段代码:

#ifdef _GLIBCXX_HAS_GTHREADS

namespace std _GLIBCXX_VISIBILITY(default)
{
_GLIBCXX_BEGIN_NAMESPACE_VERSION

#ifdef _GLIBCXX_HAVE_TLS
  __thread void* __once_callable;
  __thread void (*__once_call)();
...

因此,当直接在 libstdc++-v3 中执行 configure && make 时,听起来好像没有定义 _GLIBCXX_HAS_GTHREADS_GLIBCXX_HAVE_TLS

进一步挖掘,我看到 libstdc++-v3 通过尝试编译 #include "gthr.h" 来确定 _GLIBCXX_HAS_GTHREADS,并且该文件在 libgcc/gthr.h 中可用,但是 不是 在“标准”安装的 GCC 中。

../libstdc++-v3/configure && grep _GLIBCXX_HAS_GTHREADS config.h
/* #undef _GLIBCXX_HAS_GTHREADS */

TL;DR:正确配置 libstdc++.so 很复杂,构建 complete GCC 会更好。

完成构建后,您将有一个正确配置的 libstdc++-v3 目录,并且可以在该目录中重建:

grep _GLIBCXX_HAS_GTHREADS  ./x86_64-pc-linux-gnu/libstdc++-v3/config.h
#define _GLIBCXX_HAS_GTHREADS 1