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):
RISC (Reduced Instruction Set Computing):
What is 32-bit and?64-bit
Common Architectures
Key Players
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:
Apple Physical Device Architectures:
Apple Simulator Architectures:
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:
Example of Supported Architectures in Frameworks
The image below shows an example of several?.xcframework bundles, which include different architecture-specific builds.
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
ONLY_ACTIVE_ARCH
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:
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.