android-cmake

CMake is great, and so is Android. This is a collection of CMake scripts that may be useful to the Android NDK community. It is based on experience from porting OpenCV library to Android: http://opencv.org/platforms/android.html

Main goal is to share these scripts so that devs that use CMake as their build system may easily compile native code for Android.

TL;DR

cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake \
      -DANDROID_NDK=<ndk_path>                       \
      -DCMAKE_BUILD_TYPE=Release                     \
      -DANDROID_ABI="armeabi-v7a with NEON"          \
      <source_path>
cmake --build .

One-liner:

cmake -DCMAKE_TOOLCHAIN_FILE=android.toolchain.cmake -DANDROID_NDK=<ndk_path> -DCMAKE_BUILD_TYPE=Release -DANDROID_ABI="armeabi-v7a with NEON" <source_path> && cmake --build .

android-cmake will search for your NDK install in the following order:

  1. Value of ANDROID_NDK CMake variable;
  2. Value of ANDROID_NDK environment variable;
  3. Search under paths from ANDROID_NDK_SEARCH_PATHS CMake variable;
  4. Search platform specific locations (home folder, Windows “Program Files”, etc).

So if you have installed the NDK as ~/android-ndk-r10d then android-cmake will locate it automatically.

Getting started

To build a cmake-based C/C++ project for Android you need:

The android-cmake is also capable to build with NDK from AOSP or Linaro Android source tree, but you may be required to manually specify path to libm binary to link with.

Difference from traditional CMake

Folowing the ndk-build the android-cmake supports only two build targets:

So don’t even try other targets that can be found in CMake documentation and don’t forget to explicitly specify Release or Debug because CMake builds without a build configuration by default.

Difference from ndk-build

The following features of ndk-build are not supported by the android-cmake yet:

Basic options

Similarly to the NDK build system android-cmake allows to select between several compiler toolchains and target platforms. Most of the options can be set either as cmake arguments: -D<NAME>=<VALUE> or as environment variables:

Advanced android-cmake options

Normally android-cmake users are not supposed to touch these variables but they might be useful to workaround some build issues:

Fine-tuning CMakeLists.txt for android-cmake

Recognizing Android build

android-cmake defines ANDROID CMake variable which can be used to add Android-specific stuff:

if (ANDROID)
    message(STATUS "Hello from Android build!")
endif()

The recommended way to identify ARM/MIPS/x86 architecture is examining CMAKE_SYSTEM_PROCESSOR which is set to the appropriate value:

Other variables that are set by android-cmake and can be used for the fine-grained build configuration are:

Finding packages

When crosscompiling CMake find_* commands are normally expected to find libraries and packages belonging to the same build target. So android-cmake configures CMake to search in Android-specific paths only and ignore your host system locations. So

find_package(ZLIB)

will surely find libz.so within the Android NDK.

However sometimes you need to locate a host package even when cross-compiling. For example you can be searching for your documentation generator. The android-cmake recommends you to use find_host_package and find_host_program macro defined in the android.toolchain.cmake:

find_host_package(Doxygen)
find_host_program(PDFLATEX pdflatex)

However this will break regular builds so instead of wrapping package search into platform-specific logic you can copy the following snippet into your project (put it after your top-level project() command):

# Search packages for host system instead of packages for target system
# in case of cross compilation these macro should be defined by toolchain file
if(NOT COMMAND find_host_package)
  macro(find_host_package)
    find_package(${ARGN})
  endmacro()
endif()
if(NOT COMMAND find_host_program)
  macro(find_host_program)
    find_program(${ARGN})
  endmacro()
endif()

Compiler flags recycling

Make sure to do the following in your scripts:

set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} ${my_cxx_flags}")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${my_cxx_flags}")

The flags will be prepopulated with critical flags, so don’t loose them. Also be aware that android-cmake also sets configuration-specific compiler and linker flags.

Troubleshooting

Building on Windows

First of all cygwin builds are NOT supported and will not be supported by android-cmake. To build natively on Windows you need a port of make but I recommend http://martine.github.io/ninja/ instead.

To build with Ninja you need:

But if you still want to stick to old make then:

Projects with assembler files

The android-cmake should correctly handle projects with assembler sources (*.s or *.S). But if you still facing problems with assembler then try to upgrade your CMake to version newer than 2.8.5

Copying

android-cmake is distributed under the terms of BSD 3-Clause License