blog:2017:0913_cross_compiling_c_libraries_for_android_with_cmake

# Cross compiling C++ libraries for Android with CMake

As I am now trying to get a better understanding on the Unreal Engine and other major 3D engines it might be time to start considering building libraries and apps properly for other platforms than Windows and Linux. A good choice from that perspective would be Android as this doesn't involve getting a new computer as iOS would!

I already have abase project called NervSeed that can be used as a base project I want to build with multiple platform support, including Android. So now its time to setup the required environment to support cross compiling this project to Android either from Windows or from Linux.

# Setting up the Android compilation toolchain

First thing we obviously need is the Android NDK:

According the the Unreal Engine Required Android Setup CodeWorks is required, so we might just as well use the NDK from our CodeWorks installation to avoid any potential version mismatch issue.

So would need to retrieve the latest CodeWorks release (version 1R6 currently) from the NVidia download page (But the website is down for the moment, so will start with the currently installed CodeWorks version 1R5).

Important note: we should upgrade to at least cmake version 3.7 to ensure we get the appropriate support for Android targets: Updated cmake to version 3.9.2 in NervSeed project: OK

Let's now extend our build script to support an Android target:

So we generated this kind of toolchain file for cmake in case android target is specified:

cat <<EOF >build_config.cmake
set(CMAKE_SYSTEM_NAME $system) set(CMAKE_SYSTEM_VERSION 21) # API level set(CMAKE_ANDROID_ARCH_ABI arm64-v8a) set(CMAKE_ANDROID_NDK$ndkPath)
set(CMAKE_ANDROID_STL_TYPE gnustl_static)
EOF

Above the “$system" value is "Android" and the "$ndkPath” is a valid windows NDK path (since we run the windows version of cmake inside cygwin): “D:\Apps\CodeWorks\android-ndk-r12b”

But we get this error from cmake:

$nv_build android CMake flags: -DCMAKE_TOOLCHAIN_FILE=build_config.cmake -DNV_STATIC_BUILD=TRUE -DCMAKE_BUILD_TYPE=Release -DWITH_UPX_COMPRESSION=TRUE -DFLAVOR=ANDROID -DCMAKE_INSTALL_PREFIX=D:\Projects\NervSeed\dist\android CMake Error at build/android/build_config.cmake:4 (set): Syntax error in cmake code at D:/Projects/NervSeed/build/android/build_config.cmake:4 when parsing string D:\Apps\CodeWorks\android-ndk-r12b Invalid escape sequence \A Call Stack (most recent call first): tools/windows/cmake-3.9.2/share/cmake-3.9/Modules/CMakeDetermineSystem.cmake:91 (include) CMakeLists.txt:8 (PROJECT) CMake Error: CMAKE_C_COMPILER not set, after EnableLanguage CMake Error: CMAKE_CXX_COMPILER not set, after EnableLanguage -- Configuring incomplete, errors occurred! make: *** No rule to make target 'install'. Stop. Build completed in 0 seconds. Obviously a stupid escape sequence error… maybe it would be better with quotation marks on our CMAKE_ANDROID_NDK definition line ? ⇒ nope, this is not any better. So just replaced the backward slashes with forward slashes: ndkPath=echo$ndkPath | tr '\\' '/'

And now cmake seems to find the Android compiler appropriately:

$nv_build android tr: warning: an unescaped backslash at end of string is not portable CMake flags: -DCMAKE_TOOLCHAIN_FILE=build_config.cmake -DNV_STATIC_BUILD=TRUE -DCMAKE_BUILD_TYPE=Release -DWITH_UPX_COMPRESSION=TRUE -DFLAVOR=ANDROID -DCMAKE_INSTALL_PREFIX=D:\Projects\NervSeed\dist\android -- Android: Targeting API '21' with architecture 'arm64', ABI 'arm64-v8a', and processor 'aarch64' -- Android: Selected GCC toolchain 'aarch64-linux-android-4.9' -- The C compiler identification is GNU 4.9.0 -- The CXX compiler identification is GNU 4.9.0 -- Check for working C compiler: D:/Apps/CodeWorks/android-ndk-r12b/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-gcc.exe -- Check for working C compiler: D:/Apps/CodeWorks/android-ndk-r12b/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-gcc.exe -- 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: D:/Apps/CodeWorks/android-ndk-r12b/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-g++.exe -- Check for working CXX compiler: D:/Apps/CodeWorks/android-ndk-r12b/toolchains/aarch64-linux-android-4.9/prebuilt/windows-x86_64/bin/aarch64-linux-android-g++.exe -- works -- Detecting CXX compiler ABI info -- Detecting CXX compiler ABI info - done -- Detecting CXX compile features -- Detecting CXX compile features - done # Fixing NervSeed project compilation errors Unfortunately we have some compilation errors after that, but this is to be expected as the GCC compiler version is only 4.9.0 in this toolchain… hopefully CodeWorks release 1R6 woud provide a better compiler ? ⇒ Well according to this page gcc support is discontinued in the NDK and we should switch to Clang! What to do that in CMake ? • We had a problem in my DebugHandler class which would call exit(), and connect to signals, etc: I would not be surprised if this is all not available in an Android context, so for now, just not compiling this code at all using an #ifndef ANDROID (…) #endif section: OK • Next issue is: include/base/date.h:5780:12: error: 'stold' is not a member of 'std' • Found this issue report ⇒ checking the provided toolchain file. • Also see: https://gitlab.kitware.com/cmake/cmake/issues/17253 ⇒ adding the CMake NDK toolchain version: OK ! Finally got Cmake to use clang compiler with the toolchain file content: cat <<EOF >build_config.cmake set(CMAKE_SYSTEM_NAME$system)
set(CMAKE_SYSTEM_VERSION 21) # API level
#set(CMAKE_ANDROID_ARCH_ABI arm64-v8a)
set(CMAKE_ANDROID_NDK "\$ndkPath")
#set(CMAKE_ANDROID_STL_TYPE gnustl_static)
set(CMAKE_ANDROID_NDK_TOOLCHAIN_VERSION clang)
EOF
• : check if we can still (and if we should) specify the ARCH_ABI and STL_TYPE entries ?
• We still have the infamous 'stold' is not a member of 'std' error with this compiler.
• Including the header <cstdlib> doesn't help at all.
• We probably need to upgrade the compiler to fix this, but at the same time this date.h header is something far too complex for my current needs, so I should rather just get rid of it.
• Also, clang++ will complain about the provided -s command line argument, so we should remove it for this compiler: OK

⇒ Apart from those minor issues compiling for Android now seems to work as expected ! So in the end, that wasn't too hard…

• blog/2017/0913_cross_compiling_c_libraries_for_android_with_cmake.txt