Runtime linking on Mac
来源:互联网 发布:专业网络k歌声卡 编辑:程序博客网 时间:2024/06/07 12:24
Some files for testing
With thanks to https://dev.lsstcorp.org/trac/wiki/LinkingDarwin
Create files a.cc
through d.cc
mkdir \$HOME/dyldtestcd \$HOME/dyldtestcat << EOF > a.cc#include <iostream>void a() { std::cout << "a()" << std::endl; }EOFcat > b.cc << EOF#include <iostream>void a();void b() { std::cout << "b()" << std::endl; a(); }EOFcat > c.cc << EOF#include <iostream>void b();void c() { std::cout << "c()" << std::endl; b(); }EOFcat > d.cc << EOFvoid c();int main(int, char**) { c(); return 0; }EOF
Compile them to object files:
clang++ -c a.cc b.cc c.cc d.cc
Create libraries from a.o and b.o:
clang++ -o liba.dylib -dynamiclib a.oclang++ -o libb.dylib -dynamiclib b.o -L. -la
Using otool -L
to show linked library locations
Notice the otool -L
output for these libraries:
liba.dylib: liba.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)libb.dylib: libb.dylib (compatibility version 0.0.0, current version 0.0.0) liba.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
Link another library against these libraries:
clang++ -o libc.dylib -dynamiclib c.o -L. -lb -laclang++ -o test-lib d.o -L. -lcexport DYLD_PRINT_LIBRARIES=y./test-libunset DYLD_PRINT_LIBRARIES
This gives, among other output:
dyld: loaded: /Users/mb312/dyldtest/./test-libdyld: loaded: libc.dylibdyld: loaded: /usr/lib/libc++.1.dylibdyld: loaded: /usr/lib/libSystem.B.dylibdyld: loaded: libb.dylibdyld: loaded: liba.dylibdyld: loaded: /usr/lib/libc++abi.dylib
otool -L
on libc.dylib
:
libc.dylib: libc.dylib (compatibility version 0.0.0, current version 0.0.0) libb.dylib (compatibility version 0.0.0, current version 0.0.0) liba.dylib (compatibility version 0.0.0, current version 0.0.0) /usr/lib/libc++.1.dylib (compatibility version 1.0.0, current version 120.0.0) /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1197.1.1)
The install_name
So – the install_name
is two things:
- The name / location that a library provides to something that links against it. This is also the install name
id
(see man page forinstall_name_tool
). Theinstall_name
id
in a library you are linking to only matters at link time - The name that the linking application uses to say where it should find a library. The
install_name
values stored in your linking application or library matter at run time - because they tell the application or library where to find the library.
Install names and static absolute or relative paths
So far we’ve used library paths that are relative paths - in fact they are relative to the current directory from which we are executing our commands.
We can try moving our library:
mkdir amv liba.dylib a
Of course now our application fails:
\$ ./test-libdyld: Library not loaded: liba.dylibReferenced from: /Users/mb312/dyldtest/libc.dylibReason: image not foundTrace/BPT trap: 5
From the otool -L
output above, we have to change the install_name
in libb.dylib
, and libc.dylib
:
install_name_tool -change liba.dylib a/liba.dylib libb.dylibinstall_name_tool -change liba.dylib a/liba.dylib libc.dylib
Then, sure enough, test-lib
works again:
\$ ./test-libc()b()a()
Now move the other libraries to a new directory:
mkdir libsmv libb.dylib libc.dylib libs
Obviously we first have to tell test-lib
where libc.dylib
went:
install_name_tool -change libc.dylib libs/libc.dylib test-lib
But - oh dear - now libc.dylib
is confused:
\$ ./test-libdyld: Library not loaded: libb.dylibReferenced from: /Users/mb312/dyldtest/libs/libc.dylibReason: image not foundTrace/BPT trap: 5
So we need to tell libc.dylib
where libb.dylib
is:
install_name_tool -change libb.dylib libs/libb.dylib libs/libc.dylib
test-lib
then runs OK.
@loader_path
At the moment all our install_name
values are relative to the current directory. That’s not satisfying because it means if we run our command from anywhere but the current directory, the paths will be wrong. @loader_path
is one way to fix this. Here we tell test-lib
that it should look for libc.dylib
in the lib
directory relative to itself:
install_name_tool -change libs/libc.dylib @loader_path/libs/libc.dylib test-lib
Note the use of @loader_path
. This will be the directory containing the loading application or library - in our case the directory containing test-lib
. We can do the same trick to tell libc.dylib
where to find libb.dylib
, relative to itself:
install_name_tool -change libs/libb.dylib @loader_path/libb.dylib libs/libc.dylib
Note @loader_path
again. See rpath etc and linking and install names for more explanation. In this case @loader_path
will be the path of libc.dylib
- the library doing the loading of libb.dylib
. Now all’s good:
\$ ./test-libc()b()a()
We wanted to make it possible to call our executable from any directory, so we try that:
mkdir nice-placecd nice-place../test-lib
This gives:
dyld: Library not loaded: a/liba.dylibReferenced from: /Users/mb312/dyldtest/libs/libc.dylibReason: image not foundTrace/BPT trap: 5
Why? Because libc.dylib
is still looking for liba.dylib
at a/liba.dylib
– starting at the current working directory. How to fix? Of course:
install_name_tool -change a/liba.dylib @loader_path/../a/liba.dylib \ ../libs/libc.dylibinstall_name_tool -change a/liba.dylib @loader_path/../a/liba.dylib \ ../libs/libb.dylib
@rpath
Another option is to use @rpath
– see rpath etc:
install_name_tool -change @loader_path/../a/liba.dylib @rpath/liba.dylib \ ../libs/libc.dylibinstall_name_tool -change @loader_path/../a/liba.dylib @rpath/liba.dylib \ ../libs/libb.dylib
This won’t work yet because we haven’t told anything what @rpath
is:
\$ ../test-libdyld: Library not loaded: @rpath/liba.dylibReferenced from: /Users/mb312/dyldtest/libs/libc.dylibReason: image not foundTrace/BPT trap: 5
We can set @rpath
in our executable:
install_name_tool -add_rpath @loader_path/a ../test-lib
That works. Or in the libraries doing the loading:
# delete rpath we just set in executableinstall_name_tool -delete_rpath @loader_path/a ../test-lib# put into the library insteadinstall_name_tool -add_rpath @loader_path/../a ../libs/libc.dylib
All good again.
One advantage of @rpath
is that you can put several different search paths into the the library or executable @rpath
. For example, you could set the @rpath
so that the library or executable looks for its libraries in a relative path and also an absolute system path.
@loader_path and @rpath make code relocatable
Now notice this entire stack is relocatable (and has been since we started using @loader_path
:
cdcp -r dyldtest dyldtest2./dyldtest2/test-lib
All is still good. You are ready for great things related to OSX run-time loading.
- Runtime linking on Mac
- library linking on LINUX
- Static Linking on AIX
- To build the ruby runtime environment on Mac
- Dynamic linking static library on iOS
- dyld: Dynamic Linking On OS X
- Microsoft Visual Studio ~ C/C++ Runtime Library ~ Static/dynamic linking
- iOS Methods on Runtime
- turned on verbose logging for linking and checked to see if anything suspicious is going on
- Linking different libraries for Debug and Release builds in Cmake on windows?
- SegLink on github-Detecting Oriented Text in Natural Images by Linking Segments
- make package on mac
- Install PIL on mac
- build boost on mac
- Run Box2d on Mac
- StarDict On MAC
- Use IE on MAC
- OpenGL on Mac
- 在制定字符串内删除指定字符。
- SpringAOP之注入AspectJ切面
- more than one `-Acdtrux' or `--test-label' option
- 经典动态规划之最长上升子序列
- 使用maven和springMVC项目的结构
- Runtime linking on Mac
- C++ 阻塞队列
- 网络七层模型
- 我的博客
- HDU-1074-状态压缩DP
- The last packet sent successfully to the server was 0 milliseconds ago问题的解决
- 斯特林公式--求阶乘近似值
- 手机通讯模块开发协议文档索引
- SQL优化