运行时未定义的符号

Undefined Symbol at Runtime

我们在 Ubuntu 18.04 上使用 CMake 3.18 编译和 link 我们的代码。程序的结构是这样的:

有一个具有主要功能的应用程序,它在运行时加载共享库,比如说 lib_a.so。在运行时,这个库加载另外两个库,lib_b.so 和 lib_c.so 并使用它们中的符号。 lib_b.so 也使用 lib_c.so 中的符号。

lib_b.so 和 lib_c.so 是从 A 的子模块 B 和 C 编译而来的。

在某些系统上代码运行良好。然而,在某些系统上,我们会遇到未定义的符号错误,当使用 c++filt 对无法找到的符号进行 demangled 时,它看起来像这样:

Unable to load lib_a.so : lib_b.so: undefined symbol: D::E::Get(std::initializer_list<std::basic_string<char, std::char_traits<char>, std::allocator<char> > >)

命名空间 D 和 class D::E 位于 C 的子模块下。该子模块不包含 CMakeLists.txt,并且不会从中生成共享库或静态库。它是一个目录,仅包含源文件和头文件。

当我们使用 nm --defined-only lib_c.so 查看 lib_c.so 的定义符号时,我们看到有这个符号:

D::E::Get(std::initializer_list<std::__cxx11::basic_string<char, std::char_traits<char>, std::allocator<char> > >)

我们的G++版本是7.5.0,CMake版本是3.18.0。

据此,我们推断这是一个 CXX11 ABI 问题。所以,这些是我们分别尝试过的东西:

None 解决了问题。另外,没有变化。 lib_b.so 再次查找相同的符号。

然而,当我们编写一个 Makefile 来编译源代码和 link 共享库时,问题就消失了。

原来这是一个 third-party 库问题。

正如@Someprogrammerdude 所建议的,带有 VERBOSE=1 的 运行 CMake 显示 lib_b.so 与 -D_GLIBCXX_USE_CXX11_ABI=0.

相关联

我在B/CMakeFiles/B.dir/flags.cmake中手动修改为-D_GLIBCXX_USE_CXX11_ABI=1。这次之前的错误没有了。

然而,关于我们使用的 third-party 库之一,这给了另一个未定义的符号错误 cxx11_abi。

将库更新为使用 CXX11 ABI 编译的版本解决了该问题。