今天在Mac上搞了一个动态库(开发环境Eclipse+sconsolidator), 生成dylib倒是简单。随后新建一个可执行的demo, 链接时在设置里指定dylib的目录和相应的库名,但-L参数指定的绝对目录死活都连不上,提示找不到此目录,把它换成相对目录就可以,非常诡异。当一切OK后,运行时出错了。错误原因是dylib动态库没加载,我把动态库放在/usr/local/lib和可执行程序目录下依然无效。百思不得其解,逐Google相关资料,直到找到此篇文章,才茅塞顿开。
http://qin.laya.com/tech_coding_help/dylib_linking.html
Creating working dylibs
So creating a working dylib of one of your own libraries is not a very well documented process. So I've decided to write a short summary of some things that will aid other people in creating their own dylibs that they can just stick into their app package and have work.
I assume that you already have knowledge of how to add a framework and get it to show up in the frameworks folder in your app package. You can find out how to do this sort of stuff from other pages, so I won't take the time to cover it here.
Some tools that will come in handy:
otool -L
install_name_tool
libtool
So, chances probably are that you've figured out how to compile your library into a dylib already, but when you add it to your project builder project and compile your code, you find that the dylib is being properly put into the right folder (the Frameworks folder) in your bundle. But your application won't work because it can't find the dylib! What's up?
Well, the problem isn't actually with project builder (it's actually sort of a bug with OS X, since it all worked properly in OS 9), it's with the library. If you open up the terminal and cd into your app package and find the binary that's in the Contents/MacOS folder, you can run otool -L
on the binary that you find there, and you might see something like the following:
% otool -L MyFunBinary
MyFunBinary
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 71.0.0)
libbz2.1.0.2.dylib (compatibility version 1.0.0, current version 1.0.2)
In this example, I'm trying to link in my own copy of the bzip2 library dylib that was created for me with bzip2 and a patch that's available on the internet.
As it turns out, in OS X 10.0 - 10.2, you need the path to the library to show up in there -- what you need is for the second line to show something like this:
@executable_path/../Frameworks/libbz2.1.0.2.dylib (compatibility version 1.0.0, current version 1.0.2)
This tells OS X that it should look in the place where the binary is, move up a directory and into the Framworks folder, and the library will be sitting there. Which it is. Indeed, if you run otool -L on the binary of some application in your /Applications folder that has a working frameworks or dylibs in the app package Frameworks folder (try one of the applications from Omni), you can see that this is the case -- all of their binaries comtain the right path. But the compiler is not figuring things out right... In fact, as it is right now, you can place the dylib in the same folder that the .app package is in, and things will run properly. But that's not what we want.
Well, the first thing you can try to do is to use install_name_tool. If you read the man page for install_name_tool, you can actually change the information inside of the executable so that it has the right location. Depending on how the application was compiled, this may or may not work correctly. More specifically, you'll be able to change the location if there was extra space compiled into the binary to allow space for a longer pathname. Generally install_name_tool will work on binaries, but not libaries. So you can now do this:
% install_name_tool -change libbz2.1.0.2.dylib @executable_path/../Frameworks/libbz2.1.0.2.dylib MyFunBinary
Now try to run the file. Voila! It should work.
However this is somewhat unacceptable, as whenever the binary gets changed -- taht is, whenever you recompile your code, this binary is going to get the short end of the shaft and get replaced by a new binary. Now, you could actually set up a shell script that runs install_name_tool every time you build your program, but that's somewhat of a hack. We might as well try to fix things at the origin of the problem.
As it turns out, the actual problem resides with the library itself. If you take your library, and run otool -L on it like this:
% otool -L libbz2.1.0.2.dylib
/usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 71.0.0)
libbz2.1.0.2.dylib (compatibility version 1.0.0, current version 1.0.2)
Well, this looks familiar! Well, in fact the computer picks up the location of the library from the library itself -- what we need to do is to get @executable_path/../Frameworks/
to show up in front of the binary name. We can try using install_name_tool, but this time we find out that things don't work. Why is this? There's no extra room compiled into the library to allow for a longer pathname, so we'd have to compile the original library with an extra flag to allow for more room in the path. But even better, we might as well compile things correctly the firs time! Note that I can't give you exact directions from this point on, since things will differ slightly for different applications you are compiling. But in general, you should go back to the source code for your application, find the linker line in the Makefile that generates the dylib, and change it, adding the -install_name
flag to the libtool line. You'll want to do something like:
libtool -dynamic -flat_namespace -install_name @executable_path/../Frameworks/libbz2.1.0.2.dylib \ -lSystem -compatibility_version 1.0 -current_version 1.0.2 \ -o libbz2.1.0.2.dylib -undefined suppress $(OBJS)
Anyway, I hope that helps some people out. Good luck!
Also of interest may be the Apple Documentation on Shared Libraries and Frameworks
.
简单的说,可执行文件中要链接的动态库在连接时已经写死在可执行文件中了,这个路径来自dylib内部。我使用otool -L 查看了dylib的路径,是Debug/aaa.dylb,它等同于-o后面的参数。按照作者提供的方法,修改dylib的install_name即可,不过libtool命令行太复杂,加之苹果又修改了其参数,以至于我想依葫芦画瓢在build完成后加个patch都不行。正要放弃之际, 发现gcc有一个install_name的选项。死马当活马医,试试看。结果没问题。
修改工程的Properties -> C/C++ Build -> Settings -> MacOS X C++ Linker->Miscellaneous, 加上-install_name @executable_path/aaa.dylib参数,这样生成的动态库拷贝到demo的目录下就可以用了。
PS:
原文我没仔细看,其实苹果已经提供了一个修改可执行程序dylib的install_name的方法
install_name_tool -change /usr/local/lib/aaa.dylib @executable_path/aaa.dylib "$PRODUCT_NAME"
"$PRODUCT_NAME"就是需要修改的可执行程序路径