本文整理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 使用,且被包含的路径不同。

  1. 对于被当成第三方库使用的dylib或Framework,本身Install name可以设置为包含@rpath的值,这个@rpath其实是一个变量
  2. 对于动态库的使用者,可以通过设置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的注意点

  1. 不能导出有部分实现的基类,然后外面的派生类来继承使用,必须使用纯虚函数的接口
  2. 需要导出的headers直接放到framework内部,用 #import <MyFramework/my_header.h> 这样的方式加载

关于xcode依赖配置

关于install_name_tool的使用问题

如果是xcode下自己编写的工程内的模块,一般是使用Install NameRunpath Search Paths的设置来,但是引用第三方动态库dylib,很多时候需要根据目录设置,重新设置加载路径,Mac下有专门的改变加载动态库路径的命令工具:install_name_tool

  1. 改变第三方dylib或framework的install name,可以通过-id设置,如:install_name_tool -id "@rpath/xxx.dylib" "target_exe_or_dylib"
  2. 改变动态库的使用者的Runpath Search Paths,可以通过-add_rpath设置,如:install_name_tool -add_rpath "@loader_path/../bin/" "target_exe_or_dylib"
  3. 改变动态库的使用者的依赖项的位置,可以通过-change设置,当然首先查看目前依赖动态库的路径,查看命令:otool -L /path/to/xxx.dylib,然后再设置:install_name_tool -change "/path/to/old.dylib" "/path/to/new.dylib" "target_exe_or_dylib"
  4. 查看可执行程序或动态库的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

参考