on
Cross Compiling a C Library for iOS and macOS
Architectures everywhere
Apple has a neat array of devices running macOS and iOS - each of which run on multiple architectures. While macOS is making the transition to arm64, we still have to support x86_64 in the interim. Multiple architectures on macOS necessitates building for the iPhone simulator on arm64 and x86_64 as well. This means we have to build for
- macOS arm64
- macOS x86_64
- iOS arm64
- iPhoneSimulator arm64
- iPhoneSimulator x86_64
Targets To The Rescue
Fortunately, providing clang with a target at invocation, makes it quite easy to build across platforms. The target is defined by a triple like arm64-apple-darwin. The first part of the triple refers to the target architecture. The second part refers to the vendor, while the third is the target system. The triples we need to use to target macOS and iOS are
- macOS - arm64-apple-darwin, x86_64-apple-darwin
- iOS on device - arm64_apple-ios15.5
- iOS on simulator - arm64-apple-ios15.5-simulator, x86_64-apple-ios15.5-simulator
Modify the iOS versions referenced in the triples based on what’s installed on your system. The second part to the cross compiling is to provide a sysroot - a place where clang can find the headers, libraries for the target platform.
Compiling for macOS x86_64 would require a command invocation like
Similar platform folders for iPhoneSimulator and iPhoneOS can be found under
/Applications/Xcode.app/Contents/Developer/Platforms
.
We need to enable
Bitcode
as well, by passing in -fembed-bitcode-marker
, while compiling for iPhoneOS.
It’s important to use the version of clang
that is bundled with Xcode.app
(there might be one installed in /usr/bin
as well). The one in /usr/bin
will
not be able to work with the platform files in sysroot.
Once, we have compiled the code into object files we can assemble them into
static library files using llvm-ar
. This might require an installation of
llvm
.
Enter lipo
Even though macOS and iPhoneSimulator run on multiple architectures (arm64, x86_64), Apple considers them to be single platforms. So, we have to combine the libraries for each architecture into a single fat library before we use them in frameworks. After compiling the library for each architecture, we can lipo them.
With libraries compiled (and lipoed as needed) for macOS, iPhoneSimulator and
iPhoneOS, we can quite easily assemble them into a binary .xcframework
.