cross-compiling for iPhone dev

Update: Proof-of-concept demo. Also, updated the script for building with the 10.6 SDK.

Update #2: Source code for demo project released.

Update #3: script for use with tesseract v3 posted.

I recently had need to use an open-source library in an iPhone project. Recalling the earlier work necessary in compiling the libraries needed for openFrameworks I started looking for a more generic way to build for iPhone development. Thankfully, LateNiteSoft wrote a great article about using a shell script to cross-compile linux projects, building a Universal Binary with versions for the Simulator and Device.

I configured their provided code snippets to build tesseract-ocr for iPhone, referring to the set-up for freetype and freeimage to fill in some c++ gaps. Anyway, the library seems to have built correctly. I’ll know for sure when I incorporate it into a project, soon.

To use it, copy the script into the project directory, next to the configure script. For a simple project which generates one monolithic library, edit the LIBFILE variable to reflect the location and name of the library. I’ve only used this for static libraries…other work may be necessary to correctly generate dynamic libraries (however, the iPhone SDK prohibits linking to dynamic libraries, so in this case it seems moot). Run ./build_fat.sh to kick off the process. Look for the compiled libraries in the “lnsout” directory. There’s no error checking, so caveat emptor. :)

Cross-compile shell script follows:

#!/bin/sh

# build_fat.sh
#
# Created by Robert Carlsen on 15.07.2009.
# Updated 6.12.2009 to build i386 (simulator) on an x86_64 platform (10.6 SDK)
# build an arm / i386 lib of standard linux project
#
# adopted from:
# http://latenitesoft.blogspot.com/2008/10/iphone-programming-tips-building-unix.html
#
# initially configured for tesseract-ocr

# Set up the target lib file / path
# easiest to just build the package normally first and watch where the files are created.
LIBFILE=ccmain/libtesseract_full

# Select the desired iPhone SDK
export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
export SDKROOT=$DEVROOT/SDKs/iPhoneOS3.0.sdk

# Set up relevant environment variables
export CPPFLAGS="-I$SDKROOT/usr/lib/gcc/arm-apple-darwin9/4.0.1/include/ -I$SDKROOT/usr/include/ -miphoneos-version-min=2.2"
export CFLAGS="$CPPFLAGS -arch armv6 -pipe -no-cpp-precomp -isysroot $SDKROOT"
export CPP="$DEVROOT/usr/bin/cpp $CPPFLAGS"
export CXXFLAGS="$CFLAGS"

# Dynamic library location generated by the Unix package
LIBPATH=$LIBFILE.dylib
LIBNAME=`basename $LIBPATH`

export LDFLAGS="-L$SDKROOT/usr/lib/ -Wl,-dylib_install_name,@executable_path/$LIBNAME"

# Static library that will be generated for ARM
LIBPATH_static=$LIBFILE.a
LIBNAME_static=`basename $LIBPATH_static`

# TODO: add custom flags as necessary for package
./configure CXX=$DEVROOT/usr/bin/arm-apple-darwin9-g++-4.0.1 CC=$DEVROOT/usr/bin/arm-apple-darwin9-gcc-4.0.1 LD=$DEVROOT/usr/bin/ld --host=arm-apple-darwin

make -j4

# Copy the ARM library to a temporary location
mkdir -p lnsout
cp $LIBPATH_static lnsout/$LIBNAME_static.arm

# Do it all again for native cpu
make distclean

# Restore default environment variables
unset CPPFLAGS CFLAGS CPP LDFLAGS CXXFLAGS DEVROOT SDKROOT

export DEVROOT=/Developer
export SDKROOT=$DEVROOT/SDKs/MacOSX10.6.sdk

export CPPFLAGS="-I$SDKROOT/usr/lib/gcc/i686-apple-darwin10/4.0.1/include/ -I$SDKROOT/usr/include/ -mmacosx-version-min=10.5"
export CFLAGS="$CPPFLAGS -pipe -no-cpp-precomp -isysroot $SDKROOT -arch i386"
export CPP="$DEVROOT/usr/bin/cpp $CPPFLAGS"
export CXXFLAGS="$CFLAGS"

 #Overwrite LDFLAGS
# Dynamic linking, relative to executable_path
# Use otool -D to check the install name
export LDFLAGS="-Wl,-dylib_install_name,@executable_path/$LIBNAME"

# TODO: error checking
./configure
make -j4

# Copy the native library to the temporary location
cp $LIBPATH_static lnsout/$LIBNAME_static.i386

# Create fat lib by combining the two versions
/usr/bin/lipo -arch arm lnsout/$LIBNAME_static.arm -arch i386 lnsout/$LIBNAME_static.i386 -create -output lnsout/$LIBNAME_static

unset CPPFLAGS CFLAGS CPP LDFLAGS CPP CXXFLAGS DEVROOT SDKROOT

For reference, here is the original script (written for use with 10.5):

#!/bin/sh

# build_fat.sh
#
# Created by Robert Carlsen on 15.07.2009.
# build an arm / i686 lib of standard linux project
#
# adopted from:
# http://latenitesoft.blogspot.com/2008/10/iphone-programming-tips-building-unix.html
#
# initially configured for tesseract-ocr

# Set up the target lib file / path
# easiest to just build the package normally first and watch where the files are created.
LIBFILE=ccmain/libtesseract_full

# Select the desired iPhone SDK
export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
export SDKROOT=$DEVROOT/SDKs/iPhoneOS2.2.sdk

# Set up relevant environment variables
export CPPFLAGS="-I$SDKROOT/usr/lib/gcc/arm-apple-darwin9/4.0.1/include/ -I$SDKROOT/usr/include/"
export CFLAGS="$CPPFLAGS -arch armv6 -pipe -no-cpp-precomp -isysroot $SDKROOT"
export CPP="$DEVROOT/usr/bin/cpp $CPPFLAGS"
export CXXFLAGS="$CFLAGS"

# Dynamic library location generated by the Unix package
LIBPATH=$LIBFILE.dylib
LIBNAME=`basename $LIBPATH`

export LDFLAGS="-L$SDKROOT/usr/lib/ -Wl,-dylib_install_name,@executable_path/$LIBNAME"

# Static library that will be generated for ARM
LIBPATH_static=$LIBFILE.a
LIBNAME_static=`basename $LIBPATH_static`

# TODO: add custom flags as necessary for package
./configure CXX=$DEVROOT/usr/bin/arm-apple-darwin9-g++-4.0.1 CC=$DEVROOT/usr/bin/arm-apple-darwin9-gcc-4.0.1 LD=$DEVROOT/usr/bin/ld --host=arm-apple-darwin

make -j4

# Copy the ARM library to a temporary location
mkdir -p lnsout
cp $LIBPATH_static lnsout/$LIBNAME_static.arm

# Do it all again for native cpu
make distclean

# Restore default environment variables
unset CPPFLAGS CFLAGS CPP LDFLAGS CXXFLAGS

# Overwrite LDFLAGS
# Dynamic linking, relative to executable_path
# Use otool -D to check the install name
export LDFLAGS="-Wl,-dylib_install_name,@executable_path/$LIBNAME"

# TODO: error checking
./configure
make -j4

# Copy the native library to the temporary location
cp $LIBPATH_static lnsout/$LIBNAME_static.i386

# Create fat lib by combining the two versions
$DEVROOT/usr/bin/lipo -arch arm lnsout/$LIBNAME_static.arm -arch i386 lnsout/$LIBNAME_static.i386 -create -output lnsout/$LIBNAME_static

Posted

in

by

Comments

108 responses to “cross-compiling for iPhone dev”

  1. Nick Avatar

    Thank you for this wonderful project and your continuing support Robert.

    I successfully compiled and ran the project on OSX 10.7 with XCode 4.1 and iOS 4.3.

    In addition to the changes already listed in the discussion, I had to add “thresholder.h” to the project from the tesseract source code and remove “armv7” from “valid architectures” in Build Settings.

    Thanks again!

  2. Florin O. Avatar

    Hi,

    Thanks for your sample project and build script. I didn’t manage to build with it.

    I built separate frameworks with

    export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
    export SDKROOT=/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS4.2.sdk/
    export CC=$DEVROOT/usr/bin/gcc
    export LD=$DEVROOT/usr/bin/ld
    export CPP=$DEVROOT/usr/bin/cpp
    export CXX=$DEVROOT/usr/bin/g++
    export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
    export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer

    ./configure –host=arm-apple-darwin10
    make
    ./configure –host=arm-apple-darwin10 –prefix=/mypath

    And from there I included the frameworks from libtesseract_api.a to libtesseract_wordrec.a. Actually I corrected the path for the frameworks in your sample project.

    Everyhing compiles correctly in XCode but when it launches the app on my iPod Touch I get
    dyld: Library not loaded: /usr/local/lib/libtesseract_api.3.dylib
    Referenced from: /var/mobile/Applications/0049CF1E-D6B3-4B21-B78D-F8E490030088/OCR.app/OCR
    Reason: image not found

    Any idea what should i include?

    Thanks

  3. Robert Avatar

    Check the linking step of the compile. Ensure that you have included the set of static libs in the app’s build target. It looks like the app linked against the dynamic lib on your computer rather than the static lib in the project.

  4. Matt Avatar
    Matt

    Is there an updated script for LLVM? I dug through this script today but unfortunately running Lion & Xcode4.2 won’t let me run the script. Do you know if an updated version for LLVM exists?

  5. Abdulla Avatar
    Abdulla

    Hi Robert,

    I see your steps are “To build the tesseract library, download the source code and compile appropriately for the iPhone (arm processor). Add the library to the XCode project and build.”

    I compiled it with the script provided. But no idea how to “Add the library to the XCode”. This is required for debugging as I am facing some issues.

    I am trying to do this as the PocketOCR git is not having the latest Tesseract. Pls let me know how to debug the Tesseract library. I ve built it with external scripts and I dont know how to make it into an XCode project.

  6. Robert Avatar

    You only need to drag the Tesseract static lib (the .a file) generated by the script into the PocketOCR Xcode project. Ensure that the PocketOCR target is selected in the import menu. You do not need to create an Xcode project for the Tesseract library.

    You’ll also have to include relevant header files from the Tesseract project – which differ based on the version of Tesseract you are using. Finally, you need to include the Tesseract data dir, which contains the language files. These files need to be copied into the app bundle in the appropriate Build Phase of the PocketOCR target.

    Good luck!

  7. guanyu Avatar
    guanyu

    Hi,I try build static lib,but when I built in xcode ,have erro:
    ld: warning: ignoring file /android_developer/Pocket-OCR/libtesseract_wordrec_armv7.a, file was built for archive which is not the architecture being linked (i386)
    Undefined symbols for architecture i386:
    “tesseract::TessBaseAPI::End()”, referenced from:
    -[OCRDisplayViewController dealloc] in OCRDisplayViewController.o
    I know my .a file is wrong,I have been troubled by this problem a long time,can you send me the .a files,thank you very much.guanyu7891@gmail.com,it’s my email

  8. chris Avatar
    chris

    For anyone having issues with the eng.unicharset (or you notice that at SimpleINit the program seems to crash with no message).
    If you have done everything suggested above and it still does not work like me, i fixed it by doing the following:
    In ‘Build Phases’ go to ‘Copy Bundle Resources’ and you may notice that the eng (or whichever lang you added) files are there but listed as
    eng.word-dawg …in AppName/tessdata
    I *think* this means it is taking the files you have in your tessdata folder and just adding them to the main bundle with everything else…so not in a tessdata directory.

    i think this because i fixed it by adding a new entry and in the dialog to choose another file to add i chose ‘Add Other…’ and then added the actual directory ‘tessdata’.
    i chose Create folder references for any added folders (not 100% sure on this it just looked right, sorry i am new to this as well)
    now you will notice that it will add a directory named tessdata and not just the files.
    i think you can delete references to the other files but at this point i want to continue working and not deal with this anymore ;)

Leave a Reply