Porting a library with its existing build system using the Android NDK toolchain

The previous two recipes discussed how to port a library with the Android NDK build system. However, a lot of open source projects have their own build systems and sometimes it is troublesome to list out all sources in the Android.mk file. Fortunately, the Android NDK toolchain can also be used as a standalone cross compiler and we can use the cross compiler in an open source project's existing build system. This recipe will discuss how to port a library with its existing build system.

How to do it...

The following steps describe how to create our sample project, which demonstrates porting the open source libbmp library with its existing build system:

  1. Create an Android application named PortingWithBuildSystem with native support. Set the package name as cookbook.chapter8.portingwithbuildsystem. Please refer to the Loading native libraries and registering native methods recipe of Chapter 2, Java Native Interface, if you want more detailed instructions.
  2. Add a Java file MainActivity.java under the cookbook.chapter8.portingwithbuildsystem package. This Java file simply loads the shared library PortingWithBuildSystem, and calls the native method naCreateABmp.
  3. Download the libbmp library from http://code.google.com/p/libbmp/downloads/list and extract the archive file to the jni folder. This will create a folder libbmp-0.1.3 under the jni folder with the following content:
    How to do it...
  4. Follow step 3 of the Porting a library as shared library module with Android NDK build system recipe to update src/bmpfile.h.
  5. Add a bash shell script file build_android.sh under the libbmp-0.1.3 folder with the following content:
    #!/bin/bash
    NDK=<path to Android ndk folder>/android-ndk-r8b
    SYSROOT=$NDK/platforms/android-8/arch-arm/
    CFLAGS="-mthumb"
    LDFLAGS="-Wl,--fix-cortex-a8"
    export CC="$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"
    ./configure 
       --host=arm-linux-androideabi 
       --disable-shared 
       --prefix=$(pwd) 
       --exec-prefix=$(pwd) 
    make clean
    make 
    make install
  6. Add the execute permission to the build_android.sh file with the following command:
    $ sudo chmod +x build_android.sh
  7. At a command line shell, go to the libbmp-0.1.3 directory, and enter the following command to build the library:
    $ ./build_android.sh

    The build will fail with the following errors:

    How to do it...

    This is because the config.guess and config.sub scripts under the libbmp-0.1.3 folder are out of date (the first line of these two files indicate that the timestamp is 2009-08-19). We will need copies of the scripts with timestamps 2010-05-20 or later. The config.guess script can be found at http://gcc.gnu.org/svn/gcc/branches/cilkplus/config.guess and config.sub can be found at http://gcc.gnu.org/svn/gcc/branches/cilkplus/config.sub.

  8. Try executing the build_android.sh script again. This time it finishes successfully. We should be able to find the libbmp.a static library under the jni/libbmp-0.1.3/lib folder and bmpfile.h under the jni/libbmp-0.1.3/include folder.

How it works...

Many of the existing open source libraries can be built with the shell command "./configure; make; make install". In our sample project, we wrote a build_android.sh script to execute the three steps with the Android NDK cross compiler.

The following are a list of things we should consider when porting a library with the Android NDK cross compiler:

  1. Select the appropriate toolchain: Based on the CPU architecture (ARM, x86 or MIPS) of our targeted devices, you need to choose the corresponding toolchain. The following toolchains are available under the toolchains folder of Android NDK r8d:
    • For ARM-based devices: arm-linux-androideabi-4.4.3, arm-linux-androideabi-4.6, arm-linux-androideabi-4.7, and arm-linux-androideabi-clang3.1
    • For MIPS-based devices: mipsel-linux-android-4.4.3, mipsel-linux-android-4.6, mipsel-linux-android-4.7, and mipsel-linux-android-clang3.1
    • For x86-based devices: x86-4.4.3, x86-4.6, x86-4.7, and x86-clang3.1
  2. Select the sysroot: Based on the Android native API level and CPU architecture we want to target, you will need to choose the appropriate sysroot. The compiler will look for headers and libraries under the sysroot directory at compilation.

    The path to sysroot follows this format:

    $NDK/platforms/android-<level>/arch-<arch>/

    $NDK refers to the Android NDK root folder, <level> refers to the Android API level, and <arch> indicates the CPU architecture. In your build_android.sh script, SYSROOT is defined as follows:

    SYSROOT=$NDK/platforms/android-8/arch-arm/
  3. Specify the cross compiler: The library's existing build system usually has a way for us to specify the cross compiler. It is usually through a configuration option or an environment variable.

    In libbmp, we can enter the "./configure --help" command to see how to set the compiler. The compiler command is specified through the environment variable CC, while the environment variables CFLAGS and LDFLAGS are used to specify the compiler flags and linker flags. In your build_android.sh script, these three environment variables are set as follows:

    export CFLAGS="-mthumb"
    export LDFLAGS="-Wl,--fix-cortex-a8"
    export CC="$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"

    Note

    The "-mthumb" compiler flag indicates that you will use the thumb instruction set rather than the ARM instruction set. The "-wl, --fix-cortex-a8" linker flag is required to route around a CPU bug in some Cortex-A8 implementations.

  4. Specify the output locations for the header files and library binary: You will usually want to place the library under jni/<library folder>/.

    In the case of libbmp, the library binary is installed under the PREFIX/lib folder and the header file is installed under the EPREFIX/include folder. Therefore, we set PREFIX and EPREFIX to jni/libbmp-0.1.3 by passing the following options to configure the script:

    --prefix=$(pwd) 
    --exec-prefix=$(pwd)
  5. Make and install the library: You can simply execute "make; make install;" to build and install the library.

There's more...

In your build_android.sh script, we have disabled shared library. If you remove the line "--disable-shared ", the build will generate both the shared library (libbmp.so) and the static library (libbmp.a) under the jni/libbmp-0.1.3/lib/ folder.

In your sample project, we used the NDK toolchain directly. This method has a serious limitation that you won't be able to use any C++ STL function, and C++ exceptions and RTTI are not supported. Android NDK actually allows you to create a customized toolchain installation with the script $NDK/build/tools/make-standalone-toolchain.sh. Suppose you're targeting Android API level 8; you can use the following command to install the toolchain at the /tmp/my-android-toolchain folder.

$ANDROID_NDK/build/tools/make-standalone-toolchain.sh --platform=android-8 --install-dir=/tmp/my-android-toolchain

You can then use this toolchain by using the following commands:

export PATH=/tmp/my-android-toolchain/bin:$PATH
export CC=arm-linux-androideabi-gcc

Note that the installed toolchain will have a few libraries (libgnustl_shared.so, libstdc++.a, and libsupc++.a) under the /tmp/my-android-toolchain/arm-linux-androideabi/lib/ folder. You can link against these libraries to enable exceptions, RTTI, and STL functions support. We will further discuss exception and STL support in the Porting a library which requires RTTI recipe.

More information about using the Android toolchain as a standalone compiler can be found at Android NDK in docs/STANDALONE-TOOLCHAIN.html.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset