Porting a command-line executable to Android with an NDK standalone compiler

The previous recipe covered how to port a command-line executable to Android with an NDK build system. This recipe describes how to do it by using the Android NDK toolchain as a standalone compiler.

Getting ready

It is recommended that you read the Porting a library with its existing build system recipe in Chapter 8, Porting and Using Existing Libraries with Android NDK, before continuing.

How to do it...

The following steps describe how to port the fusch program to Android by using the NDK toolchain directly:

  1. Create an Android application named PortingExecutableBuildSystem with native support. Set the package name as cookbook.chapter9.portingexecutablebuildsystem. Refer to the Loading native libraries and registering native methods recipe of Chapter 2, Java Native Interface, if you want more detailed instructions.
  2. Remove the existing content under the jni folder of the project.
  3. Download the source code of the fusch library and the command-line application from http://fugenschnitzer.sourceforge.net/main_en.html. Extract the archive files and put them into the jni/fusch and jni/fusch_lib folders respectively.
  4. Download libpng 1.2.50 from http://sourceforge.net/projects/libpng/files/libpng12/1.2.50/ and extract the files to the jni/libpng-1.2.50 folder. The latest version of libpng won't work because the interface has changed. Replace the config.guess script under libpng-1.2.50 with the one at http://gcc.gnu.org/svn/gcc/branches/cilkplus/config.guess and config.sub with the script at http://gcc.gnu.org/svn/gcc/branches/cilkplus/config.sub.
  5. Add a build_android.sh file under the jni/libpng-1.2.50 folder to build libpng. The file has the following content:
    #!/bin/bash
    NDK=~/Desktop/android/android-ndk-r8b
    SYSROOT=$NDK/platforms/android-8/arch-arm/
    export CFLAGS="-fpic 
       -ffunction-sections 
       -funwind-tables 
       -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ 
       -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ 
      -Wno-psabi 
      -march=armv5te 
       -mtune=xscale 
       -msoft-float 
      -mthumb 
       -Os 
      -DANDROID 
       -fomit-frame-pointer 
       -fno-strict-aliasing 
       -finline-limit=64"
    export LDFLAGS="-lz"
    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 
       --prefix=$(pwd) 
       --exec-prefix=$(pwd) 
      --enable-shared=false 
      --enable-static=true
    make clean
    make 
    make install
  6. Add a build_android.sh file under the jni/fusch_lib folder to build the library libseamcarv. The file content is as follows:
    #!/bin/bash
    NDK=~/Desktop/android/android-ndk-r8b
    SYSROOT=$NDK/platforms/android-8/arch-arm/
    export CFLAGS="-fpic 
       -ffunction-sections 
       -funwind-tables 
       -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ 
       -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ 
      -Wno-psabi 
      -march=armv5te 
       -mtune=xscale 
       -msoft-float 
      -mthumb 
       -Os 
       -fomit-frame-pointer 
       -fno-strict-aliasing 
       -finline-limit=64 
      -std=c99 
      -DANDROID "
    export CC="$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"
    AR="$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-ar"
    SRC_FILES="
      sc_core.c  
      sc_carve.c  
      sc_color.c  
      sc_shift.c 
      sc_mgmnt.c 
      seamcarv.c"
    $CC $SRC_FILES $CFLAGS -c
    $AR cr libseamcarv.a *.o 
  7. Add the third build_android.sh file under the jni/fusch folder to build the fusch executable, which uses the two static libraries built at the two folders libpng-1.2.50 and fusch_lib.
    #!/bin/bash
    NDK=~/Desktop/android/android-ndk-r8b
    SYSROOT=$NDK/platforms/android-8/arch-arm
    CUR_D=$(pwd)
    export CFLAGS="-fpic 
       -ffunction-sections 
       -funwind-tables 
       -D__ARM_ARCH_5__ -D__ARM_ARCH_5T__ 
       -D__ARM_ARCH_5E__ -D__ARM_ARCH_5TE__ 
      -Wno-psabi 
      -march=armv5te 
       -mtune=xscale 
       -msoft-float 
      -mthumb 
       -Os 
       -fomit-frame-pointer 
       -fno-strict-aliasing 
       -finline-limit=64 
      -std=c99 
      -DANDROID 
      -I$CUR_D/../fusch_lib 
      -I$CUR_D/../libpng-1.2.50/include"
    export LDFLAGS="-Wl,--no-undefined -Wl,-z,noexecstack -Wl,-z,relro -Wl,-z,now -lz -lc -lm -lpng -lseamcarv -L$CUR_D/../fusch_lib -L$CUR_D/../libpng-1.2.50/lib"
    export CC="$NDK/toolchains/arm-linux-androideabi-4.4.3/prebuilt/linux-x86/bin/arm-linux-androideabi-gcc --sysroot=$SYSROOT"
    SRC_FILES="fusch.c"
    $CC $SRC_FILES $CFLAGS $LDFLAGS -o fusch
  8. Build the two libraries libpng and libseamcarv and the fusch executable by executing the build_android.sh script in the three subfolders libpng-1.2.50, fusch_lib, and fusch. We shall find libpng.a under the libpng-1.2.50/lib folder, libseamcarv.a under the fusch_lib folder, and the fusch executable under the fusch folder.
  9. We can put the binary file fusch to a rooted Android device or an emulator with the following command:
    $ cd <path to project folder>/PortingExecutableBuildSystem/jni/fusch
    $ adb push fusch /data/data/
  10. Note that we will not be able to copy and execute the binary on a non-rooted Android device because we cannot get the permission.
  11. Start the first command-line shell. We can grant the execution permission to the binary and execute it with the following command:
    $ adb shell
    # cd /data/data
    # chmod 755 fusch
    # ./fusch
  12. This will print out the help message of the program.
  13. Start the second command-line shell. Push the test PNG file cookbook_ch9_test.png (available under the assets folder of the sample project's source code) to the testing device or emulator with the following command:
    $ adb push cookbook_ch9_test.png /data/data/
  14. Get back to the first command-line shell and execute the fusch program again with the following command:
    # ./fusch cookbook_ch9_test.png 1.png v-200
  15. The program will take a while to resize the input image from 800 x 600 to 800 x 400. Once it is finished, we can get the processed image with the following command at the second command-line shell:
    $ adb pull /data/data/1.png .
  16. The following figure shows the original image on the left and the processed image on the right:
    How to do it...

How it works...

The sample project shows how to port a command-line executable to Android by using the NDK toolchain as a standalone compiler.

The steps to port the executable are similar to those in the previous recipe where we used the Android NDK build system. The key here is to pass proper options to the standalone compiler.

Porting libpng

libpng comes with its own build scripts. We can get a list of options to configure the building process with the following command:

$ ./configure –help

The compiler command, compiler flags, and linker flags can be configured with the environment variables CC, CFLAGS, and LDFLAGS respectively. In the build_android.sh script under the libpng-1.2.50 folder, we set these variables to use the NDK compiler to build for the ARM architecture. For a detailed explanation of how to port a library, we can refer to the Porting a library with its existing build system using Android NDK toolchain recipe in Chapter 8, Porting a Library with its Existing Build System.

We will now cover a few compilation options. Since the Android NDK toolchain is based on GCC, we can refer to http://gcc.gnu.org/onlinedocs/gcc/Option-Summary.html for a detailed explanation of each option.

  • -fpic: It generates position-independent code suitable for building a shared library.
  • -ffunction-sections: This option asks the linker to perform optimizations to improve the locality of reference in the code.
  • -funwind-tables: It generates static data for unwinding the call stack.
  • -D__ARM_ARCH_5__, -D__ARM_ARCH_5T, -D__ARM_ARCH_5E__, -D__ARM_ARCH_5TE,-DANDROID defines __ARM_ARCH_5__, __ARM_ARCH_5T, __ARM_ARCH_5E__, __ARM_ARCH_5TE, and ANDROID as macro, with definition equal to 1. For example, -DANDROID is equivalent to -D ANDROID=1.
  • -Wno-psabi: It suppresses the warning message about va_list and so on.
  • -march=armv5te: It specifies the target ARM architecture as ARMv5te.
  • -mtune=xscale: It tunes the performance of the code as it will be running on the xscale processor. Note that xscale is a processor name.
  • -msoft-float: It uses software floating point functions.
  • -mthumb: It generates code using the Thumb instruction set.
  • -Os: It provides optimization for size.
  • -fomit-frame-pointer: It helps avoid saving frame pointers in registers if possible.
  • -fno-strict-aliasing: No strict aliasing rules can be applied. This prevents the compiler from unwanted optimizations.
  • -finline-limit=64: It sets the limit size of functions that can be inlined as 64 pseudo instructions.
  • -std=c99: It accepts c99 standard syntax.

When the build executes successfully, we can find the libpng.a static library under the libpng-1.2.50/lib folder and the header files under the libpng-1.2.50/include folder.

Note

The Android NDK build system essentially figures out the proper compilation options for us and invokes the cross compiler for us. Therefore, we can learn the options to pass to the compiler from the NDK build system output. For example, we can invoke the command ndk-build -B V=1 or ndk-build -B -n in the previous recipe to see how the NDK build system handles the building of libpng, libseamcarv, and fusch, and apply similar options in this recipe.

Porting libseamcarv

libseamcarv comes with a Makefile but no configure file. We can either modify the Makefile or write a build script from scratch. Since the library only contains a few files, we will write the build script directly. There are two steps to be followed:

  1. Compile all source files to object files. This is done by passing the "-c" option at compilation.
  2. Archive the object files into a static library. This step is done with the archiver arm-linux-androideabi-ar from the NDK toolchain.

Tip

As we have explained in Chapter 8, Porting and Using Existing Libraries with Android NDK, a static library is simply an archive of object files, which can be created by the archiver program.

Porting fusch

We need to link to the two libraries we built, namely libpng and libseamcarv. This is done by passing the following options to the linker:

-lpng -lseamcarv -L$CUR_D/../fusch_lib -L$CUR_D/../libpng-1.2.50/lib

This "-L" option adds fusch_lib and libpng-1.2.50/lib to the library's search path and "-l" tells the linker to link to the libpng and libseamcarv libraries. The build script will output a binary file named fusch under the fusch folder.

The fusch program is fairly simple. Therefore, we can use either the Android NDK build system or a standalone compiler to port it. If an application has more dependencies, it can be difficult to describe everything in Android.mk files. Therefore, it is helpful that we can use the NDK toolchain as a standalone compiler and make use of a library's existing build scripts.

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

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