使用 CMake 构建 .so 库时提升未定义符号

Boost undefined symbol when building .so library with CMake

我正在 Linux 上使用使用 Boost 1.75.0 的 CMake 构建共享库 (.so)。

在CMakeLists.txt中,Boost的添加方式如下:

find_package(Boost REQUIRED COMPONENTS system chrono filesystem date_time log iostreams program_options)

并添加到目标:

target_link_libraries(mytarget PUBLIC ${Boost_LIBRARIES})

CMake 找到了 Boost,所以这里没有问题。

Boost 链接为静态库。当我列出链接的目标文件时,我得到了正确的库:

-- LIB_FILES: ...;/path/to/boost/debug/lib/libboost_filesystem.a;...

库编译和链接没有错误。

但是,当我使用库的一个简单函数时,出现以下错误:

undefined symbol: _ZNK5boost10filesystem16filesystem_error4whatEv

这个符号确实在库中未定义:

$ nm -g libmytarget.so | grep _ZNK5boost10filesystem16filesystem_error4whatEv
                 U _ZNK5boost10filesystem16filesystem_error4whatEv

demangled名称为boost::filesystem::filesystem_error::what() const,在boost/filesystem/exception.hpp中定义为

namespace boost
{
  namespace filesystem
  {
    class BOOST_FILESYSTEM_DECL filesystem_error : public std::exception
    {
    public:
      virtual const char * what() const throw();
...

请注意,我的代码不会调用此方法。

符号在libboost_filesystem.a中定义,链接器使用,作为文本(代码)部分中的符号:

$ nm -g /path/to/boost/debug/lib/libboost_filesystem.a | grep _ZNK5boost10filesystem16filesystem_error4whatEv
00000000000003fa T _ZNK5boost10filesystem16filesystem_error4whatEv

我的问题:

我不明白为什么这个符号在编译库中是未定义的,当它出现在静态链接库(文件libboost_filesystem.a)中时,它被链接器识别和使用.

在 CMake 中启用 INTERPROCEDURAL_OPTIMIZATION 解决了问题:

set_target_properties(mytarget PROPERTIES INTERPROCEDURAL_OPTIMIZATION TRUE)

现在,符号已正确链接:

$ nm -g libmytarget.so | grep filesystem_error4what
00000000001cfe22 T _ZNK5boost10filesystem16filesystem_error4whatEv

但我仍然不知道幕后发生了什么,也不知道为什么首先会出现这个错误。