我正在尝试使用 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
引用不同的(较短的)损坏的名称呢?其他注意事项:
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/