It appears that we can - theoretically - build a single static library that includes both simulator and iPhone and iPad.
However, Apple has no documentation on this that I can find, and Xcode's default templates are NOT configured to do this.
I'm looking for a simple, portable, re-usable technique that can be done inside Xcode.
Some history:
References:
This is a great idea, it's an excellent approach, but it doesn't work: http://www.drobnik.com/touch/2010/04/universal-static-libraries/
Another SO questioner asked how to do it WITHOUT xcode, and with responses that focussed on the arm6 vs arm7 part - but ignored the i386 part: How do i compile a static library (fat) for armv6, armv7 and i386
Great job! I hacked together something similar, but had to run it separately. Having it just be part of the build process makes it so much simpler.
One item of note. I noticed that it doesn't copy over any of the include files that you mark as public. I've adapted what I had in my script to yours and it works fairly well. Paste the following to the end of your script.
if [ -d "${CURRENTCONFIG_DEVICE_DIR}/usr/local/include" ]
then
mkdir -p "${CURRENTCONFIG_UNIVERSAL_DIR}/usr/local/include"
cp "${CURRENTCONFIG_DEVICE_DIR}"/usr/local/include/* "${CURRENTCONFIG_UNIVERSAL_DIR}/usr/local/include"
fi
XCode 12 update:
If you run xcodebuild
without -arch
param, XCode 12 will build simulator library with architecture "arm64 x86_64" as default.
Then run xcrun -sdk iphoneos lipo -create -output
will conflict, because arm64
architecture exist in simulator and also device library.
I fork script from Adam git and fix it.
I needed a fat static lib for JsonKit so created a static lib project in Xcode and then ran this bash script in the project directory. So long as you've configured the xcode project with "Build active configuration only" turned off, you should get all architectures in one lib.
#!/bin/bash
xcodebuild -sdk iphoneos
xcodebuild -sdk iphonesimulator
lipo -create -output libJsonKit.a build/Release-iphoneos/libJsonKit.a build/Release-iphonesimulator/libJsonKit.a
I've made an XCode 4 project template that lets you make a universal framework as easily as making a regular library.
IOS 10 Update:
I had a problem with building the fatlib with iphoneos10.0 because the regular expression in the script only expects 9.x and lower and returns 0.0 for ios 10.0
to fix this just replace
SDK_VERSION=$(echo ${SDK_NAME} | grep -o '.\{3\}$')
with
SDK_VERSION=$(echo ${SDK_NAME} | grep -o '[\\.0-9]\{3,4\}$')
I actually just wrote my own script for this purpose. It doesn't use Xcode. (It's based off a similar script in the Gambit Scheme project.)
Basically, it runs ./configure and make three times (for i386, armv7, and armv7s), and combines each of the resulting libraries into a fat lib.
I've made this into an Xcode 4 template, in the same vein as Karl's static framework template.
I found that building static frameworks (instead of plain static libraries) was causing random crashes with LLVM, due to an apparent linker bug - so, I guess static libraries are still useful!
I have spent many hours trying to build a fat static library that will work on armv7, armv7s, and the simulator. Finally found a solution.
The gist is to build the two libraries (one for the device and then one for the simulator) separately, rename them to distinguish from each other, and then lipo -create them into one library.
lipo -create libPhone.a libSimulator.a -output libUniversal.a
I tried it and it works!
There is a command-line utility xcodebuild
and you can run shell command within xcode.
So, if you don't mind using custom script, this script may help you.
#Configurations.
#This script designed for Mac OS X command-line, so does not use Xcode build variables.
#But you can use it freely if you want.
TARGET=sns
ACTION="clean build"
FILE_NAME=libsns.a
DEVICE=iphoneos3.2
SIMULATOR=iphonesimulator3.2
#Build for all platforms/configurations.
xcodebuild -configuration Debug -target ${TARGET} -sdk ${DEVICE} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Debug -target ${TARGET} -sdk ${SIMULATOR} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Release -target ${TARGET} -sdk ${DEVICE} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
xcodebuild -configuration Release -target ${TARGET} -sdk ${SIMULATOR} ${ACTION} RUN_CLANG_STATIC_ANALYZER=NO
#Merge all platform binaries as a fat binary for each configurations.
DEBUG_DEVICE_DIR=${SYMROOT}/Debug-iphoneos
DEBUG_SIMULATOR_DIR=${SYMROOT}/Debug-iphonesimulator
DEBUG_UNIVERSAL_DIR=${SYMROOT}/Debug-universal
RELEASE_DEVICE_DIR=${SYMROOT}/Release-iphoneos
RELEASE_SIMULATOR_DIR=${SYMROOT}/Release-iphonesimulator
RELEASE_UNIVERSAL_DIR=${SYMROOT}/Release-universal
rm -rf "${DEBUG_UNIVERSAL_DIR}"
rm -rf "${RELEASE_UNIVERSAL_DIR}"
mkdir "${DEBUG_UNIVERSAL_DIR}"
mkdir "${RELEASE_UNIVERSAL_DIR}"
lipo -create -output "${DEBUG_UNIVERSAL_DIR}/${FILE_NAME}" "${DEBUG_DEVICE_DIR}/${FILE_NAME}" "${DEBUG_SIMULATOR_DIR}/${FILE_NAME}"
lipo -create -output "${RELEASE_UNIVERSAL_DIR}/${FILE_NAME}" "${RELEASE_DEVICE_DIR}/${FILE_NAME}" "${RELEASE_SIMULATOR_DIR}/${FILE_NAME}"
Maybe looks inefficient(I'm not good at shell script), but easy to understand. I configured a new target running only this script. The script is designed for command-line but not tested in :)
The core concept is xcodebuild
and lipo
.
I tried many configurations within Xcode UI, but nothing worked. Because this is a kind of batch processing, so command-line design is more suitable, so Apple removed batch build feature from Xcode gradually. So I don't expect they offer UI based batch build feature in future.
Source: Stackoverflow.com