我正在尝试使用 GCC 4.9.3 在 OS X Yosemite 上构建和运行一个使用 Folly 的小示例应用程序。这是源代码:

#include <folly/AtomicHashMap.h>

int main() {
    folly::AtomicHashMap<int, int> map(256);
    map.insert(std::make_pair(1, 1));
    return 0;
}

我从源代码构建并安装了 Boost (1.59.0) 和 Folly(最新的 GitHub 头文件),确保使用了 GCC,现在它们的库和头文件在 /usr/local 中可用。 GCC 和其他依赖项是使用 MacPorts 安装的。我可以使用以下命令行成功构建上述示例:
$ g++-mp-4.9 main.cpp -std=c++11 -I/usr/local/include -L/opt/local/lib -lfolly -lglog

但是,当我尝试运行它时,出现以下错误:
$ ./a.out
dyld: Symbol not found: __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKSs
  Referenced from: /usr/local/lib/libfolly.57.dylib
  Expected in: flat namespace
 in /usr/local/lib/libfolly.57.dylib
Trace/BPT trap: 5

据我了解,这应该是 /usr/local/lib/libfolly.57.dylib 在加载时通​​过引用自动拉入 libboost_program_options.dylib 的方式。当我运行 otool -L 时,我可以看到它被列为依赖项:
$ otool -L /usr/local/lib/libfolly.57.dylib
/usr/local/lib/libfolly.57.dylib:
    /usr/local/lib/libfolly.57.dylib (compatibility version 58.0.0, current version 58.0.0)
    libboost_context.dylib (compatibility version 0.0.0, current version 0.0.0)
    libboost_program_options.dylib (compatibility version 0.0.0, current version 0.0.0)
    ...
libboost_program_options.dylib 位于 /usr/local/lib 中,如果我将其重命名为其他名称,则运行 ./a.out 会导致加载程序提示无法找到它(“dyld:未加载库:libboost_program_options.dylib”)。所以看起来加载器至少能够找到它。

我使用 nm -gU 检查了这个库导出的符号:
$ nm -gU /usr/local/lib/libboost_program_options.dylib | grep program_options
    ...
    0000000000023560 T __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE
    ...

所以有一个非常类似于加载器提示缺少的符号。损坏的名称只是具有不同的后缀。

[编辑:除非滚动到右侧,否则很难看到名称,因此这里又是:
  • nm 表示库包含 __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKNSt3__112basic_stringIcNS2_11char_traitsIcEENS2_9allocatorIcEEEE
  • 加载时的“缺失符号”是 __ZNK5boost15program_options22error_with_option_name23substitute_placeholdersERKSs 。]

  • 我在 /usr/local/include/boost/program_options/errors.hpp 中找到了相应的声明:
    namespace boost { namespace program_options {
    ...
        class BOOST_PROGRAM_OPTIONS_DECL error_with_option_name : public error {
    ...
        protected:
    ...
            virtual void substitute_placeholders(const std::string& error_template) const;
    

    我认为这是 Folly 在我构建它时使用的头文件,因为它是 substitute_placeholders/usr/include/usr/local/include 中唯一匹配的 /opt/local/include 。 (请注意,Folly 甚至不直接调用此函数,而是从 #include <boost/program_options.hpp> 调用 folly/experimental/ProgramOptions.h 并使用 boost::program_options 的其他成员。)

    在我看来,更长的损坏名称——唯一实际从 libboost_program_options.dylib 导出的名称——是正确的,因为它包含 std::string 参数。

    那么什么可能导致 libfolly.57.dylib 引用不同的(较短的)损坏的名称呢?

    其他注意事项:
  • 我最初是从 MacPorts 安装 Boost 而不是从源代码构建它的,它导致了同样的错误。
  • 如果我使用 g++-mp-4.9 main.cpp -std=c++11 -I/usr/local/include -L/opt/local/lib /usr/local/lib/libfolly.a -lglog 构建示例——换句话说,只需链接 Folly 的静态库——问题就会消失,示例会运行。
  • 最佳答案

    使用c++ filt(或http://demangler.com)对两个符号进行解混,boost库中的符号具有std::__1::basic_string前缀,而在愚蠢的情况下缺少的符号具有std::string。一些谷歌搜索表明 libc++(clang 的 C++ 标准库)使用 __1 子命名空间以避免与 libstdc++(GNU 的)冲突。这表明boost 是使用clang 和libc++ 编译的,这是OS X 上的默认设置,而folly 是使用libstdc++ 编译的(通过使用g++ 或为clang 指定不同的标志)。

    由于这两个库没有兼容的 ABI,仅修复符号名称对您没有帮助,因此您的解决方案必须涉及重新编译,以便它们共享相同的标准库实现。

    关于c++ - 为什么 Folly 的共享库引用了来自 Boost 的错误符号? (OS X 上的 GCC),我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/33685886/

    10-11 17:25