9

我有一个胖(32 位和 64 位)英特尔二进制文件myBinary,它无法在另一个运行 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?

4

3 回答 3

2

是的,您有 2 个选项,要么不使用客户没有的库...(您可以将它们作为 dyld 或框架提供。)

或者只是静态链接库...如果您的包只是一个进程,这实际上最终会在内存和磁盘空间中变小,因为您可以剥离不使用的符号。

于 2013-03-30T05:14:52.627 回答
1

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

您唯一的选择是将库捆绑在您的应用程序中或静态链接它。

要将库与应用程序捆绑在一起:

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

  2. 确保您的应用会在需要时找到它

例如,您可以将 dylib 放入 .app/Contents/Frameworks,将其安装名称设置为@rpath并使用-rpath @executable_path/../Frameworks.

于 2013-03-23T09:44:08.757 回答
0

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

首先,我将解释为什么它可以在您的系统上正确运行:MacPorts 为您的系统提供了 GCC 4.7 为其提供符号的 libstdc++ 版本,位于 /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)

提高可移植性的最简单方法是-static-libstdc++ -static-libgcc在最后的 gcc 构建步骤(调用链接器的步骤)中。您需要两者,因为动态 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
于 2014-05-08T06:01:16.313 回答