普通视图

发现新文章,点击刷新页面。
昨天以前首页

[转载] 告别构建错误, iOS 开发架构难题全面解析, 避免 CPU 架构陷阱

作者 wyanassert
2025年1月15日 16:15

原文地址

前言

如果你经常开发 iOS 中的第三方框架,那么你可能会遇到以下错误:

1
"Could not find module *** for target 'x86_64-apple-ios-simulator'."

或者:

1
"building for iOS Simulator, but linking in dylib built for iOS, file, '.../Frameworks/xxx.framework/xxx' for architecture arm64."

要解决这个问题,我们需要了解 CPU 架构和 Xcode 构建设置的一些知识,今天我们就来聊聊这个。

理解 CPU 架构

每个 CPU 都有一组可以执行的指令。这些指令主要分为两种类型:

CISC(复杂指令集计算)

  • 复杂且强大的指令。
  • 每条指令执行多个任务。
  • 例如:x86 处理器(由 Intel 和 AMD 使用)。

RISC(精简指令集计算)

  • 简单且快速的指令。
  • 每条指令执行一个任务。
  • 例如:ARM 处理器(由 Qualcomm、MediaTek 和苹果的 M1 芯片使用)。

什么是 32 位和 64 位

32 位:一次可以处理 32 位数据。
64 位:一次可以处理 64 位数据,允许更多的计算能力和内存使用。

常见架构

x86:Intel 和 AMD 使用的 32 位架构。

x86_64:x86 的 64 位版本,更强大,能处理更多数据。

ARM:Qualcomm 和 MediaTek 使用的 32 位架构。

ARM64:ARM 的 64 位版本,更强大,苹果的 M1 芯片使用。

主要的制造商

Intel 和 AMD:制造 x86 和 x86_64 处理器。

Qualcomm 和 MediaTek:制造 ARM 和 ARM64 处理器。

Apple:在 Apple Silicon 系列(M1、M1、M2、M3、M4 等)Mac 中使用
ARM64 处理器。

向 M 系列过渡与 Rosetta 的作用

M 系列处理器的引入,始于 M1,标志着苹果及其生态系统的重大转变。由于 M 系列基于 ARM,现有为 x86 构建的软件无法在这些新芯片上原生运行。为弥补这一差距,苹果推出了 Rosetta,它是一种兼容层,主要作用是允许 x86 软件在 M 系列处理器上运行。

M1 MacBooks 推出后,Xcode 最初就是使用 Rosetta 支持 x86 应用程序。

虽然这让开发者可以继续无缝工作,但 Rosetta 只是 Apple Silicon 过渡期的临时解决方案。随着 Xcode 12 的推出,苹果使 Xcode 能够在 ARM 上原生运行,全力支持 M 系列 MacBooks,而不再依赖于 Rosetta。

iOS 14 之前的模拟器仅限于 x86,并通过 Rosetta 在 M 系列 Mac 上运行。自 iOS 14 起,模拟器更新支持 ARM 和 x86,这意味着虽然模拟器可以在 M 系列 Mac 上原生运行,但未为 ARM 优化的应用程序仍会通过 Rosetta 运行。这种双重架构支持确保了过渡期间的兼容性和性能。

要检查你的应用程序正在使用哪种架构,你可以使用活动监视器。在活动监视器中,有一个名为”Kind”的列,显示应用程序是运行在 Intel(x86)还是 Apple(ARM)架构下。这一功能仅在 M 系列 Mac 上可用。

descript

Apple 物理设备架构

  • arm64:也称为 AArch64,现代 64 位 iOS 设备(iPhone 5S及更新机型),包括 A7、A8、A9、A10 和 A11 芯片的设备。
  • arm64e:较新的 64 位 iOS 设备,带有 A12仿生芯片及更新版本(例如,iPhone XS、XR、11、12、13 等)。
  • armv7:较旧的 32 位 iOS 设备(iPhone 3GS、4、4S)。
  • armv7s:略新的 32 位设备(iPhone 5、5C)。

Apple 模拟器架构

  • x86_64:基于 Intel 的 Mac 上的模拟器。
  • i386:用于较旧 iOS 版本的 32 位模拟器(主要是遗留支持)。
  • arm64:Apple Silicon(M1、M2)Mac 上的模拟器。

在了解了 CPU 架构基础知识、列出设备和模拟器架构,并讨论了 M
系列的历史和 Rosetta
的作用后,为解决之前提到的错误,我们需要知道如何找出我们集成的框架所支持的架构。

此外,我们需要调整构建设置,如 EXCLUDED_ARCHS 和
ONLY_ACTIVE_ARCH。接下来聊聊这些。

确定支持的架构

要确定 .xcframework 支持的架构,我们可以在终端中使用 lipo -info 命令。通过检查 .xcframework 中的目录,我们可以识别出支持哪些架构。以下是使用 lipo -info ~/Downloads/Bugly.framework/Bugly 查看 Bugly 2.6.0 版本的示例:

descript

根据命令输出可以看出 Bugly 2.6.0 版本支持 armv7、i386、x86_64 和 arm64 架构。

理解 EXCLUDED_ARCHS 和 ONLY_ACTIVE_ARCH

EXCLUDED_ARCHS

  • 定义:Xcode 中的一个构建设置,用于指定在构建目标时要排除的架构。
  • 用途:排除某些架构以避免兼容性问题或不必要的构建。
  • 示例:EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64 在为 iOS 模拟器构建时排除 arm64 架构,以确保兼容基于 Intel 的 Mac 上的 x86_64 模拟器。

ONLY_ACTIVE_ARCH

  • 定义:一个构建设置,决定 Xcode 是仅构建活动架构还是所有指定架构。
  • 用途:通过仅构建活动架构来加快开发过程中的构建速度。
  • 示例:ONLY_ACTIVE_ARCH = YES 仅构建活动架构,在开发过程中减少构建时间。通常在 Debug 配置中设置为 YES,在 Release 配置中设置为 NO,以确保最终构建支持所有所需架构。

说白了一个是黑名单,一个是白名单。

之前提到的错误

错误消息”Could not find module *** for target ‘x86_64-apple-ios-simulator’.”通常表示我们尝试使用的框架或模块不可用于我们目标的架构,它需要原生运行而不是使用 Rosetta,但我们试图导入仅为 x86_64 构建的框架或可测试应用:

descript

解决方法

我们可以实施一种变通方法来让测试目标运行,但这取决于使用的机器:

Apple Silicon M 系列:在 EXCLUDED_ARCHS 中排除 arm64。

descript

基于 Intel 的:在 Debug 模式下使用”仅构建活动架构”,这将允许项目成功运行。

descript

更好的解决方案

如果你可以控制框架的构建,建议打包的时候支持缺失的架构,特别是 arm64 模拟架构。

在分发的时候,优先使用 ios-arm64_i386_x86_64-simulator 或 ios-arm64_x86_64-simulator,更旧的模拟器一般就不用支持了。

如果你无法控制框架的构建,也无法联系开发者,你需要使用 EXCLUDED_ARCHS 排除缺失的架构。然而,这种方法可能限制你只能在物理设备上运行,特别是对于 Apple M 系列。此外,它要求你在使用此框架的所有依赖项中排除缺失的架构。例如,如果你使用的核心框架依赖于缺少架构的库,则核心框架和导入核心的项目都必须排除相同的架构。因此,在解决此类错误时要谨慎和耐心。

❌
❌