How to Convert Intel macOS Libraries to arm64 for Apple Silicon Simulators
This guide explains why Intel‑based macOS libraries need architecture conversion for Apple Silicon simulators, compares XCFramework and Rosetta solutions, and provides a step‑by‑step method using lipo, ar, and custom Swift code to replace load commands and rebuild arm64 binaries for simulator use.
Background
Older Macs used Intel x86_64 CPUs and the iOS simulator also ran on x86_64. Apple’s transition to Apple Silicon introduced arm64 for both devices and simulators. The traditional lipo -based fat binary cannot contain two slices with the same architecture name, so an arm64 library built for devices cannot be used directly by an arm64 simulator.
Problem
The simulator architecture changed from x86_64 to arm64, causing lipo to reject merging two arm64 slices (device and simulator) and resulting in build failures.
Apple‑provided solutions
XCFramework : separate slices per platform, but converting many third‑party libraries is impractical.
Rosetta simulator : run the simulator under Rosetta to use the x86_64 slice; this option is unavailable for the visionOS simulator.
Manual conversion for visionOS
Modify the Mach‑O load commands of the arm64 slice so that the same binary works for both device and simulator.
Key difference
Using otool -l shows that device binaries contain LC_VERSION_MIN_IPHONEOS while simulator binaries contain LC_BUILD_VERSION. Replacing the former with the latter (and adjusting related fields) makes the binary compatible with the simulator.
Conversion steps
Extract the arm64 slice from the fat library:
lipo -thin arm64 path/to/lib.xcframework/lib.a -output lib.arm64Unpack the slice into object files: ar x lib.arm64 Patch each object file :
Replace the load command LC_VERSION_MIN_IPHONEOS with LC_BUILD_VERSION.
Adjust cmdsize to include any build_tool_version entries.
Recalculate offsets for the header, load commands and data sections.
The Swift helper used by the original tool is reproduced below:
static func updatePreiOS12ObjectFile(lc: Data, minos: UInt32, sdk: UInt32) -> Data {
let offset = UInt32(abs(MemoryLayout<build_version_command>.stride - MemoryLayout<version_min_command>.stride))
let cmd = Int32(bitPattern: lc.loadCommand)
switch cmd {
case LC_SEGMENT_64:
return updateSegment64(lc, offset)
case LC_VERSION_MIN_IPHONEOS:
return createVersionMin(lc, offset, minos: minos, sdk: sdk)
case LC_DATA_IN_CODE, LC_LINKER_OPTIMIZATION_HINT:
return updateDataInCode(lc, offset)
case LC_SYMTAB:
return updateSymTab(lc, offset)
case LC_BUILD_VERSION:
return updateVersionMin(lc, offset, minos: minos, sdk: sdk)
default:
return lc
}
}Re‑assemble the modified objects into a new arm64 library:
ar cr lib.arm64 *.oHandling bitcode and build‑tool versions
If the library contains embedded bitcode, the build_tool_version structure must be accounted for when adjusting cmdsize. The relevant structs are:
struct build_tool_version {
uint32_t tool;
uint32_t version;
};
struct build_version_command {
uint32_t cmd; // LC_BUILD_VERSION
uint32_t cmdsize; // sizeof(build_version_command) + (ntools * sizeof(build_tool_version))
uint32_t platform;
uint32_t minos;
uint32_t sdk;
uint32_t ntools;
};When bitcode is present, you can convert it to LLVM IR with llvm‑dis, edit the load commands, and re‑assemble with llvm‑as. Use the same LLVM version as Xcode to avoid incompatibilities.
Verification
After rebuilding, the library links without architecture‑conflict errors and runs on an arm64 simulator (including visionOS) without Rosetta.
References
https://bogo.wtf/arm64-to-sim.html
https://github.com/luosheng/arm64-to-sim
Sohu Tech Products
A knowledge-sharing platform for Sohu's technology products. As a leading Chinese internet brand with media, video, search, and gaming services and over 700 million users, Sohu continuously drives tech innovation and practice. We’ll share practical insights and tech news here.
How this landed with the community
Was this worth your time?
0 Comments
Thoughtful readers leave field notes, pushback, and hard-won operational detail here.
