处理 nm 找不到符号时"dyld: lazy symbol binding failed: Symbol not found"错误



我有一个名为myBinary的fat(32位和64位)英特尔二进制文件,无法在另一个运行Mac OS X 10.8.2的工作站上运行:

$ myBinary
dyld: lazy symbol binding failed: Symbol not found: __ZNSt8__detail15_List_node_base7_M_hookEPS0_
  Referenced from: /usr/local/bin/myBinary
  Expected in: /usr/lib/libstdc++.6.dylib
dyld: Symbol not found: __ZNSt8__detail15_List_node_base7_M_hookEPS0_
  Referenced from: /usr/local/bin/myBinary
  Expected in: /usr/lib/libstdc++.6.dylib
Trace/BPT trap: 5

我从运行GCC 4.7.2的Mac OS X 10.8.2工作站编译它:

$ gcc --version
gcc (MacPorts gcc47 4.7.2_2+universal) 4.7.2

我运行nm,符号未定义:

$ nm /usr/local/bin/myBinary | grep __ZNSt8__detail15_List_node_base7_M_hookEPS0_
     U __ZNSt8__detail15_List_node_base7_M_hookEPS0_

编译myBinary时我错过或做错了什么?我不确定我能做些什么关于/usr/lib/libstdc++.6.dylib缺失的符号-我应该静态编译c++库到myBinary吗?

是的,你有两个选择,要么不使用客户没有的库…(您可以将它们作为代码或框架提供。)

或者只是静态链接库…如果您的包只有一个进程,那么这实际上最终会占用更小的内存和磁盘空间,因为您可以去掉不使用的符号。

每个c++编译器都有自己的标准c++库实现。由于您使用的是外部编译器(GCC 4.7),因此它的库在Mac OS x的标准安装中不可用。

你唯一的选择是要么在你的应用程序中捆绑库,要么静态链接它。

将库与应用捆绑在一起:

  1. 使用install_name_tool更新库的安装名称

  2. 确保你的应用程序会在需要的时候找到它

。你可以把dylib放到.app/Contents/Frameworks中,把它的安装名设置为@rpath,然后用-rpath @executable_path/../Frameworks编译你的应用。

我在使用MacPorts GCC 4.8编译10.6时遇到了同样的问题,然后试图在没有MacPorts的新10.9安装上运行我的应用程序。幸运的是,我找到了你的问题,而Kentzo的回答引导我在正确的方向为什么问题发生…但它并没有真正提供我正在寻找的解决方案。

首先,我将解释为什么它可以在您的系统上正确运行:MacPorts已经为您的系统提供了libstdc++版本,GCC 4.7为它提供了符号,在/opt/local/lib下,而不是/usr/lib下下面是我看到的情况(使用GCC 4.8通用版本):

$ find /opt/local/lib -name 'libstdc++.*'
/opt/local/lib/gcc48/i386/libstdc++.6.dylib
/opt/local/lib/gcc48/i386/libstdc++.a
/opt/local/lib/gcc48/i386/libstdc++.a-gdb.py
/opt/local/lib/gcc48/i386/libstdc++.dylib
/opt/local/lib/gcc48/i386/libstdc++.la
/opt/local/lib/gcc48/libstdc++.6.dylib
/opt/local/lib/gcc48/libstdc++.a
/opt/local/lib/gcc48/libstdc++.a-gdb.py
/opt/local/lib/gcc48/libstdc++.dylib
/opt/local/lib/gcc48/libstdc++.la
/opt/local/lib/libgcc/libstdc++.6.dylib
/opt/local/lib/libstdc++.6.dylib

你可以看到你的应用程序链接到otool -L:

$ otool -L myBinary
myBinary:
    /opt/local/lib/libgcc/libstdc++.6.dylib (compatibility version 7.0.0, current version 7.18.0)
    /usr/lib/libgcc_s.1.dylib (compatibility version 1.0.0, current version 832.0.0)
    /opt/local/lib/libgcc/libgcc_s.1.dylib (compatibility version 1.0.0, current version 1.0.0)
    /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 125.2.11)

提高可移植性的最简单方法是在最后的gcc构建步骤(调用链接器的步骤)中使用-static-libstdc++ -static-libgcc。两者都需要,因为动态libgcc会带来动态libstdc++绑定,所以仅仅请求静态libstdc++是不够的。对于一个简单的应用程序,您的gcc行可能是这样的:

g++ -static-libstdc++ -static-libgcc myBinary.cpp -o myBinary

然而,根据gcc关于链接器选项的手册页,在处理跨库异常时,静态链接libgcc可能会导致问题。我没有遇到问题,但你可能会。

所以,按照Kentzo的方式,首先你应该从MacPorts获得最新的install_name_tool,这样它就不会被未知的加载命令所混淆:

sudo port install cctools +universal

现在,让我们改变路径,使它搜索可执行文件的目录:

/opt/local/bin/install_name_tool -change /opt/local/lib/libgcc/libstdc++.6.dylib '@executable_path/libstdc++.6.dylib'
/opt/local/bin/install_name_tool -change /opt/local/lib/libgcc/libgcc_s.1.dylib '@executable_path/libgcc_s.1.dylib'

现在您只需要将这些dylib与应用程序一起分发。如果你正在制作一个。app,将dylib复制到myBinary.app/Contents/MacOS/.

最后一点:如果你在制作一个好的通用二进制文件时遇到困难,可以分别构建体系结构(使用不同的编译器和选项),然后用lipo合并它们:

/usr/bin/g++ -arch i686 -mmacosx-version-min=10.5 -isysroot /Developer/SDKs/MacOSX10.5.sdk myBinary.cpp -o myBinary_32
/opt/local/bin/g++ -arch x86_64 -static-libstdc++ -static-libgcc myBinary.cpp -o myBinary_64
lipo myBinary_32 myBinary_64 -create -output myBinary

相关内容

最新更新