Simulator ARM64 Support for Static Libraries in M1 Machines

We have an SDK project that contains a static library (.a) with binaries for arm64, armv7 (Device) and x86_64, i386 (Simulator). When we run in M1 Macbooks we are unable to run on arm64 simulators and get the following error:

building for iOS Simulator, but linking in file built for iOS

Our SDK is built into an XCframework bundle, however this issue still persists. We have tried building the static library into its own XCframework as well by separating the architectures into two different binaries, one for Device and one for Simulator, however we still didn't get it to work.

We would like to know if this is a limitation or current issue on Xcode or if there are certain steps we need to follow to get this static library to be supported on arm64 simulators.

We have an SDK project that contains a static library (.a) with
binaries for arm64, armv7 (Device) and x86_64, i386
(Simulator).

This is definitely not the right approach. A universal binary, by definition, can only contain architectures for the same platform. iOS and the iOS Simulator are different platforms and thus shouldn’t be mixed in a universal binary.

We have tried building the static library into its own XCframework as
well by separating the architectures into two different binaries, one
for Device and one for Simulator, however we still didn't get it to
work.

This is the correct approach. Can you give us more details about what didn’t work?

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Thanks for the prompt reply. In order to generate the XCFramework for the static library, we generated 2 binaries, one with arm64, armv7 architectures (Device), and one with x86_64, arm64 architecture (Simulator), when we run the 'xcodebuild -create-xcframework' command and pass these two binaries, we are prompted with the following error related to the Simulator binary:

'error: binaries with multiple platforms are not supported'

We are building the Simulator binary using clang and passing the following options:
  • arch arm64 -isysroot iPhoneSimulator14.2.sdk -miphoneos-version-min=9.0 -fembed-bitcode

Our question is whether or not this seems like the right approach to properly build an arm64 Simulator binary in order to avoid the above error where xcodebuild doesn't recognize that the arm64 arch should be for Simulator platform? Thanks.


Sounds like the XCFramework infrastructure isn’t able to identify the platform for each of your static libraries. I recommend that you dump the each library to confirm that the platform is set correctly. Before I talked about how to do that, a quick primary on structure:
  • A static library is a collection of object files (extension .o, Mach type MH_OBJECT).

  • These are collected in the archive format (extension .a, see the ar(5) man page).

  • Each architecture is then merged into a Mach-O universal binary (extension .a, see <mach-o/fat.h>). Note that the universal binary header does not have field to indicate what platform each architecture applies to.

  • Finally, those are collected into an XCFramework (.xframework).

Each level has its own tools. For example, you can examine a static library with otool (see its man page), an archive with ar (man page) and ranlib (man page), and a universal binary with arch (man page) and lipo (man page). Some of these tools can see through higher levels. For example, otool can see through both the universal binary (select the target architecture using -arch argument) and the archive.

So, what you want to do is run otool against the static library to confirm that every object file has the correct platform info set. For example:

Code Block
% otool -l -arch arm64 libTest673387.a
Archive : libTest673387.a
libTest673387.a(Test673387.o):
Load command 1
cmd LC_BUILD_VERSION
cmdsize 24
platform 6
minos 14.3
sdk 14.3
ntools 0


This tells you that the arm64 architecture of the universal binary has an archive that contains an object file that was built for platform 6. A quick trip to <mach-o/loader.h> reveals that 6 refers to PLATFORM_MACCATALYST.

IMPORTANT Depending on the tools you use you may not see the LC_BUILD_VERSION command but instead see the older LC_VERSION_MIN_*** command, where *** identifies the platform.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Thanks for the information above, it is very helpful.
We ran the command as you mentioned above and here is our output:

Code Block
...
Load command 1
cmd LC_VERSION_MIN_IPHONEOS
cmdsize 16
version 9.0
sdk n/a
Load command 2
cmd LC_SYMTAB
cmdsize 24
symoff 16364
nsyms 290
stroff 21004
strsize 4056
...

We did not see a "platform" value, does this mean that the library was generated incorrectly?
As a next step, is there anything you would recommend to help generate arm64 simulator build properly and have XCFramework recognize the proper platform of each static library. Thanks.

We did not see a "platform" value

Right. If you have your deployment set high enough you’ll get a LC_BUILD_VERSION build command and that has an explicit platform field. If your deployment target is older, you’ll get a LC_VERSION_MIN_xxxx command where the platform is implied by the xxxx.

does this mean that the library was generated incorrectly?

It’s hard to say without seeing the results for all the architectures on all the platforms.

Share and Enjoy

Quinn “The Eskimo!” @ Developer Technical Support @ Apple
let myEmail = "eskimo" + "1" + "@apple.com"
Thanks. We will go back on our end and investigate further following your feedback above and get back with any updates.

I wrote up some details in another answer asking essentially the same question:

https://developer.apple.com/forums/thread/666335?answerId=685927022#685927022

The summary is:

  • xcframework is a collection of (usually fat) platform binaries all targeting different platform system interfaces
  • framework or library is a collection of different mach-o binaries targeting various different hardware architectures but all targeting the same platform system interface.

You must use a combination of lipo and xcframework to achieve an ultimate sumo framework supporting multiple platforms and multiple architectures.

Simulator ARM64 Support for Static Libraries in M1 Machines
 
 
Q