问题
I have a fat (32- and 64-bit) Intel binary called myBinary
that fails to run on another workstation running 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
I compiled it from a Mac OS X 10.8.2 workstation running GCC 4.7.2:
$ gcc --version
gcc (MacPorts gcc47 4.7.2_2+universal) 4.7.2
I ran nm
and the symbol is undefined:
$ nm /usr/local/bin/myBinary | grep __ZNSt8__detail15_List_node_base7_M_hookEPS0_
U __ZNSt8__detail15_List_node_base7_M_hookEPS0_
What did I miss or do wrong when compiling myBinary
? I'm not sure what I can do about a missing symbol in /usr/lib/libstdc++.6.dylib
— should I have statically compiled the C++ library into myBinary
?
回答1:
yeah you have 2 options, either not use libraries that the customer won't have... (you can provide them as a dyld or framework.)
or just statically link the library... this will actually end up being smaller in memory and disk space if your package is only one process, because you can strip symbols that you don't use.
回答2:
Each C++ compiler has its own implementation of Standard C++ Library. Since you're using external compiler (GCC 4.7) its library is not available among standard installations of Mac OS X.
Your only options is to either bundle the library within your app or statically link it.
To bundle the library with the app:
Update install name of the library using
install_name_tool
Ensure your app will find it when needed
E.g. you can put the dylib into .app/Contents/Frameworks, set its install name to @rpath
and compile you app with the -rpath @executable_path/../Frameworks
.
回答3:
I ran into this same issue when compiling on 10.6 with MacPorts GCC 4.8, and then trying to run my application on a fresh 10.9 install without MacPorts. Luckily I found your question, and Kentzo's answer steered me in the right direction as to why the problem occurred... but it didn't really provide the solution I was looking for.
First, I'll explain why it runs on your system correctly: MacPorts has provided your system with the version of libstdc++ that GCC 4.7 is providing symbols for, under /opt/local/lib rather than /usr/lib. Here's what it looks like for me (with GCC 4.8 universal):
$ 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
And you can see what your application is linking to with 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)
The easiest way to improve portability is -static-libstdc++ -static-libgcc
in your final gcc build step (the one that calls the linker). You need both because dynamic libgcc will bring dynamic libstdc++ binding with it, so it's not enough to simply request static libstdc++. For a simple application, here's what your gcc line might look like:
g++ -static-libstdc++ -static-libgcc myBinary.cpp -o myBinary
However, according to the gcc man page about linker options, statically linking libgcc can cause problems when handling exceptions across libraries. I haven't run into issues with it, but you might.
So, to do it Kentzo's way, first you should get the newest install_name_tool from MacPorts so it won't be confused by unknown load commands:
sudo port install cctools +universal
Now, let's change the path so it searches the executable's directory:
/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'
Now you just need to distribute these dylibs with the application. If you're making a .app, copy the dylibs to myBinary.app/Contents/MacOS/.
One final note: If you're having trouble making a good universal binary, it is possible to build the architectures separately (with different compilers and options) and then merge them with 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
来源:https://stackoverflow.com/questions/15541706/handling-dyld-lazy-symbol-binding-failed-symbol-not-found-error-when-nm-does