前言
当你构建一个应用程序时,你需要为特定的“平台”和“CPU架构”组合进行构建。
iOS平台:
- iOS设备
"generic/platform=iOS"
- 模拟器
"generic/platform=iOS Simulator"
注意:还有很多其他平台。为了简洁起见,我只关注iOS平台。其他还有macOS、watchOS、tvOS、visionOS平台。
CPU架构:
这是因为macOS与iOS以及iOS模拟器使用不同的库。详见在构建iOS设备和模拟器时有什么不同之处?
而不同的CPU架构使用不同的CPU指令。
这意味着构建的二进制文件和运行环境(设备/模拟器)需要匹配。否则,操作系统上可能缺少某些系统库,或者无法处理CPU指令。
你是否总是构建同一组合?
不是的。如果你使用的是“Release”配置,那么你将为“arm64”和“x86_64”架构同时存档你的产品。
在存档过程中(通常在CI/CD中),会选择模拟器架构,导致一些问题。
然而,对于物理设备上的“Debug”构建,不会尝试为不同的平台或架构构建。这是因为它优先考虑“开发速度”而不是“完全正确性”。
默认的Xcode“ONLY_ACTIVE_ARCH”设置如下:
![enter image description here](https://istack.dev59.com/UikhK.webp)
我有一台Intel MacBook。如果我不排除任何架构和平台,会发生什么?
- 如果你正在构建一个调试配置,那么它只会构建目标平台的CPU架构。意思是:
- 如果你正在构建到你的iPhone上,你只需要支持ARM64架构。
- 如果你正在构建到模拟器上,你只需要支持X86_64架构。
- 如果你正在构建一个发布配置,那么它将:
- 构建适用于两个平台和所有可能的架构。
我有一台M1 MacBook。如果我不排除任何架构和平台,会发生什么?
如果你正在构建一个调试配置,那么它只会构建目标平台的CPU架构。意思是:
- 如果你正在构建到你的iPhone上,你只需要支持ARM64。
- 如果你正在构建到模拟器上,你只需要支持ARM64。
- 或者你可以为Xcode启用Rosetta。在这种情况下,如果你正在构建到模拟器上,那么你还需要支持X86_64。
如果你正在构建一个发布配置,那么会:
- 构建适用于两个平台和所有可能的架构。
为什么发布构建不同呢?
在积极开发过程中,你希望快速构建项目。没有必要构建你不需要使用的架构。这意味着如果你正在构建到设备上,那么你只想为该平台-架构组合构建。你不想构建其他组合。
然而,如果你要发布给其他人使用,那么因为你不想限制/指导他们如何构建你的应用程序,你就必须为所有可能的组合进行构建,并确保你的框架可以编译所有这些组合。
对于一个应用程序来说,为模拟器平台创建存档可能没有太多意义,但对于一个框架来说,你的消费者是另一个开发者。这个开发者将把你的框架构建到模拟器和真实设备中。因此,你需要支持两个平台和架构。
可可粉是问题的根源吗?
这要看情况。如果某个可可粉排除了某种架构,而你正试图为该架构构建应用程序,那么你必须要求可可粉的所有者不要排除它。
否则,如果你的所有可可粉都支持你要构建的特定平台/架构,那么问题就出在你自己编写的主机应用程序的代码中。
解决方案
更新支持Apple芯片的预编译库
如果错误信息中提到的库来自供应商,请参考
更新来自供应商的预编译库。如果您拥有该库的源代码,请重新构建该库,以支持Apple芯片上的模拟器。了解如何构建XCFramework,请参阅
创建多平台二进制框架捆绑包。
更新来自供应商的预编译库
如果产生构建错误的库是来自供应商的预编译库,并且您没有源代码,请联系供应商获取支持Apple芯片的更新XCFramework。如果供应商没有提供更新,可以临时使用EXCLUDED_ARCHS构建设置来排除模拟器SDK的arm64,如下图所示。请勿对其他SDK排除arm64。
来自
文档
关于解决方案结果的更多问题:
如果我在“iOS模拟器”平台中排除ARM64会发生什么?
您将无法直接构建到M1模拟器中。您需要在M1上使用带有Rosetta的Xcode。这是一种折中方法,速度稍慢。
如果我在“iOS模拟器”平台中排除X86会发生什么?
您将无法构建到基于Intel的模拟器中。您也无法使用Rosetta构建到模拟器中。
如果我在“iOS”平台中排除ARM64会发生什么?
您将无法构建到物理设备中。也无法为其创建存档。这是一个糟糕的想法!
那么我应该排除架构吗?
努力使您的应用程序(包括所有预编译库)始终构建为由ARCHS构建设置的默认值定义的完整架构集。仅在最终发布的应用程序不在特定架构上使用目标功能的目标上使用EXCLUDED_ARCHS构建设置,例如仅在基于Intel的Mac计算机上支持传统功能的Mac应用程序。不要修改ARCHS构建设置以达到相同的结果。
此外,在大型团队中,一些开发人员可能使用M1芯片,而其他人可能使用较旧的基于Intel的MacBook。你永远不知道,也许将来会有一款M5 MacBook,它将具有独特的架构。因此,在设计项目/产品/框架时,考虑到如何使其与开发人员和库的使用者兼容是很重要的。
我们是否有一台搭载Intel X86_64的iOS设备?
这样的设备并不存在。
如何检查一个二进制文件?
你可以使用lipo、file或dyld_info。
lipo和file只提供架构信息。
dyld_info提供架构、平台信息等更多信息。
在终端应用程序二进制文件上进行简单检查的比较,请参见以下内容:
![enter image description here](https://istack.dev59.com/QWYRc.webp)
记住,在XCFramework中通常会有两个或更多的二进制文件。例如,如果我们只是使用
lipo -info
,我们必须对库的两个二进制文件都执行此操作:
lipo -info <path-to-binary>
在xcframework打包中的arm64目录中,我看到:
Non-fat file: /Users/mfaani/Video.xcframework/ios-arm64/Video.framework/Video is architecture: arm64
对于《模拟人生》游戏,我看到的是:
Architectures in the fat file: /Users/mfaani/Video.xcframework/ios-arm64_x86_64-simulator/Video.framework/Video are: x86_64 arm64
你可以进入你的Mac的/Applications目录,右键点击任何应用程序,选择“显示包内容”,找到应用程序的相关二进制文件。然后使用lipo命令进行检查。
明确一点,无论是框架还是应用程序都可以使用lipo进行检查。同样,如果你访问模拟器上的构建文件夹,也可以检查二进制文件。
XCFramework和FAT二进制文件有什么区别?
- FAT二进制文件只是一个二进制文件,将两个(或更多)架构合并成一个单一的二进制文件。它之所以被称为FAT,是因为它变得臃肿。它的其他名称是“多架构二进制文件”或“通用二进制文件”。
- XCFramework只是一个结构化的文件夹,一个包装器。没有其他。它具有每个平台的不同文件夹。在每个文件夹中有一个二进制文件。该二进制文件可以是FAT二进制文件或非FAT(单一架构)二进制文件。
另外请注意,FAT二进制文件可以是框架或应用程序的二进制文件。XCFramework只是一个框架,它本身不是应用程序。
我的应用程序会因为其他我不需要的平台和架构组合而变得臃肿吗?
XCFramework不会使应用商店的提交变得臃肿,因为iOS设备的存档只会从与模拟器平台隔离的目录中选择每个框架。
然而,对于FAT二进制文件,由于它只是一个单一的二进制文件,您必须在提交到Apple商店之前对依赖项进行瘦身/切片。否则,您将收到以下错误消息:
不支持的架构。您的可执行文件包含不支持的架构“[x86_64,i386]”。
有关更多信息及其先前的解决方案,请参阅
此处。
要非常清楚,这是在Xcode 12之前的一个问题。但并不是每个项目设置都会遇到这个问题。只有当您有一些来自供应商的预编译依赖项(他们没有共享源代码,而只是共享了FAT二进制文件,以便您可以为设备和模拟器构建应用程序)时,您才会遇到这个问题。否则,如果您可以访问源代码,那么您的存档将不会包含针对两个体系结构的编译。它只会包含针对目标体系结构的二进制文件。
另请参阅这篇很棒的
博客文章,了解更多细节和历史背景。
一个FAT的文件夹结构是什么样的?
它只是一个二进制文件,不是一个文件夹。该二进制文件适用于两个或更多体系结构。
一个xcframework的文件夹结构是什么样的?
ios-arm64
- binary
ios-arm64_x86_64-simulator
- (FAT) binary
如果要使XCFramework与Mac Catalyst配合使用,则文件夹结构应如下所示:
ios-arm64
- binary
ios-arm64_x86_64-simulator
- (FAT) binary
ios-x86_64-maccatalyst
- binary
要获取更全面的可能平台列表,请参阅XCFrameworsk: 创建和集成xcframeworks以及它们与静态库和Swift包的合作演示
为什么我的供应商不支持ios-arm64-simulator?
可能有很多原因。
- 迁移工作:通常情况下,他们编译时没有M1芯片,而且他们已经很久没有编译过了,如果他们重新编译,就需要做一些改变。你要明白,多年来没有需要新的架构-平台组合的需求。所以这是新的,不是每个人都理解。Swift现在与之前的版本ABI兼容,减少了框架所有者需要每次新的Swift发布时重新编译应用程序的需求。所以他们可以多年不需要重新编译...
- 限制:预编译库依赖于另一个未编译为arm64-sim的预编译库。
- 框架所有者没有苹果芯片(arm64)的机器。或者了解这些事情的人已经离开了公司。
还有什么要补充的吗?
确保您查看所有项目和目标以及Pod项目和Pod目标的设置。如果其中一个排除了某个架构,那么您无法为该架构构建应用程序。通常,这可能在您的Podfile中。
或者,如果Pod/框架在完全不同的存储库中进行编译,则您在那里设置的设置最为重要。
如果您注意到您收到的错误消息,应该很容易找到不支持的目标。一旦确定了目标,您就必须根据上面两段的注释确定何时/何地进行编译。
arm64
添加到排除的架构中(构建设置)。 (3)清理构建文件夹。 (4)运行应用程序。 - Ryan Cocuzzo