本机系统架构:x86_64
太长不读总结:通常会默认以本机系统架构进行融合,如果编译器或链接器无法分析出需要融合的架构,需要指定 -target / -arch 来辅助。
1、多架构编译
- 编译多架构
gcc -target x86_64-apple-macos10.15 -c add.c -o x86
gcc -target arm64-apple-ios9.0 \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk \
-c add.c -o arm64
- 合并多架构
lipo -create -output add.o x86 arm64
- 打包成静态库
ar rcs libadd.a add.o
- 打包成动态库
gcc -target x86_64-apple-macos10.15 -fPIC add.o -shared -o share_x86
gcc -target arm64-apple-ios9.0 -fPIC add.o -shared \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk \
-o share_arm64
lipo -create -output share share_x86 share_arm64
2、单架构 MachO 和 多架构库
- 静态库
gcc libadd.a main.c -o main
// 或者使用下面的方式,因为本质上是链接器在做融合
gcc -c main.c -o main.o
ld main.o libadd.a -lSystem -o main
- 动态库
ld main.o share -lSystem -o main
用 MachOView 查看,可以看到多架构动态库 share 只有 share_x86 这个会被链接。
我们合成的多架构动态库 share 被分拆了,只拿了其中的 x86_64 的部分。
注意:这样会有什么问题?
可以看到这里 LC_LOAD_DYLIB 的路径信息 name 是相对路径,即编译器/链接器默认我们 main 执行文件,即放 share 动态库的地方会有 share_x86 这个单架构文件。
那如果找不到的话,是会报运行时错误的,所以多架构合成之后,也要小心不要把单架构文件删掉了。
其原因在于我合成的动态库其架构上的路径的不统一:
不过 iOS 开发不需要担心,Xcode 对于多架构的处理非常好:
其路径下的 name 是完全一样的,而且也没有发生像我这种拆分情况,直接链接的就是多架构的库
是我合成的动态库不标准,不同架构的路径不一样,但 Xcode 合成的路径是同一个。
比如图中的 /usr/lib/libSystem.B.dylib
它就是个多架构的库,并不影响单架构的使用。
那么 Xcode 是如何控制这个路径一样的呢?
-install_name @rpath/share
用这个就能控制动态库的搜索路径了。
即使库是多架构,可执行文件是单架构,也不用慌,因为只有对应架构部分被加载到内存当中。
如何验证?可以试试查找多架构库其中的某一个函数,会发现只有对应架构的版本。
dis -n "函数符号名"
想想其实很合理,看看文件结构就知道了:
文件当中会有 Fat Header,记录不同架构各自的 Header 信息在哪里,然后再去处理自己所需要的那部分架构。
但如果库中没有所需要的架构,那么肯定就是报错了:
dyld: Library not loaded: @rpath/XXX.framework/XXX
题外话:新版 Xcode 可能找不到设置架构的地方,可以用以下操作:
3、多架构 MachO 和 多架构库
gcc -target x86_64-apple-macos10.15 -c main.c -o main_x86
gcc -target arm64-apple-ios9.0 \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk \
-c main.c -o main_arm64
lipo -create -output main.o main_x86 main_arm64
多架构与多架构无法直接链接到一起,需要指定架构,分别链接好了,再合成到一起
4、多架构 MachO 和 单架构库
- x86 库
- arm64 库
由于默认是本机架构 x86_64,所以没能从中找到对应的符号,指定 arm64 架构看看:
gcc -target arm64-apple-ios9.0 \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk \
main.o arm64 -o main
- 动态库
可以看到多架构的 MachO 会被分拆,同样试试 arm64:
gcc -target arm64-apple-ios9.0 \
-isysroot /Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS14.0.sdk \
main.o share_arm64 -o main
5、总结
通常会默认以本机系统架构进行融合,如果编译器或链接器无法分析出需要融合的架构,需要指定 -target / -arch 来辅助。