当nm找不到符号时,处理“dyld:惰性符号绑定失败:未找到符号”错误

时间:2013-03-21 07:27:40

标签: macos gcc osx-mountain-lion dylib libstdc++

我有一个名为myBinary的胖(32位和64位)Intel二进制文件无法在运行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

3 个答案:

答案 0 :(得分:2)

是的,你有两个选择,要么不使用客户不会拥有的库......(你可以将它们作为dyld或框架提供。)

或者只是静态地链接库...如果你的包只是一个进程,这实际上最终会减少内存和磁盘空间,因为你可以删除你不使用的符号。

答案 1 :(得分:1)

每个C ++编译器都有自己的标准C ++库实现。由于您使用的是外部编译器(GCC 4.7),因此在Mac OS X的标准安装中无法使用其库。

您唯一的选择是在您的应用中捆绑图书馆或静态链接。

使用应用程序捆绑库:

  1. 使用install_name_tool

  2. 更新库的安装名称
  3. 确保您的应用在需要时找到它

  4. E.g。您可以将dylib放入.app / Contents / Frameworks,将其安装名称设置为@rpath并使用-rpath @executable_path/../Frameworks编译应用程序。

答案 2 :(得分:0)

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

首先,我将解释为什么它在您的系统上正确运行: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 man page about linker options,静态链接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