Build fat static library (device + simulator) using Xcode and SDK 4+



Building a Fat Static Library for Device and Simulator in Xcode
Are you struggling to build a static library that can be used both on simulators and actual devices? You're not alone! Apple's lack of documentation on this topic and Xcode's default templates not configured for this have caused many developers to face difficulties. But fear not! In this blog post, we will guide you through a simple, portable, and reusable technique to build a fat static library that works seamlessly in both the simulator and on devices using Xcode and SDK 4+.
The Challenge: Building a Universal Static Library
To better understand the problem, let's take a brief look at the past. In 2008, it was possible to create single static libraries that included both simulators and devices. However, Apple disabled this functionality. Later, in 2009, developers resorted to creating separate static libraries for simulators and devices, but Apple disabled that too.
The Solution: A Portable Technique in Xcode
Despite Apple's restrictions, we have found a simple technique to create a universal static library that works on both simulators and devices within Xcode. Follow the steps below to get started:
Open Xcode and create a new project or navigate to your existing project.
Go to the project settings by selecting your project in the Project Navigator and selecting the project target.
Under the "Build Settings" tab, search for "Architectures."
Set the "Architectures" field to
$(ARCHS_STANDARD)
which is a placeholder for the standard architectures.Set the "Valid Architectures" field to
armv7 arm64 i386 x86_64
to ensure compatibility with both simulators and devices.
Next, go to the "Build Phases" tab in the project settings.
Under the "Link Binary With Libraries" section, click the "+" button to add the libraries you want to include in your universal static library. Make sure to select the same library for both the device and simulator targets.
Now, create a new "Aggregate" target. This will allow us to run custom build scripts.
Select your project in the Project Navigator, click the "+" button under "Targets," and choose "Aggregate." Rename the aggregate target to something like "Universal Library."
Open the "Build Phases" tab for the aggregate target, and under the "Run Script" section, add a new script by clicking the "+" button.
In the script editor, enter the following code:
# Step 1: Set the target folders and the final framework product. FRAMEWORK_NAME="YourFrameworkName" FRAMEWORK_VERSION=A # Step 2: Build Device and Simulator versions xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch 'arm64' only_active_arch=no defines_module=yes -sdk iphoneos CLEAN_BUILD_FOLDER=YES build xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch 'x86_64' only_active_arch=no defines_module=yes -sdk iphonesimulator CLEAN_BUILD_FOLDER=YES build # Step 3: Create the universal framework folder. UNIVERSAL_FOLDER="YourFrameworkName-Universal" DEVICE_FOLDER="build/Release-iphoneos/${FRAMEWORK_NAME}.framework" SIMULATOR_FOLDER="build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework" UNIVERSAL_OUTPUT_FOLDER="${UNIVERSAL_FOLDER}/${FRAMEWORK_NAME}.framework" rm -rf "${UNIVERSAL_FOLDER}" mkdir "${UNIVERSAL_FOLDER}" mkdir "${UNIVERSAL_OUTPUT_FOLDER}" # Step 4: Copy files from device and simulator frameworks to the universal framework folder. cp -R "${DEVICE_FOLDER}" "${UNIVERSAL_OUTPUT_FOLDER}/${FRAMEWORK_NAME}" cp -R "${SIMULATOR_FOLDER}/" "${UNIVERSAL_OUTPUT_FOLDER}/${FRAMEWORK_NAME}/" # Step 5: Create the universal binary file using lipo. lipo -create -output "${UNIVERSAL_OUTPUT_FOLDER}/${FRAMEWORK_NAME}" "${DEVICE_FOLDER}/${FRAMEWORK_NAME}" "${SIMULATOR_FOLDER}/${FRAMEWORK_NAME}"
Replace
"YourFrameworkName"
in the script with the actual name of your framework.Build the aggregate target by selecting it and clicking the "Run" button.
If everything goes smoothly, you will find a universal static library in the "YourFrameworkName-Universal" folder inside your project's directory.
References for Additional Information
Want to dive deeper or need more information? Here are some references for you:
Drobnik's blog post: Although this approach is outdated and may not work directly, it can provide valuable insights.
Stack Overflow question: This question and its answers discuss building a fat static library for armv6, armv7, and i386. While the specifics might have changed since then, it still provides some useful information.
Building a fat static library that works on both simulators and devices using Xcode and SDK 4+ can be a bit challenging, but with the right technique, it's definitely achievable. Start leveraging the power of a single universal static library for all your testing and deployment needs.
We hope this guide helps you overcome this common challenge. If you have any questions or thoughts, feel free to reach out in the comments section below. Happy coding! 🚀📱💻