我有一个名为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的标准安装中不可用。
你唯一的选择是要么在你的应用程序中捆绑库,要么静态链接它。
将库与应用捆绑在一起:
-
使用
install_name_tool
更新库的安装名称 -
确保你的应用程序会在需要的时候找到它
。你可以把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