Did you know that Xcode 12 builds both x86_64
and arm64
slices for the iOS Simulator now?
Only under certain circumstances, though.
If you build with xcodebuild
, and specify the generic
destination, like so:
xcodebuild -project Cat.xcodeproj -scheme Cat -destination "generic/platform=iOS Simulator"
and then you do this from the command line:
lipo -archs Cat.app/Cat
you’ll see this:
x86_64 arm64
If you build the same thing within the Xcode application, specifying a particular simulator model, on any Mac now shipping, you’ll instead see this:
x86_64
Looks like they’re thinking ahead to ARM-based Macs, eh?
This can cause problems.
Let’s say you have a pre-built framework, ready for the simulator and any iOS device.
When you try to link that framework under the above command, you’ll get an odd-sounding error, something like this:
building for iOS Simulator, but linking in object file built for iOS, for architecture arm64
That’s weird, right? It’s looking for the arm64
slice, and it found it! But because it’s categorized as for device, instead of for the simulator, the linker errors out.
You might say to yourself, I can fix this! I’ll rebuild my framework using Xcode 12!
You can, but it may involve more effort than you’re willing to put in right now.
The old way you make a framework for shipping is with lipo
. But when you try to use lipo -create
to combine (a) a device binary with ARM slices and (b) a simulator binary with ARM and Intel slices, you get an error:
lipo: simulator/Meow.framework/Meow and devices/Meow.framework/Meow have the same architectures (arm64) and can't be in the same fat output file
So that’s out.
The new way to make a framework for shipping is to make it an XCFramework.
As far as I can tell, even in Xcode 12, support for this is not built in to the application itself. You have to use xcodebuild
, as described in this WWDC session. And your end product is no longer a .framework
bundle, but rather an .xcframework
bundle, requiring that every target that links against it be modified.
This is fine if you control all the code yourself, but what if you’re getting a framework from a third-party vendor? Are they ready to switch to an XCFramework right now?
In any case, unless you’ve gotten your hands on one of those shiny new developer kits from Apple, there’s absolutely no need for you to be building simulator builds for ARM just yet.
Instead, don’t build for ARM at all.
Go to your Target build settings, go to Architectures, and then go to the new setting Excluded Architectures (EXCLUDED_ARCHES
), which Apple recommends you use instead of the older setting Valid Architectures (VALID_ARCHS
).
There, hover over it with your mouse and click the + button that appears, and it will give you the option of adding a subheading called “Any iOS Simulator SDK”. Do that, and add an arm64
entry to the build setting’s list of values.
You don’t want to specify this for any Debug build, as you could be building a Debug build for the device. Just the simulator.
You can also, instead of specifying it in the project, specify it in the xcodebuild
invocation, like so:
xcodebuild -project Cat.xcodeproj -scheme Cat -destination "generic/platform=iOS Simulator" EXCLUDED_ARCHS=arm64
I hope this helps anyone who’s been puzzling over this issue!