How do i compile a static library (fat) for armv6, armv7 and i386

34,265

Solution 1

Just use libtool to link the two arm6 and arm7 versions together - its what XCode does. However you will have problems if you try to combine these static libraries into a new super-library. If you need to do that then read this.

If you are doing this already, that would be why lipo is complaining that your "armv6" library contains both armv6 and armv7. My post has a fix that will probably be easier for you since you don't use XCode, but basically you use lipo -extract to make sure you have a thin armv6 library and a thin armv7 library before you go any further.

Solution 2

Here is a good solution I found: Static Libs With Support to iOS 5 and Arm64

Edited:

The solution is to build different architectures separated then bind them using lipo, by using command line (or Rakefile).

First build the binary with arm using xcodebuild:

xcodebuild -project 'StaticLibDemo.xcodeproj' -configuration 'Release' -sdk 'iphoneos7.0' clean build ARCHS='armv7 armv7s' IPHONEOS_DEPLOYMENT_TARGET='5.0' TARGET_BUILD_DIR='./build-arm' BUILT_PRODUCTS_DIR='./build-arm'

Note that you must set IPHONEOS_DEPLOYMENT_TARGET='5.0' and ARCHS='armv7 armv7s', it’s recommended to set build and product dirs to make the things more clear, take a look at Build Setting Reference for more details what this flags means.

Next build for arm64:

xcodebuild -project 'StaticLibDemo.xcodeproj' -configuration 'Release' -sdk 'iphoneos7.0' clean build ARCHS='arm64' IPHONEOS_DEPLOYMENT_TARGET='7.0' TARGET_BUILD_DIR='./build-arm64' BUILT_PRODUCTS_DIR='./build-arm64'

Note the difference on ARCHS and IPHONEOS_DEPLOYMENT_TARGET. We also need to build for simulator, in this case we have to change the sdk to iphonesimulator7.0 and build in two steps first for i386:

xcodebuild -project 'StaticLibDemo.xcodeproj' -configuration 'Release' -sdk 'iphonesimulator7.0' clean build ARCHS='i386' IPHONEOS_DEPLOYMENT_TARGET='5.0' TARGET_BUILD_DIR='./build-i386' BUILT_PRODUCTS_DIR='./build-i386'

Now the tricky part! If you just change the ARCHS to x86_86 depending on your Xcode setting you will got an error like: “x86_64 is not a valid arch”. To avoid this just add VALID_ARCHS='x86_64':

xcodebuild -project 'StaticLibDemo.xcodeproj' -configuration 'Release' -sdk 'iphonesimulator7.0' clean build ARCHS='x86_64' VALID_ARCHS='x86_64' IPHONEOS_DEPLOYMENT_TARGET='7.0' TARGET_BUILD_DIR='./build-x86_64' BUILT_PRODUCTS_DIR='./build-x86_64'

Finally we just have to create a fat binary with all the 5 architectures:

lipo -create './build-arm/libStaticLibDemo.a' './build-arm64/libStaticLibDemo.a' './build-i386/libStaticLibDemo.a' './build-x86_64/libStaticLibDemo.a' -output 'libStaticLibDemo.a'

The author created a working example of this, you can get it: https://github.com/diogot/StaticLibDemo


Here is the Link to the post: Static Libs With Support to iOS 5 and Arm64

All credits go to Diogo Tridapalli.

Solution 3

There doesn't seem to be a need to extract from the fat library before rejoining any more (as described in jamie's answer). I'm using the final 4.0 SDK from apple, which appear to create the fat armv6/armv7 libraries by default.

I was previously specifying the architecture for the input lib like so:

$DEVROOT/usr/bin/lipo -arch arm $PROJECT_DIR/buildlib/Release-iphoneos/lib.a -arch i386 $PROJECT_DIR/buildlib/Release-iphonesimulator/lib.a -create -output $PROJECT_DIR/buildlib/lib.a

This fails on the later SDKs, but removing the architecture from the (now fat) arm lib works fine:

$DEVROOT/usr/bin/lipo $PROJECT_DIR/buildlib/Release-iphoneos/lib.a -arch i386 $PROJECT_DIR/buildlib/Release-iphonesimulator/lib.a -create -output $PROJECT_DIR/buildlib/lib.a

Lipo must now be able to detect the architectures in the fat libraries.

Solution 4

Make sure to have your build settings set to Valid Architectures: armv6 armv7 and Architectures: Optimized (armv6 armv7). This should result in a binary optimized for both v6 & v7. If you're not sure it worked out, just set the Architectures: Standard (armv6) and compare the file sizes. Optimized should produce double the size (when I remember rightly).

You also always can use lipo -info on your binary to see all the included architecures.

Running it on a distribution build of my app gives me:

ullrich ~/Code/.../build/Distribution-iphoneos/My.app (streaming)$ lipo -info My
Architectures in the fat file: My are: armv6 armv7 
Share:
34,265
Massimo Cafaro
Author by

Massimo Cafaro

Associate Professor at the University of Salento, Italy. A computer scientist, whose research is centered around Data Mining, Machine Learning, High Performance, Distributed and Grid/Cloud Computing. Especially interested to the design, analysis and implementation of parallel and distributed algorithms. Developing for the unix environment since 1987, for Mac OS since 1988, and for iOS since 2008.

Updated on July 09, 2022

Comments

  • Massimo Cafaro
    Massimo Cafaro almost 2 years

    I know this question has been posed several times, but my goal is slightly different with regard to what I have found searching the web. Specifically, I am already able to build a static library for iPhone, but the final fat file I am able to build only contains arm and i386 architectures (and I am not sure to what arm refers: is v6 or v7?). I am not able to compile specifically for armv6 and armv7 and them merge both architectures using lipo. The lipo tool complains that the same architecture (arm, not armv6 or armv7) is present in both the armv6 and armv7 libraries.

    Can someone explain exactly how to build for armv6 and armv7, and them merge these libraries into a fat file using lipo?

    EDIT: I need to build not using Xcode but compiling directly a traditional unix library.

  • Massimo Cafaro
    Massimo Cafaro about 14 years
    Sorry, I forgot to mention that I need to build this not using Xcode but compiling directly a traditional unix library. I am editing my answer to reflect this fact.
  • Yang
    Yang over 10 years
    Thanks for telling me! @kleopatra