本文整理xcode工程配置,模块间依赖配置,安装和加载路径等,同时介绍关于引用第三方dylib或framework的注意点。
Build Settings中的变量@rpath、@loader_path、@executable_path
@executable_path
这个变量表示可执行程序所在的目录. 比如 /path/QQ.app/Contents/MacOS/
@loader_path
这个变量表示每一个被加载的 binary (包括App, dylib, framework, plugin等) 所在的目录,对于framework内置模块或plugin特别适合。
在一个程序中, 对于每一个模块, @loader_path 会解析成不用的路径, 而 @executable_path 总是被解析为同一个路径(可执行程序所在目录).
比如一个会被多个程序调用的 plugin,位于 /path/Flash Player.plugin/Contents/MacOS/Flash Player,依赖 /path/Flash Player.plugin/Contents/Frameworks/XPSSO.dylib,那么 XPSSO.dylib 的 INSTALL_PATH 可以设置为 @loader_path/../Frameworks, 这样设置的话, 不论 Flash Player.plugin 目录放到什么位置, XPSSO.dylib 都能正确的被加载.
@rpath
@rpath
和前面两个不同,它只是一个保存着一个或多个路径的变量。比如 XPSSO.dylib 被两个.app 使用,且被包含的路径不同。
- 对于被当成第三方库使用的dylib或Framework,本身
Install name
可以设置为包含@rpath
的值,这个@rpath
其实是一个变量 - 对于动态库的使用者,可以通过设置
Runpath Search Paths
指定多个值,这些值在运行时会用于替代动态库自己设置的@rpath
来查找动态库
比如:
softA.app/Contents/MacOS/dylib/XPSSO.dylib
softB.app/Contents/MacOS/Frameworks/XPSSO.dylib
将 XPSSO.dylib 的 INSTALL_PATH 设置成 @loader_path/../dylib 或 @loader_path/../Frameworks 都只能满足其中一个 .app 的需求。
要解决这个问题,就可以用 @rpath,将 XPSSO.dylib 的 INSTALL_PATH 设置成 @rpath,然后在编译 softA.app, softB.app 时分别指定 @rpath 为 @loader_path/../dylib, @loader_path/../Frameworks,问题得到了解决。
@rpath 的另一个优点是可以设置多个路径。如果 softA.app 还需要使用另一个 .plugin (假设它的 INSTALL_PATH 也设置成了 @rpath), 位于 @loader_path/../plugin, 把这个路径加到 @rpath 即可。
XPSSO.dylib的Build Settings中设置Installation Directory
在 softA.app或softB.app 中设置 Runpath Search Paths(对应了@rpath)
其他注意点
关于framework的注意点
- 不能导出有部分实现的基类,然后外面的派生类来继承使用,必须使用纯虚函数的接口
- 需要导出的headers直接放到framework内部,用
#import <MyFramework/my_header.h>
这样的方式加载
关于xcode依赖配置
- target dependence只是工程编译顺序依赖
- Link Binary With Libraries才是真正的库依赖
关于install_name_tool的使用问题
如果是xcode下自己编写的工程内的模块,一般是使用Install Name
和Runpath Search Paths
的设置来,但是引用第三方动态库dylib,很多时候需要根据目录设置,重新设置加载路径,Mac下有专门的改变加载动态库路径的命令工具:install_name_tool
- 改变第三方dylib或framework的install name,可以通过
-id
设置,如:install_name_tool -id "@rpath/xxx.dylib" "target_exe_or_dylib"
- 改变动态库的使用者的Runpath Search Paths,可以通过
-add_rpath
设置,如:install_name_tool -add_rpath "@loader_path/../bin/" "target_exe_or_dylib"
- 改变动态库的使用者的依赖项的位置,可以通过
-change
设置,当然首先查看目前依赖动态库的路径,查看命令:otool -L /path/to/xxx.dylib
,然后再设置:install_name_tool -change "/path/to/old.dylib" "/path/to/new.dylib" "target_exe_or_dylib"
- 查看可执行程序或动态库的Runpath Search Paths设置,可以使用
otool -l target_exe_or_dylib
,在最后查看LC_RPATH
段内容
当然,install_name_tool的这些控制命令还可以一起使用:
install_name_tool [-change old new] ... [-rpath old new] ... [-add_rpath new] ... [-delete_rpath old] ... [-id name] input
参考
- http://www.cnblogs.com/csuftzzk/p/mac_run_path.html
- http://blog.csdn.net/openglnewbee/article/details/17783909
- http://blog.csdn.net/dadalan/article/details/4335833
- http://www.tanhao.me/pieces/1361.html/
- https://developer.apple.com/library/mac/documentation/Darwin/Reference/ManPages/man1/dyld.1.html
- http://stackoverflow.com/questions/33991581/install-name-tool-to-update-a-executable-to-search-for-dylib-in-mac-os-x