关于这个知识点,如果你没有遇到类似的坑是不会去关注的。这里做个总结。
MacDown
项目的Link
设置
install Name
install Name 本质是一个路径,告诉连接器在运行时在哪里找到需要的库。比如libfoo.dylib
有一个/usr/lib/libfoo.dylib.
的install name.在链接的时候install name 会被拷贝到应用程序。当动态链接器需要libfoo.dylib
的时候,它将会从应用程序中找到这个install Name,然后知道在/usr/lib/
找到libfoo.dylib
这个库。
executable_path
有时候你需要嵌入一个库到应用程序中,而不是将这个库安装到\Library
下,绝对路径是不合适的。
Mac下的解决方案就是@executable_path
。当放在 install Name 前面的时候,比如Bar.app
依赖于Foo.framework
,并且Bar.app
安装在/Applications
。@executable_path
被展开为/Applications/Bar.app/Contents/MacOS
。如果想嵌入一个库在Contents/Frameworks
。只需要设置Foo.framework
的install Name 为@executable_path/../Frameworks/Foo.framework/Versions/A/Foo
。动态链接库会把它扩展为/Applications/Bar.app/Contents/MacOS/../Frameworks/Foo.framework/Versions/A/Foo
。这样就可以找到库了。
loader_path
查找可执行文件并不总是好用的,想象一下你需要传递一个已经嵌入了另一个库的库。比如Foo.framework
嵌入Baz.framework.
即使是Foo.framework
请求加载,当确实@executable_path
的具体指向的时候,动态链接器也找不到Bar.app
。
苹果提供了@loader_path
解决类似问题。他会扩展所有的路径,去掉最后的部分,无论是什么原因让库加载。如果是应用程序,则和@executable_path
一样,如果是Framework
或者plugin
,则和Framework
或者plugin
相关,这样更有用。
@rpath
上面的方案是可行的,但也有问题。问题是,库的单个拷贝只能用一种方式使用。如果想当Foo.framework
嵌入在一个应用程序或者安装到/Library/Frameworks
使用,你需要提供两个单独的不同的install name包。
苹果提供了@rpath
解决这个问题。当把@rpath
放在install name前面,就将告诉动态链接器去本地的列表搜索这个库。这个列表嵌入到这个应用程序,因此能够被应用程序的编译过程控制,而不是framework.因此单个framework可以用于多个目的。
To make this work, Foo.framework's install name would be set to @rpath/Foo.framework/Versions/A/Foo. An application that intends to embed Foo.framework would then pass -rpath @executable_path/../Frameworks to the linker at build time, which tells the dynamic linker to search for @rpath frameworks there. An application that intends to install the framework would pass -rpath /Library/Frameworks, telling the dynamic linker to search there. An application that for some reason doesn't want to commit to one or the other at build time can just pass both sets of parameters, which will cause the dynamic linker to try both locations.
例子
Absolute paths
对于安装在共享位置的库可用
Install path: /Library/Frameworks/Foo.framework/Versions/A/Foo
@executable_path
用于内嵌在应用程序中的库,允许设置相对于应用程序可执行文件的路径。
Install path: @executable_path/../Frameworks/Foo.framework/Versions/A/Foo
Application location: /Applications/Foo.app
Executable path: /Applications/Foo.app/Contents/MacOS
Framework location: /Applications/Foo.app/Contents/Frameworks/Foo.framework
- 把相关的路径链接在一起确定库的路径:
/Applications/Foo.app/Contents/MacOS/../Frameworks/Foo.framework/Versions/A/Foo
@loader_path
在Mac OSX 10.4
才可用。用于内嵌在插件中的库,允许设置这个库相对于插件的路径。(注意,相对于应用程序而言,插件不知道他从哪里被加载。所以知道@executable_path
是没有用的。)
@rpath
在Mac OSX 10.5
之后可用
-
@rpath
知识动态连接器,所有路径列表来找到对应的库。 - 重要是,这个路径是了已经加载的应用中存在
- 意味着当个库,比如
@rpath/Foo.framework/Versions/A/Foo
能够通过多种方式使用。也就是不在限制通过@executable_path or @loader_path
设置install name - 但是你必须传递额外的链接标识,当编译主应用的时候