最近项目开发新的功能,要在主应用中嵌入一个子程序:
(本文暂不涉及如何嵌入子程序)
主程序和子程序引用同一个framework,出现了重复,这会导致程序比较大。
为了解决此问题,学习了解了下xcode动态库设置
1. 首先我在子程序中移除嵌入的framework
2. 因为公用framework,所以我觉得将该framework嵌入大SharedFrameworks路径下比较合适
注: 路径是可以自定义的,我在该Demo中将其放在~/**MainApp.app/Contents/SharedFrameworks
3. build主工程后在主工程的.app文件中双击打开子程序
发现无法打开子应用,在Console中看到crash日志:
Dyld Error Message:
dyld: Using shared cache: 467A83CB-BA86-3F07-B652-B9256C74080A
Library not loaded: @rpath/**IPCComm.framework/Versions/A/**IPCComm
Referenced from: /Users/USER/Library/Developer/Xcode/DerivedData/ZWIPCDemo-gkbfqxfobhhkajaylzhevlbfjqaq/Build/Products/Debug/**MainApp.app/Contents/Applications/**Indexer.app/Contents/MacOS/**Indexer
Reason: image not found
Library not loaded: @rpath/**IPCComm.framework/Versions/A/**IPCComm
4. 解决:
- 配置子程序Runpath Search Paths 路径:
这个路径要根据子工程嵌入的位置来设置
我的子应用相对主应用的路径:
~/**MainApp.app/Contents/Applications/**Indexer.app
我嵌入的共享Framework路径:
~/**MainApp.app/Contents/SharedFrameworks/**IPCComm.framework
所以我配置的是@executable_path/…/…/…/…/SharedFrameworks
2. 配置住程序Runpath Search Paths 路径:
我配置的为;@executable_path/…/SharedFrameworks
在解决该问题的过程中遇到几个变量:
@rpath, @loader_path, @executable_path
这里copy下参考2,以作记录(暂未验证,因为我的案例和这个介绍不同)
1. @executable_path:
这个变量表示可执行程序所在的目录. 比如 /path/QQ.app/Contents/MacOS/
2. @loader_path:
这个变量表示每一个被加载的 binary (包括App, dylib, 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 都能正确的被加载.
2. @rpath:
和前面两个不同, 它只是一个保存着一个或多个路径的变量.
比如 XPSSO.dylib 被两个 .app 使用, 且被包含的路径不同。
比如:
- 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):