The Architecture Mismatch Dilemma in iOS: Solving the ‘Could Not Find Module *** for Target x86_64-apple-ios-simulator’ Issue on Apple Silicon

The Architecture Mismatch Dilemma in iOS: Solving the ‘Could Not Find Module *** for Target x86_64-apple-ios-simulator’ Issue on Apple Silicon



Imagine you’re working on a complex e-commerce app. Your team has divided the app into various features, like product listings, checkout processing, etc., with each feature implemented in custom frameworks. These frameworks depend on a core framework and integrate with third-party libraries such as Alamofire and Firebase. You’re working on an M1 MacBook Pro, while some of your colleagues use Intel-based Macs. When you import features or third-party frameworks or even import the testable app in the UnitTest target, you might encounter the error:

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

Or even this:

building for iOS Simulator, but linking in dylib built for iOS, file, ‘…/Frameworks/Core.framework/BaseRequest’ for architecture arm64.

To resolve this, we need to understand some knowledge about the CPU architectures and Xcode build settings.


Understanding CPU Architectures

Every CPU has a set of instructions it can execute. These instructions fall into two main types:

CISC (Complex Instruction Set Computing):

  • Complex and powerful instructions.
  • Each instruction does multiple tasks.
  • Example: x86 processors (used by Intel and AMD).

RISC (Reduced Instruction Set Computing):

  • Simple and fast instructions.
  • Each instruction does one task.
  • Example: ARM processors (used by Qualcomm, MediaTek, and Apple’s M1 chips).


What is 32-bit and?64-bit

  • 32-bit: Can process 32 bits of data at a time.
  • 64-bit: Can process 64 bits of data at a time, allowing for more power and memory usage.

Common Architectures

  • x86: 32-bit architecture used by Intel and AMD.
  • x86_64: 64-bit version of x86, more powerful and can handle more data.
  • ARM: 32-bit architecture used by Qualcomm and MediaTek.
  • ARM64: 64-bit version of ARM, more powerful and used in Apple’s M1 chips.

Key Players

  • Intel and AMD: Make x86 and x86_64 processors.
  • Qualcomm and MediaTek: Make ARM and ARM64 processors.
  • Apple: Uses ARM64 processors in Apple Silicon series (M1, M1 Pro, M1 Max, M2, etc.) Macs.

The Transition to M Series and the Role of?Rosetta

The introduction of M series processors, starting with the M1, marked a significant shift for Apple and its ecosystem. Since the M series is ARM-based, existing software built for x86 couldn’t run natively on these new chips. To bridge this gap, Apple introduced Rosetta, a compatibility layer allowing x86 software to run on M series processors.?

After the launch of M1 MacBooks, Xcode initially used Rosetta to support x86 applications. While this allowed developers to continue their work seamlessly, Rosetta was intended as a temporary solution during the transition to Apple Silicon. With Xcode 12, Apple enabled Xcode to run natively on ARM, fully supporting M series MacBooks without relying on Rosetta.?

Simulators before iOS 14 were limited to x86 and ran on M series Macs using Rosetta. Starting with iOS 14, simulators were updated to support both ARM and x86. This means that while simulators can run natively on M series Macs, applications not yet optimized for ARM would still run through Rosetta. This dual architecture support ensures compatibility and performance during the transition.

To check which architecture your applications are using, you can use the Activity Monitor. In the Activity Monitor, there is a column labeled “Kind” that shows whether an application is running under the Intel (x86) or Apple (ARM) architecture. This feature is only available on M series Macs. This is illustrated in the image below:

The ‘Kind’ column

Apple Physical Device Architectures:

  1. arm64: also known as AArch64, Modern 64-bit iOS devices (iPhone 5S and later), This includes devices with A7, A8, A9, A10, and A11 chips.).
  2. arm64e: Newer 64-bit iOS devices with A12 Bionic chip and later (e.g., iPhone XS, XR, 11, 12, 13,etc.).
  3. armv7: Older 32-bit iOS devices (iPhone 3GS, 4, 4S).
  4. armv7s: Slightly newer 32-bit devices (iPhone 5, 5C).

Apple Simulator Architectures:

  1. x86_64: Simulators on Intel-based Macs.
  2. i386: 32-bit simulators for older iOS versions (mainly legacy support).
  3. arm64: Simulators on Apple Silicon (M1, M2) Macs


After covering the basics of CPU architectures, listing device and simulator architectures, and discussing the history of the M Series and the role of Rosetta, to solve the errors mentioned earlier, we need to know how to figure out the supported architectures of the frameworks we integrate. Additionally, we need to adjust build settings like `EXCLUDED_ARCHS` and `ONLY_ACTIVE_ARCH`. Let's discuss these aspects.

Determine Supported Architectures

To determine the architectures supported by a? `.xcframework`, we can use the is command in the Terminal

lipo -info        

By examining the directories within the?`.xcframework`, we can identify which architectures are supported. Here's an example of using `lipo -info`:

lipo -info DocumentReader.framework/DocumentReader:        
The illustrated steps will help you determine the supported architectures of the

Example of Supported Architectures in Frameworks

The image below shows an example of several?.xcframework bundles, which include different architecture-specific builds.


  • ios-arm64_armv7: Targets physical iOS devices, ensuring compatibility with both newer (arm64) and older (armv7) devices.
  • ios-x86_64-simulator: Targets iOS simulators, ensuring compatibility with Intel (x86_64) architecture.
  • ios-arm64: Targets physical iOS devices, ensuring compatibility with newer (arm64) devices.
  • ios-arm64_x86_64-simulator: Targets iOS simulators, ensuring compatibility with both Apple Silicon (arm64) and Intel (x86_64) architectures.
  • ios-arm64_i386_x86_64-simulator: Targets iOS simulators, ensuring compatibility with both Apple Silicon (arm64) and Intel (x86_64) architectures, including older 32-bit simulators (i386).

Understanding these will help you solve the problem after adjusting build settings `EXCLUDED_ARCHS` and `ONLY_ACTIVE_ARCH`. Let's discuss these aspects.

Understanding EXCLUDED_ARCHS and ONLY_ACTIVE_ARCH

EXCLUDED_ARCHS

  • Definition: A build setting in Xcode to specify architectures to exclude when building the target.
  • Usage: Excludes certain architectures to avoid compatibility issues or unnecessary builds.
  • Example: `EXCLUDED_ARCHS[sdk=iphonesimulator*] = arm64` excludes the arm64 architecture when building for the iOS simulator, ensuring compatibility with x86_64 simulators on Intel-based Macs.

ONLY_ACTIVE_ARCH

  • Definition: A build setting determining whether Xcode should build only the active architecture or all specified architectures.
  • Usage: Speeds up the build process during development by building only for the active architecture.
  • Example: ONLY_ACTIVE_ARCH = YES builds only the active architecture, reducing build time during development. This is typically set to YES for Debug configurations and NO for Release configurations to ensure the final build supports all required architectures.

The Error Mentioned Earlier

The error message “Could not find module *** for target ‘x86_64-apple-ios-simulator’,” usually indicates that the framework or module we are trying to use is not available for the architecture we are targeting, it needs to run natively not using Rosetta, but we try to import the framework or tastable app that built for the x86_64 architecture only, check the image describing the issue.

Workaround

We can implement a workaround to make the test target run, but it depends on the machine being used:

  • Apple Silicon M series: Exclude arm64 in the EXCLUDED_ARCHS.

  • Intel-based: Use “Build Active Architecture Only” in Debug mode, which will allow the project to run successfully.


The Better?Solution?

If you have control over the framework generation, it’s recommended to include the missing architecture, particularly the arm64 simulation one. For distribution, prefer using ios-arm64_i386_x86_64-simulator or ios-arm64_x86_64-simulator if supporting older simulators isn't a priority.

In cases where you don’t have access or can’t request the framework from the provider, you’ll need to exclude the missing architecture using EXCLUDED_ARCHS. However, this approach might limit you to running only on physical devices, especially for the Apple M series. Additionally, it requires you to exclude the missing architecture in all dependencies that use this framework. For example, if you use a core framework that relies on a library that missing an architecture, both the core framework and the project that imports the core must exclude the same architecture. Therefore, exercise caution and patience when addressing such errors.

References

要查看或添加评论,请登录

Magdy Zamel的更多文章

  • Swift Memory Management: Heap & Stack

    Swift Memory Management: Heap & Stack

    Managing memory is crucial in mobile development for creating efficient and responsive apps. Since mobile devices have…

    7 条评论

社区洞察

其他会员也浏览了