为 Apple Silicon mac 模拟器构建静态库
Build static lib for Apple Silicon mac simulator
我的静态库是用 xcodebuild 构建的,然后从模拟器和设备构建结果创建了一个胖库。
这是我的 xcodebuild 命令:
xcodebuild OTHER_CFLAGS="-fembed-bitcode" -configuration "iphoneos" -target "${LIB_NAME}Common" -sdk iphoneos
xcodebuild OTHER_CFLAGS="-fembed-bitcode" -configuration "iphonesimulator" -target "${LIB_NAME}Common" -sdk iphonesimulator
lipo 命令:
lipo -create "${DEVICE_DIR}/lib${LIB_NAME}Common.a" "${SIMULATOR_DIR}/lib${LIB_NAME}Common.a" -output "${INSTALL_DIR}/include/${LIB_NAME}/lib${LIB_NAME}Common.a"
查看 fat lib 中的体系结构后,我得到:
$ lipo -info MyLibCommon.a
Architectures in the fat file: MyLibCommon.a are: armv7 i386 x86_64 arm64
但是,当我通过 cocoapods 将库添加到一个项目中时,运行 在模拟器上使用 Apple 的新 Silicon(带有 arm64 芯片组)上的项目,我得到了以下编译错误:
building for iOS Simulator, but linking in object file built for iOS, file 'MyLibCommon.a' for architecture arm64
模拟器的 arm64 架构不是一个选项,因为在 Apple Silicon Mac 上有 arm64 芯片组。
知道如何为 Apple Silicon Simulator 构建静态库吗?
这是不可能的。
很有可能,您的模拟器二进制文件只是 i386 和 x86_64。如果你真的有 arm64 iOS 二进制文件和 arm64 macOS 二进制文件,lipo
会出错:
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: test.a.ios and test.a.macos have the same architectures (arm64) and can't be in the same fat output file
无论您尝试使用完整的二进制文件、未链接的目标文件还是静态库,都会发生这种情况。原因很简单,就是胖文件格式的一个缺点:每个架构只能有一个切片。您需要 arm64 iOS 和 Apple Silicon 模拟器,但那将是 2x arm64。
您可能想尝试构建一个同时适用于 iOS 和 macOS 的瘦 arm64 二进制文件,但这也是不可能的。二进制文件是平台锁定的:
% otool -l test.o.ios | fgrep -B1 -A5 LC_BUILD_VERSION
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 2
sdk 14.2
minos 14.2
ntools 0
% otool -l test.o.macos | fgrep -B1 -A5 LC_BUILD_VERSION
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 1
sdk 11.0
minos 11.0
ntools 0
注意 platform 2
与 platform 1
。内核实际上会忽略这个加载命令,但 dyld
不会。而且你也不能在一个二进制文件中有两个这样的加载命令,这也被认为是无效的。
您可能还记得 Apple's announcement 中提到的“Universal 2”文件格式或引用它的内容 - 但他们撒了谎。没有“通用 2”,它与十年前的文件格式完全相同。当他们说“universal 2”时,他们的意思是“向您的 macOS 二进制文件添加一个 arm64 切片”。
在我看来,您有以下三种选择:
- 您构建单独的库并将名称分开。
- 您永远不会同时构建两种架构。
- 您在 Rosetta 下为 x86_64 和 运行 构建模拟器目标。
后两者在互联网上被广泛推荐,第 2 个是“只为活动架构构建”,第 3 个是“排除 arm64”。鉴于预计 Rosetta 最终会消失,从长远来看,第三种选择似乎不可行。
我的静态库是用 xcodebuild 构建的,然后从模拟器和设备构建结果创建了一个胖库。 这是我的 xcodebuild 命令:
xcodebuild OTHER_CFLAGS="-fembed-bitcode" -configuration "iphoneos" -target "${LIB_NAME}Common" -sdk iphoneos
xcodebuild OTHER_CFLAGS="-fembed-bitcode" -configuration "iphonesimulator" -target "${LIB_NAME}Common" -sdk iphonesimulator
lipo 命令:
lipo -create "${DEVICE_DIR}/lib${LIB_NAME}Common.a" "${SIMULATOR_DIR}/lib${LIB_NAME}Common.a" -output "${INSTALL_DIR}/include/${LIB_NAME}/lib${LIB_NAME}Common.a"
查看 fat lib 中的体系结构后,我得到:
$ lipo -info MyLibCommon.a
Architectures in the fat file: MyLibCommon.a are: armv7 i386 x86_64 arm64
但是,当我通过 cocoapods 将库添加到一个项目中时,运行 在模拟器上使用 Apple 的新 Silicon(带有 arm64 芯片组)上的项目,我得到了以下编译错误:
building for iOS Simulator, but linking in object file built for iOS, file 'MyLibCommon.a' for architecture arm64
知道如何为 Apple Silicon Simulator 构建静态库吗?
这是不可能的。
很有可能,您的模拟器二进制文件只是 i386 和 x86_64。如果你真的有 arm64 iOS 二进制文件和 arm64 macOS 二进制文件,lipo
会出错:
fatal error: /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/lipo: test.a.ios and test.a.macos have the same architectures (arm64) and can't be in the same fat output file
无论您尝试使用完整的二进制文件、未链接的目标文件还是静态库,都会发生这种情况。原因很简单,就是胖文件格式的一个缺点:每个架构只能有一个切片。您需要 arm64 iOS 和 Apple Silicon 模拟器,但那将是 2x arm64。
您可能想尝试构建一个同时适用于 iOS 和 macOS 的瘦 arm64 二进制文件,但这也是不可能的。二进制文件是平台锁定的:
% otool -l test.o.ios | fgrep -B1 -A5 LC_BUILD_VERSION
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 2
sdk 14.2
minos 14.2
ntools 0
% otool -l test.o.macos | fgrep -B1 -A5 LC_BUILD_VERSION
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 1
sdk 11.0
minos 11.0
ntools 0
注意 platform 2
与 platform 1
。内核实际上会忽略这个加载命令,但 dyld
不会。而且你也不能在一个二进制文件中有两个这样的加载命令,这也被认为是无效的。
您可能还记得 Apple's announcement 中提到的“Universal 2”文件格式或引用它的内容 - 但他们撒了谎。没有“通用 2”,它与十年前的文件格式完全相同。当他们说“universal 2”时,他们的意思是“向您的 macOS 二进制文件添加一个 arm64 切片”。
在我看来,您有以下三种选择:
- 您构建单独的库并将名称分开。
- 您永远不会同时构建两种架构。
- 您在 Rosetta 下为 x86_64 和 运行 构建模拟器目标。
后两者在互联网上被广泛推荐,第 2 个是“只为活动架构构建”,第 3 个是“排除 arm64”。鉴于预计 Rosetta 最终会消失,从长远来看,第三种选择似乎不可行。