Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cross-compile to static lib (libgcrypt) for use on iOS

I have downloaded latest libgcrypt & libgpg-error libraries from https://www.gnupg.org/download/index.html. I have successfully built (command line) both libraries using ./configure --enable-static --disable-shared; make ; make install on my Mac (Mavericks w/OSX 10.10 & latest Xcode 6.1).

I can link just fine to these new libs from an OS X client app I am building. So far, so good. Just perfect. BUT, I also need to build an iOS client using same exact source code.

Questions:

1) What are the modifications to the command line build sequence for the library I would need to build a universal static library for the (simulator, Mac & iOS)? 2) Or do I need to build separate static libs for iOS? And if so, again, what command line magic would I need to accomplish getting the target architecture right?

like image 202
Chris Heimark Avatar asked Nov 07 '14 23:11

Chris Heimark


2 Answers

Note that it is not possible to build a universal library that will work for both the iOS Simulator and macOS. iOS/Intel and macOS/Intel are not ABI compatible above the C runtime library (Libc). This answer serves to show you how to crosscompile autoconf based projects for iOS targets, and you can easily lipo the resulting static archives together.

You will want to do something like this:

#!/bin/bash -e -x

OPT_FLAGS="-Os -g3"
MAKE_JOBS=16

dobuild() {
    export CC="$(xcrun -find -sdk ${SDK} cc)"
    export CXX="$(xcrun -find -sdk ${SDK} cxx)"
    export CPP="$(xcrun -find -sdk ${SDK} cpp)"
    export CFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
    export CXXFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
    export LDFLAGS="${HOST_FLAGS}"

    ./configure --host=${CHOST} --prefix=${PREFIX} --enable-static --disable-shared

    make clean
    make -j${MAKE_JOBS}
    make install
}

SDK="iphoneos"
ARCH_FLAGS="-arch armv7"
HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
CHOST="arm-apple-darwin"
PREFIX="${HOME}/DEVICE_ARM"
dobuild

SDK="iphoneos"
ARCH_FLAGS="-arch arm64"
HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
CHOST="arm-apple-darwin"
PREFIX="${HOME}/DEVICE_ARM64"
dobuild

SDK="iphonesimulator"
ARCH_FLAGS="-arch i386"
HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
CHOST="i386-apple-darwin"
PREFIX="${HOME}/SIM_i386"
dobuild

SDK="iphonesimulator"
ARCH_FLAGS="-arch x86_64"
HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=8.0 -isysroot $(xcrun -sdk ${SDK} --show-sdk-path)"
CHOST="x86_64-apple-darwin"
PREFIX="${HOME}/SIM_x86_64"
dobuild

I just threw that script together and verified it works (with the addition of --disable-libpng and skipping tests) for pixman. You will probably need to customize it for libgcrypt, but it serves to show the general pattern for building autoconf/automake/glibtool based projects for iOS.

After building, you'll have content in ~/{DEVICE_ARM{,64},SIM_{i386,x86_64}} and you can either lipo the static libraries together or just use all of them in your project (the linker will emit warnings about missing slices for the "other" archives which you can ignore).

lipo -create -output lib.a DEVICE_ARM/lib/lib.a DEVICE_ARM64/lib/lib.a SIM_i386/lib/lib.a SIM_x86_64/lib/lib.a
like image 61
Jeremy Huddleston Sequoia Avatar answered Sep 27 '22 20:09

Jeremy Huddleston Sequoia


Jeremy gave a good answer, but I'd like to add a few things and offer my two cents.

The updated script

#!/bin/bash

OPT_FLAGS="-O3 -g3"
MAKE_JOBS=8

dobuild() {
    export CC
    CC=$(xcrun --find --sdk "${SDK}" gcc)
    export CXX
    CXX=$(xcrun --find --sdk "${SDK}" g++)
    export CPP
    CPP=$(xcrun --find --sdk "${SDK}" cpp)
    export CFLAGS
    CFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
    export CXXFLAGS
    CXXFLAGS="${HOST_FLAGS} ${OPT_FLAGS}"
    export LDFLAGS
    LDFLAGS="${HOST_FLAGS}"

    ./configure --host="${CHOST}" --prefix="${PREFIX}" --enable-static

    make clean
    make -j"${MAKE_JOBS}"
    make install
}

SDK="iphoneos"
ARCH_FLAGS="-arch armv7 -arch armv7s -arch arm64"
HOST_FLAGS="${ARCH_FLAGS} -miphoneos-version-min=8.0 -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)"
CHOST="arm-apple-darwin"
PREFIX="${HOME}/DEVICE_ARM"
dobuild

SDK="iphonesimulator"
ARCH_FLAGS="-arch x86_64"
HOST_FLAGS="${ARCH_FLAGS} -mios-simulator-version-min=8.0 -isysroot $(xcrun --sdk ${SDK} --show-sdk-path)"
CHOST="x86_64-apple-darwin"
PREFIX="${HOME}/SIM_x86"
dobuild

The iOS toolchain is separated by SDKs and iphonesimulator has a separate SDK as does macos, tvos, and of course iphoneos. For each SDK you'll need one compile. You can lipo together iphonesimulator and iphoneos output into a single library since they contain different architectures, but really they are not compiled with the same SDK. I recommend against the super binary of mixed SDKs.

Why am I doing this?

If you're compiling a library and need this, it is because the library is using autoconf, or in the case of Boost and OpenSSL other custom build systems. The keys to compiling for the SDKs are the correct clang, -sysroot, -miphoneos-ver-min, and -arch flags. If you get the -arch or -sysroot flags wrong you'll see #error Unsupported architecture errors.

Remove the --disable-shared flag

I like leaving the generation of the shared libs even if I intend to use the static library. This generally means you'll compile with Position Independent Code (-fPIC) so if you decide to include this library in a shared library, you're good to go. Also, unlike a static library which isn't linked, but archived, the linking of the shared library often exposes missing objects.

Multiple architectures on the line

You can pass multiple -arch flags on the line and you'll get FAT binaries. This save you some hassle and time during compilation.

$ lipo -info libwhatever.a 
Architectures in the fat file: libwhatver.a are: i386 x86_64 

Remove architectures

In all honesty, do you need i386 support? If you're not targeting that device then don't include the architecture. You only need i386 if your host system runs an OS predating Lion.

like image 35
Cameron Lowell Palmer Avatar answered Sep 27 '22 20:09

Cameron Lowell Palmer