Wednesday, February 22, 2017

Android Studio NDK and CMake build system. Compiling hello-jni using cmake without Android Studio.

This post will be short and to the point. Android Studio and development tools have reached very stable and feature rich state in past few years after Android Studio was released. However it is still hard for many developers trying to use NDK 1st time. Now NDK has become more easier than before!. Thanks to CMake build system.


While building many c/c++ libraries like libpng, webp, fluidsynth, imagemagick, jpegoptim, vorbis, freetype etc i used Android.mk based build system. However while looking at new ndk samples i found CMake based source codes. Lets start learning basics of CMake build system by building hello-jni without using Android Studio.


Firstly ensure all SDK and NDK are installed before proceeding further. Use SDK manager to install platform, platform-tools, build-tools, tools (SDK tools), cmake, ndk and other required packages like Google support libraries. After all is done the directories in the installed location will contain these folders -

licenses
add-ons
lldb
patcher
sources
build-tools
platforms
tools
cmake/3.6.3155560
platform-tools
docs
samples
extras
... etc


In list above we can see cmake version. This means cmake is installed. Before cmake ndk-build command was used to build c/c++ codes present inside jni folder. That ndk-build script required some hard-coded paths like presence of jni folder, manifest file. Using Cmake its more convenient to build native binaries.


Download hello-jni from here. Extract the zip go to hello-jni/app/src/main/cpp/ and start a command shell bash etc in Linux and cmd.exe etc in Windows. Execute cmake from shell. Like this -


/home/bindesh/bin/android-sdk/cmake/3.6.3155560/bin/cmake -DCMAKE_TOOLCHAIN_FILE=/home/bindesh/bin/ndk/build/cmake/android.toolchain.cmake


This command tells cmake to use Android NDK's toolchain to build ARM/X86/MIPS binary. It dumps text like below -


-- Check for working C compiler: /home/bindesh/bin/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/clang
-- Check for working C compiler: /home/bindesh/bin/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/clang -- works
-- Detecting C compiler ABI info
-- Detecting C compiler ABI info - done
-- Detecting C compile features
-- Detecting C compile features - done
-- Check for working CXX compiler: /home/bindesh/bin/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++
-- Check for working CXX compiler: /home/bindesh/bin/ndk/toolchains/llvm/prebuilt/linux-x86_64/bin/clang++ -- works
-- Detecting CXX compiler ABI info
-- Detecting CXX compiler ABI info - done
-- Detecting CXX compile features
-- Detecting CXX compile features - done
-- Configuring done
-- Generating done
-- Build files have been written to: /media/bindesh/WORK/Software/Android/NDK/android-ndk-master/hello-jni/app/src/main/cpp



CMake's job is to identify development tools and configuration. The job of toolchain file it to supply the configuration. Open android.toolchain.cmake file in a text editor to see what it does. CMake creates a Makefile by default. After Makefile is created run make and this will show messages like -


[ 50%] Building C object CMakeFiles/hello-jni.dir/hello-jni.c.o
[100%] Linking C shared library libhello-jni.so
[100%] Built target hello-jni


libhello-jni.so file is created and ready to be used by Android Java project. Cmake can be used to easily change project configurations like adding libraries, custom header paths, external libraries etc.


You can read about cmake in Android NDK docs here https://developer.android.com/ndk/guides/cmake.html#build-command


To learn more how jni binary was built you can read contents of CMakeFiles folder created by cmake. In this folder more details can be found. For example hello-jni/app/src/main/cpp/CMakeFiles/hello-jni.dir/flags.make file contains the CFLAGS, -D, -I, -L flags we pass in a makefile or Android.mk. The good thing is we have to deal with CMakeLists.txt file ONLY. All thing is done from here. Refer to cmake help pages for more information. Use cmake --help to see what more it can do. This article focused on building hello-jni from command like without using Android Studio.



Important links -

https://cmake.org/cmake/help/v3.7/manual/cmake-toolchains.7.html#cross-compiling-for-android

https://developer.android.com/studio/projects/add-native-code.html#create-cmake-script

https://developer.android.com/ndk/guides/cmake.html#build-command

https://cmake.org/Wiki/CMake_Cross_Compiling


This article is very short so i will probably (if i didn't forgot!) write advanced ndk project compilation articles like compiling libpng, libjpeg etc using CMake.