Compiling External C++ Library for Use with iOS Project

Compiling external C++ library for use with iOS project

So I've used many a 3rd party C++ library in my iOS projects. There are different strategies people use for this. As some have already cited, you can include the code within the project directly, build the static lib with Xcode, or build it command line. In the case of cross platform C++ libs which use the GNU configure and build system, I prefer command line. You only need to build it once and you only have to revisit it if you need to update the version or add a new architecture slice.

The generalized approach you want is:

  • Figure out the right configure arguments to use to build each slice. Typically, you only need to focus on getting one of the arm as well as i386 working. The rest are easy one you have this done. In some cases, you actually need to modify the configure file to add the host or make some other adjustments.

  • Once you can build all slices, you want to run lipo to build a fat binary.

The best way then to deal with this is create a build script which will do all the work for you. This way, it's easier to redo. More importantly, you can reuse the script or permute it to build other external libs.

There are many ways you can build the script. Here is one. I happen to have several variations of this type of script. This script was used to build cURL. It more or less worked for presage with very little mod (ie. change curl to presage). Note I didn't test it in Xcode (ie. linking it and running it). I did find that I had to disable sqlite, else it built tool items which don't build right. If you need it, you can figure that part out.

There are many ways you could make it more slick. For example using an array to store all the architectures. This is just brute force.

The key points of the script are:

  1. Getting the latest SDK
  2. Building each slice
  3. Then running lipo

Note that it should work out of the box, however, YMMV. Be prepared to have to debug it if necessary. For example, I haven't confirmed the host type, but generally that is what I've always used. You want to put this at the directory for presage (same directory where configure). When it is done, all architectures are in the output directory. The universal lib is in the presage directory.

Also remember it is your responsibility to properly link in the universal lib as well as have the header files search path defined properly.

#!/bin/bash

PLATFORMPATH="/Applications/Xcode.app/Contents/Developer/Platforms"
TOOLSPATH="/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin"
export IPHONEOS_DEPLOYMENT_TARGET="8.0"
pwd=`pwd`

findLatestSDKVersion()
{
sdks=`ls $PLATFORMPATH/$1.platform/Developer/SDKs`
arr=()
for sdk in $sdks
do
arr[${#arr[@]}]=$sdk
done

# Last item will be the current SDK, since it is alpha ordered
count=${#arr[@]}
if [ $count -gt 0 ]; then
sdk=${arr[$count-1]:${#1}}
num=`expr ${#sdk}-4`
SDKVERSION=${sdk:0:$num}
else
SDKVERSION="8.0"
fi
}

buildit()
{
target=$1
hosttarget=$1
platform=$2

if [[ $hosttarget == "x86_64" ]]; then
hostarget="i386"
elif [[ $hosttarget == "arm64" ]]; then
hosttarget="arm"
fi

export CC="$(xcrun -sdk iphoneos -find clang)"
export CPP="$CC -E"
export CFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION"
export AR=$(xcrun -sdk iphoneos -find ar)
export RANLIB=$(xcrun -sdk iphoneos -find ranlib)
export CPPFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk -miphoneos-version-min=$SDKVERSION"
export LDFLAGS="-arch ${target} -isysroot $PLATFORMPATH/$platform.platform/Developer/SDKs/$platform$SDKVERSION.sdk"

mkdir -p $pwd/output/$target

./configure --prefix="$pwd/output/$target" --disable-shared --disable-sqlite --host=$hosttarget-apple-darwin

make clean
make
make install
}

findLatestSDKVersion iPhoneOS

buildit armv7 iPhoneOS
buildit armv7s iPhoneOS
buildit arm64 iPhoneOS
buildit i386 iPhoneSimulator
buildit x86_64 iPhoneSimulator

LIPO=$(xcrun -sdk iphoneos -find lipo)
$LIPO -create $pwd/output/armv7/lib/libpresage.a $pwd/output/armv7s/lib/libpresage.a $pwd/output/arm64/lib/libpresage.a $pwd/output/x86_64/lib/libpresage.a $pwd/output/i386/lib/libpresage.a -output libpresage.a

How to build and use C library in iOS project?

Xcode can compile a C code without additional settings. Just add your C files to project and select proper target.

To use C code at Swift you should create bridging header.

Here is an example how to use C and Swift in same project from a scratch. You can do the same with your exist C code.

  1. Create a new iOS project.
  2. Add a C file by click command+N. Select C file with header.
    C file
  3. Xcode should suggest to add bridging header and create it automatically. If it doesn't happen you can do it manually by create header file and add it name to build settings of the project.
    Bridging header
    Build settings
  4. Add some function at C file. For example:

     // example.h
    #include <stdio.h>
    int exampleMax(int num1, int num2);

    // example.c
    #include "example.h"

    int exampleMax(int num1, int num2)
    {
    int result;
    if (num1 > num2)
    result = num1;
    else
    result = num2;
    return result;
    }
  5. Add C header to bridging file:

     // ModuleName-Bridging-Header.h
    #import "example.h"
  6. Now you can use C code at Swift files:

     import UIKit

    class ViewController: UIViewController {
    override func viewDidLoad() {
    super.viewDidLoad()
    let number1 = Int32(1)
    let number2 = Int32(5)
    let result = exampleMax(number1, number2)
    print("min = \(result)")
    }
    }

Auto completion should see your C header:

Auto completion

Instead of bridging header you can use modulemap file. It's more flexible and convenient but a little harder to setup.

Compile C library as iPhone framework?

I combined techniques I found here and here into my open source library here (NOTE - I have since removed the relevant scripts from this project. I have updated the link to point to the last revision that included these techniques.). Think that's basically the solution you're looking for.

Basically, it has a target that will build a fat static library (lipo builds for arm6, arm7 and i386). It has another target that takes that library and builds it into a framework.

There's no reason you can't use the same techniques for a C project. In fact I've started work on porting C the VTD XML parser to an Objective C framework using the same techniques.

Link External Library in Xcode C++ Project

If I understand correctly what you are asking, you simply want to "set" the file chooser dialog at the right place, right?

If so, you just have to press Cmd + Alt + G once you are in the file chooser dialog, after clicking on "Add Other..." in the "Link Binary with Libraries" menu. A "Go to the folder:" dialog comes up, and there you can type the fullpath to the file or the folder you are looking for.

Hope that helped!

adding an external library to a project in Xcode 4.3

By default, Xcode searches for headers recursively in the project's own directory. If you're using a static library, you'll need to use the lib's header files which likely reside somewhere else. There are 2 settings in an Xcode project that allow you specify additional paths to search during compilation:

User Header Search Paths

#import "SomeHeader.h"

Header Search Paths

#import <SomeHeader.h>

Depending on which style you intend to use, pick the appropriate setting, and supply the path to the header files you wish to use:

Sample Image

The paths can be recursive, relative to the project (using $(SRCROOT)/), or absolute. You could also use the derrived data directory if you have Xcode set up correctly.



Related Topics



Leave a reply



Submit