How to build ICU so I can use it in an iPhone app?

前端 未结 4 387
没有蜡笔的小新
没有蜡笔的小新 2020-12-02 19:22

How do I configure and build ICU so I can link it to my iPhone app?

I\'m maintaining an iPhone app that uses a SQLite database. Now I have to compil

相关标签:
4条回答
  • 2020-12-02 19:53

    If you have the source, do you really need to link the library? Just add the sources to your XCode project and you should be good to go...

    If you really want to build a library, I'd suggest you to create an XCode project for the library with the iPhone as your target, and link that library to your code, as your library is built to run in your MacOS computer (according to your error logs).

    EDIT

    To build it from the command line and assuming you're not using iOS 5 (because of your version of XCode), I've borrowed and adapted this set of instructions to properly setup the flags to configure and build correctly the binaries to your platform from here:

    export IOS_BASE_SDK=4.2
    export IOS_DEPLOY_TGT=4.2
    export DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
    export SDKROOT=$DEVROOT/SDKs/iPhoneOS$IOS_BASE_SDK.sdk
    export CFLAGS="-arch armv7 -pipe -no-cpp-precomp -isysroot $SDKROOT -miphoneos-version-min=$IOS_DEPLOY_TGT -I$SDKROOT/usr/include/"
    
    export CPP=$DEVROOT/usr/bin/cpp-4.2
    export CXX=$DEVROOT/usr/bin/g++-4.2
    export CXXCPP=$DEVROOT/usr/bin/cpp-4.2
    export CC=$DEVROOT/usr/bin/gcc-4.2
    export LD=$DEVROOT/usr/bin/ld
    export AR=$DEVROOT/usr/bin/ar
    export AS=$DEVROOT/usr/bin/as
    export NM=$DEVROOT/usr/bin/nm
    export RANLIB=$DEVROOT/usr/bin/ranlib
    export LDFLAGS="-L$SDKROOT/usr/lib/"
    
    export CPPFLAGS=$CFLAGS
    export CXXFLAGS=$CFLAGS
    
    ./configure --target=arm-apple-darwin --enable-static --disable-shared
    

    Please, properly set the IOS version on the first two instructions to the correct value of your environment.

    If you're going to use iOS 5 SDK, you'll need to change the name of the compiler binaries since they've changed.

    0 讨论(0)
  • 2020-12-02 20:01

    I used iOS SDK version 6.1, with clang and building against the c++11 standard library. I found that setting environment variables such as CXXFLAGS had no affect, and trying to pass them to 'configure' on the command line seemed to break it entirely. I ended up making a clang, clang++, and ld scripts that would allow me to pass in additional parameters. For example, my clang script:

    #This script circumvents gnumake getting rid of our flags. Use the environment variable $MORE_CFLAGS
    /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/clang "$@" $MORE_CFLAGS
    

    The others are identical, but substitute clang++ and ld where appropriate, and use MORE_CXXFLAGS and MORE_LDFLAGS respectively.

    Lastly, I made this script, which does a host build, a simulator build, and an iOS build. Note that the simulator build includes debug info, and the iOS version is -O2 optimized. It then lipos the libs (makes a universal binary) and copies them, along with the include folder, to a target specified by INSTALL_PATH. Lines 3-5 are used to configure the script. Place all 4 of these scripts in the same folder and execute this last one from the command line:

    #unpack the ICU source and point $ICU_PATH at it
    
    ICU_PATH="$HOME/Downloads/icu"
    ICU_FLAGS="-I$ICU_PATH/source/common/ -I$ICU_PATH/source/tools/tzcode/ "
    INSTALL_PATH="$HOME/Documents/git/gamelib/Graphics/Text/icu/51.1"
    SDKROOT=`xcrun --sdk iphoneos --show-sdk-path`
    SIMULATOR_SDKROOT=`xcrun --sdk iphonesimulator --show-sdk-path`
    
    
    SCRIPT_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
    SAVEPATH=$PATH
    
    cd $ICU_PATH
    mkdir host_build
    cd host_build
    ../source/configure
    gnumake
    
    PATH=$SCRIPT_DIR:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneSimulator.platform/Developer/usr/bin:$SAVEPATH
    cd $ICU_PATH
    mkdir iPhoneSimulator_build
    cd iPhoneSimulator_build
    #PATH points to the folder that contains this script, which should also contain scripts titled clang, clang++, and ld
    #those scripts call the actual clang, clang++, and ld, appending MORE_CFLAGS, MORE_CXXFLAGS, and MORE_LDFLAGS respectively
    export MORE_CFLAGS="-arch i386 -pipe -std=c99 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SIMULATOR_SDKROOT $ICU_FLAGS"
    export MORE_CXXFLAGS="-arch i386 -pipe -std=c++11 -stdlib=libc++ -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SIMULATOR_SDKROOT $ICU_FLAGS"
    export MORE_LDFLAGS="-arch i386 -isysroot $SIMULATOR_SDKROOT -miphoneos-version-min=5.0"
    $ICU_PATH/source/configure --enable-debug --disable-release --with-cross-build="$ICU_PATH/host_build" --prefix="$ICU_PATH/iPhoneSimulator_build/install" --enable-static=yes --enable-shared=no
    gnumake clean
    gnumake VERBOSE=1 install
    
    PATH=$SCRIPT_DIR:/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin:/Applications/Xcode.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/usr/bin:$SAVEPATH
    cd $ICU_PATH
    mkdir iPhoneOS_build
    cd iPhoneOS_build
    #PATH points to the folder that contains this script, which should also contain scripts titled clang, clang++, and ld
    #those scripts call the actual clang, clang++, and ld, appending MORE_CFLAGS, MORE_CXXFLAGS, and MORE_LDFLAGS respectively
    export MORE_CFLAGS="-arch armv7 -pipe -std=c99 -O2 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SDKROOT $ICU_FLAGS"
    export MORE_CXXFLAGS="-arch armv7 -pipe -std=c++11 -stdlib=libc++ -O2 -fmessage-length=0 -fvisibility=hidden -miphoneos-version-min=5.0 -isysroot $SDKROOT $ICU_FLAGS"
    export MORE_LDFLAGS="-arch armv7 -isysroot $SDKROOT -miphoneos-version-min=5.0"
    $ICU_PATH/source/configure --host=arm-apple-darwin --with-cross-build="$ICU_PATH/host_build" --prefix="$ICU_PATH/iPhoneOS_build/install" --enable-static=yes --enable-shared=no
    gnumake clean
    gnumake VERBOSE=1 install
    
    PATH=$SAVEPATH
    
    mkdir "$INSTALL_PATH/lib"
    for file in $ICU_PATH/iPhoneOS_build/install/lib/*.a; do
        BASENAME="${file##*/}"
        lipo "$ICU_PATH/iPhoneOS_build/install/lib/$BASENAME" "$ICU_PATH/iPhoneSimulator_build/install/lib/$BASENAME" -create -output "$INSTALL_PATH/lib/$BASENAME"
    done
    
    rm -r "$INSTALL_PATH/include"
    cp -r "$ICU_PATH/iPhoneOS_build/install/include" "$INSTALL_PATH/include"
    
    0 讨论(0)
  • 2020-12-02 20:09

    re: sync synchronize: someone may be lying about the atomics or there's some gcc library needed. try #define U_HAVE_GCC_ATOMICS 0 at the top of icu/source/common/unicode/uconfig.h ( note: ARM seems to have a weak memory model, so this change will result in more locking/unlocking than would otherwise be necessary, but still safe. )

    0 讨论(0)
  • 2020-12-02 20:12

    EDIT:

    I can confirm that if you do, as Steven R. Loomis suggests:

    1. set U_HAVE_GCC_ATOMICS to 0 in icu/source/common/unicode/platform.h

    2. make distclean

    3. sh cross_configure.sh (using my script, i.e., if you are using it)

    the problem should be solved. Indeed, without doing this, the built libraries contain the offending undefined symbol:

    sergio@sfogliatella$ nm -a ./lib/libicuuc.a | grep __sync_
         U ___sync_synchronize
         U ___sync_val_compare_and_swap_4
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
         U ___sync_synchronize
    

    After following the above suggestion, this is the result for the same command:

    sergio@sfogliatella$ nm -a ./lib/libicuuc.a | grep __sync_
    nm: no name list
    nm: no name list
    

    So, definitely, the offending symbol is not present in the binaries.

    END EDIT.

    Cross-compiling libicu for iOS requires two separate steps:

    1. compiling libicu for your host (MacOS) in a build directory;

    2. cross-compiling libicu for iOS by also specifying the cross-compile directory.

    The reason why step 1 is necessary is that libicu will bootstrap itself a bit, i.e., it will compile some intermediate tools, which will be then used in the rest of the build process; those tools need to be ran on the host platform, so they are to be available.

    Well, all in all, you can follow the steps (1. compile for the host):

    $ cd $icu
    $ mkdir hostbuild
    $ cd hostbuild
    $ ../icu/source/configure <configure settings you need>
    $ gnumake
    

    Once this is done, it's time to cross-compile (2. compile for iOS):

    $ cd $icu  (or cd ../ from the previous directory)
    $ mkdir iosbuild
    $ cd iosbuild
    $ sh ../cross_configure_icu.sh
    $ gnumake
    

    Where cross_configure_icu.sh is a shell script similar to those proposed by Sergio Moura above, but customized for libicu and using the more advanced llvm compiler:

    DEVROOT=/Developer/Platforms/iPhoneOS.platform/Developer
    SDKROOT=$DEVROOT/SDKs/iPhoneOS4.3.sdk
    SYSROOT=$SDKROOT
    
    ICU_PATH=<ABSOLUTE_PATH_TO_YOUR_ICU_DIR>
    ICU_FLAGS="-I$ICU_PATH/source/common/ -I$ICU_MYSRC/source/tools/tzcode/ "
    
    export CXXPP=
    export CXXPPFLAGS=
    export CPPFLAGS="-I$SDKROOT/usr/lib/gcc/arm-apple-darwin10/4.2.1/include/ -I$SDKROOT/usr/llvm-gcc-4.2/lib/gcc/arm-apple-darwin10/4.2.1/include/ -I$SDKROOT/usr/include/ -I$SDKROOT/usr/include/c++/4.2.1/armv7-apple-darwin10/ -I./include/ -miphoneos-version-min=2.2 $ICU_FLAGS"
    
    export CFLAGS="$CPPFLAGS -pipe -no-cpp-precomp -isysroot $SDKROOT"
    export CPP="$DEVROOT/usr/bin/cpp $CPPFLAGS"
    export CXXFLAGS="$CFLAGS" 
    export CC="$DEVROOT/usr/llvm-gcc-4.2/bin/arm-apple-darwin10-llvm-gcc-4.2"
    export CXX="$DEVROOT/usr/llvm-gcc-4.2/bin/arm-apple-darwin10-llvm-g++-4.2"
    export LDFLAGS="-L$SDKROOT/usr/lib/ -isysroot $SDKROOT -Wl,-dead_strip -miphoneos-version-min=2.0"
    
    sh $ICU_PATH/source/configure --host=arm-apple-darwin --enable-static --disable-shared -with-cross-build=$ICU_PATH/hostbuild
    

    In the above script (source), ICU_PATH is an absolute path because libicu configure so requires for the with-cross-build option. Again, check your values for the SDK and compilers, but this should be ok for 4.3.

    Finally, you should take into account that Apple has (half) rejected at least one app that was linked against libicu, because it uses reserved APIs. Have a look at this S.O. topic.

    EDIT:

    happy the hear that you could compile!

    now, to the linking problem.

    first of all, please check that the libicu libraries are in the correct format:

    sergio@sfogliatella$ lipo -info ./lib/libicuuc.a 
    

    output should be (for any of the libs):

    input file ./lib/libicuuc.a is not a fat file
    Non-fat file: ./lib/libicuuc.a is architecture: arm
    

    If this is fine, then next question: are you building for the simulator or for the device? simulator needs i386 libraries, device arm libraries... from the error message you show:

    ld: warning: ... file was built for unsupported file format which is not the architecture being linked (i386)

    it seems to me that you are building against the simulator... for that you will need "normal" macos x libs...

    0 讨论(0)
提交回复
热议问题