Porting a command-line executable to Android with an NDK build system

This recipe discusses how to port a command-line executable to Android with an NDK build system. We will use the open source Fugenschnitzer program (fusch) as an example.

Getting ready

You should read the Porting a library as a static library with an Android NDK build system recipe in Chapter 8, Porting and Using Existing Libraries with Android NDK, before going through this one.

How to do it...

The following steps describe how to port the fusch program to Android with an NDK build system:

  1. Create an Android application named PortingExecutable with native support. Set the package name as cookbook.chapter9.portingexecutable. Refer to the Loading native libraries and registering native methods recipe in 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 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 is different.
  5. Add an Android.mk file under the jni/libpng-1.2.50 folder to build libpng as a static library module. The file has the following content:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_CFLAGS := 
    LOCAL_MODULE    := libpng
    LOCAL_SRC_FILES :=
      png.c 
      pngerror.c 
      pngget.c 
      pngmem.c 
      pngpread.c 
      pngread.c 
      pngrio.c 
      pngrtran.c 
      pngrutil.c 
      pngset.c 
      pngtrans.c 
      pngwio.c 
      pngwrite.c 
      pngwtran.c 
      pngwutil.c 
    LOCAL_LDLIBS := -lz
    LOCAL_EXPORT_LDLIBS := -lz
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
    include $(BUILD_STATIC_LIBRARY)
  6. Add an Android.mk file under the jni/fusch_lib folder to build libseamcarv as a static library module. The file content is as follows:
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE    := libseamcarv
    LOCAL_SRC_FILES :=
      sc_core.c  
      sc_carve.c  
      sc_color.c  
      sc_shift.c 
      sc_mgmnt.c 
      seamcarv.c
    LOCAL_CFLAGS := -std=c99 
    LOCAL_EXPORT_C_INCLUDES := $(LOCAL_PATH)
    include $(BUILD_STATIC_LIBRARY)
  7. Add the third Android.mk file under the jni/fusch folder to build the fusch executable, which uses the two static libraries built in the two folders libpng-1.2.50 and fusch_lib.
    LOCAL_PATH := $(call my-dir)
    include $(CLEAR_VARS)
    LOCAL_MODULE    := fusch
    LOCAL_SRC_FILES := fusch.c
    LOCAL_CFLAGS := -std=c99
    LOCAL_STATIC_LIBRARIES := libpng libseamcarv
    include $(BUILD_EXECUTABLE)
  8. Add the fourth Android.mk file under the jni folder to include the Android.mk files under its subfolders.
    LOCAL_PATH := $(call my-dir)
    include $(call all-subdir-makefiles)
  9. Build the application and you will see a binary file, fusch, under the libs/armeabi folder. We can put this binary into a rooted Android device or an emulator with the following command:
    $ 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 to execute.
  11. Start the first command line on the console. 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

    This will print out the help message of the program.

  12. 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/
  13. 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 h-200
  14. The program will take a while to resize the input image from 800 x 600 to 600 x 600. 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 .
  15. The following screenshot shows the original image on the left and the processed image on the right:
    How to do it...

How it works...

The sample project demonstrates how to port the fusch program as a command-line executable to Android. We describe the sources to the Android NDK build system in the Android.mk file and the NDK build system handles the rest.

The steps to port a command-line executable are as follows:

  1. Figure out the library dependencies. In our sample program, fusch depends on libseamcarv (in the fusch_lib folder) and libpng, and libpng subsequently depends on zlib.
  2. If a library is not available on the Android system, port it as a static library module. This is the case for libseamcarv and libpng in our sample application. But as zlib is available on Android, we simply need to link to it.
  3. Port the executable as a separate module and link it to the library modules.

Understanding the Android.mk files

We have covered most of the Android.mk variables and macros in Chapter 8, Porting and Using Existing Libraries with Android NDK. We will introduce two more predefined variables here. You can also refer to the Android NDK file docs/ANDROID-MK.html for information on more macros and variables.

  • LOCAL_CFLAGS: A module description variable. This allows us to specify additional compiler options or macro definitions for building C and C++ source files. Another variable that serves a similar purpose is LOCAL_CPPFLAGS, but for C++ source files only. In our sample project, we passed -std=c99 to the compiler when building libseamcarv and fusch. This asks the compiler to accept ISO C99 C language standard syntax. Failing to specify the flag will result in compilation errors at the time of building.

    Note

    It is also possible to specify the include paths with LOCAL_CFLAGS += I<include path>. However, it is recommended that we use LOCAL_C_INCLUDES because the LOCAL_C_INCLUDES path will also be used for ndk-gdb native debugging.

  • BUILD_EXECUTABLE: A GNU make variable. It points to a build script that collects all information about the executable that we want to build and determines how to build it. It is similar to BUILD_SHARED_LIBRARY and BUILD_STATIC_LIBRARY except that it is for executables. It is used when building fusch in our sample project.
    include $(BUILD_EXECUTABLE)

With this explanation and the knowledge we acquired in Chapter 8, Porting and Using Existing Libraries with Android NDK, it is now fairly easy to understand the four Android.mk files used in our sample application. We ported libpng and libseamcarv as two static library modules. We export the dependent libraries (with LOCAL_EXPORT_LDLIBS) and header files (with LOCAL_EXPORT_C_INCLUDES), so they are automatically included when using the module. When porting libpng, we also link to the zlib library (with LOCAL_LDLIBS) available on the Android system. Finally, we port the fusch program by referring to the two library modules (with LOCAL_STATIC_LIBRARIES).

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

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