项目里RPATH使用比较混乱,也基本很多同事不深究,只要库里设了能工作就行了。
二进制文件有各种 @executable_path和@loader_path然后拼上
../Frameworks
../../Frameworks以及../../../Frameworks
这其实纯属瞎搞,根本没搞清楚哪个起作用。
于是清理工作开始。在过程中,有一个情况比较特殊,中间用了.framework。然后它里面有symbol
link会造成理解的混乱。
先讲一下上面这两个东西的用法,网上文章比较多。大部分讲的都正确,总结一下,就是一般情况下,执行文件用@executable_path,库用@loader_path。然后它们代表的是可执行文件,库所在的路径,相当于二进制文件本身的Parent目录。所以@loader_path/Sibling.dylib
其实代表着和本身同目录的兄弟文件,以此类推。
@executable_path/../Frameworks
代表可执行文件本身的文件夹外层的文件夹下的Frameworks目录。
相对于MACOS的Frameworks
conanchen@ConanChen
MacOS % cd ../Frameworks
conanchen@ConanChen Frameworks % pwd
/Users/conanchen/Downloads/Fusion_Output_MAC_Release_AppleSilicon/Autodesk
Fusion 360.app/Contents/Frameworks
接下来讨论一下在带.framework的情况。
.framework
conanchen@ConanChen Frameworks % otool -L
/Users/conanchen/Downloads/Fusion_Output_MAC_Release\
FSR/Frameworks/ClientFramework/ClientData.framework/ClientData
/Users/conanchen/Downloads/Fusion_Output_MAC_Release
FSR/Frameworks/ClientFramework/ClientData.framework/ClientData:
@rpath/ClientFramework/ClientData.framework/ClientData
(compatibility version 0.0.0, current version 0.0.0)
@rpath/Qt/QtRemoteObjects.framework/Versions/5/QtRemoteObjects
(compatibility version 5.15.0, current version 5.15.2)
@rpath/ClientFramework/ClientCommon.framework/Versions/A/ClientCommon
(compatibility version 0.0.0, current version 0.0.0)
可以看到,它的ID是在外层的快捷方式,引用ClientData的模块会去定位这个在外面的快捷方式,但加载的是符号链接所指向的真实文件。
ClientData本身的LC_RPATH,应该也只会对真实文件的所在的路径起作用,相对路径是以内部真实文件为基础的。
但别人加载ClientData却是引用的外层的快捷方式,所以各级引用库会看起来不一致,有的引用快捷方式所在路径,有的引用库真实路径。
经过测试,QT库所有的ID是指向内部真实文件的,并不是外面的快捷方式。
快捷方式可能用来给Framework升级用的,它永远指向真实文件的位置,编译的时候CMAKE可以引用外面的快捷方式,但是文件ID记录的是真实文件所在路径,而不是符号链接的位置。
但是ClientData明显不是这样,可以说是它错了或者不标准。
它引用其他ClientCommon的位置,也是一个真实文件的位置,这和QT是一致的。
QT应该是对的。QtGUI引用QtCore用@loader_path/../../../是正确的。ID和依赖都写的真实文件的路径。
对QT来说是用@loader_path/../../../来引用相对路径中的库引用,但是ClientData不是,它用的可执行文件那些多层的../../../Frameworks,这就已经挖了一个坑了,你一个库,其实正常情况不应该知道可执行文件和它内部的结构,只应该关注自己的位置。
otool -L binary 会显示ID和依赖的库
形如
@rpath/binarySelf
@rpath/binaryDependency
ID的作用是,别人引用它的时候,@rpath/binarySelf会被作为字符串写进别人的dependency。
而@rpath本身在加载的时候,会被otool -l
binary所显示的LC_RPATH段所指示的路径所替代,LC_RPATH可以有多个,每个具体值以@exectuable_path或@loader_path开头。这些路径被用来替换@rpath,并查找每个binaryDependency。
@loader_path和@executable_path的起始路径
项目里RPATH使用比较混乱,也基本很多同事不深究,只要库里设了能工作就行了。
二进制文件有各种 @executable_path和@loader_path然后拼上 ../Frameworks
../../Frameworks以及../../../Frameworks
这其实纯属瞎搞,根本没搞清楚哪个起作用。
于是清理工作开始。在过程中,有一个情况比较特殊,中间用了.framework。然后它里面有symbol link会造成理解的混乱。
先讲一下上面这两个东西的用法,网上文章比较多。大部分讲的都正确,总结一下,就是一般情况下,执行文件用@executable_path,库用@loader_path。然后它们代表的是可执行文件,库所在的路径,相当于二进制文件本身的Parent目录。所以@loader_path/Sibling.dylib 其实代表着和本身同目录的兄弟文件,以此类推。
@executable_path/../Frameworks 代表可执行文件本身的文件夹外层的文件夹下的Frameworks目录。
conanchen@ConanChen MacOS % cd ../Frameworks
conanchen@ConanChen Frameworks % pwd
/Users/conanchen/Downloads/Fusion_Output_MAC_Release_AppleSilicon/Autodesk Fusion 360.app/Contents/Frameworks
接下来讨论一下在带.framework的情况。
conanchen@ConanChen Frameworks % otool -L /Users/conanchen/Downloads/Fusion_Output_MAC_Release\ FSR/Frameworks/ClientFramework/ClientData.framework/ClientData
/Users/conanchen/Downloads/Fusion_Output_MAC_Release FSR/Frameworks/ClientFramework/ClientData.framework/ClientData:
@rpath/ClientFramework/ClientData.framework/ClientData (compatibility version 0.0.0, current version 0.0.0)
@rpath/Qt/QtRemoteObjects.framework/Versions/5/QtRemoteObjects (compatibility version 5.15.0, current version 5.15.2)
@rpath/ClientFramework/ClientCommon.framework/Versions/A/ClientCommon (compatibility version 0.0.0, current version 0.0.0)
可以看到,它的ID是在外层的快捷方式,引用ClientData的模块会去定位这个在外面的快捷方式,但加载的是符号链接所指向的真实文件。
ClientData本身的LC_RPATH,应该也只会对真实文件的所在的路径起作用,相对路径是以内部真实文件为基础的。
但别人加载ClientData却是引用的外层的快捷方式,所以各级引用库会看起来不一致,有的引用快捷方式所在路径,有的引用库真实路径。
经过测试,QT库所有的ID是指向内部真实文件的,并不是外面的快捷方式。
快捷方式可能用来给Framework升级用的,它永远指向真实文件的位置,编译的时候CMAKE可以引用外面的快捷方式,但是文件ID记录的是真实文件所在路径,而不是符号链接的位置。
但是ClientData明显不是这样,可以说是它错了或者不标准。
它引用其他ClientCommon的位置,也是一个真实文件的位置,这和QT是一致的。
QT应该是对的。QtGUI引用QtCore用@loader_path/../../../是正确的。ID和依赖都写的真实文件的路径。
对QT来说是用@loader_path/../../../来引用相对路径中的库引用,但是ClientData不是,它用的可执行文件那些多层的../../../Frameworks,这就已经挖了一个坑了,你一个库,其实正常情况不应该知道可执行文件和它内部的结构,只应该关注自己的位置。
otool -L binary 会显示ID和依赖的库
形如
@rpath/binarySelf
@rpath/binaryDependency
ID的作用是,别人引用它的时候,@rpath/binarySelf会被作为字符串写进别人的dependency。
而@rpath本身在加载的时候,会被otool -l binary所显示的LC_RPATH段所指示的路径所替代,LC_RPATH可以有多个,每个具体值以@exectuable_path或@loader_path开头。这些路径被用来替换@rpath,并查找每个binaryDependency。