C++11 support on Android with g++ 4.8

Summary

The C++11 support on Android when using g++ 4.8 is pretty good. The important concurrency features that were missing from g++ 4.6 are now available in the Standard Template Library.

Testing libgnustl_shared.so

After examining the LLVM libc++ library on Android, I wanted to check which C++11 features are currently available using g++ 4.8 and the GNU Standard Template Library (libstdc++). g++ 4.8 improved support for C++11 significantly (4.6 vs. 4.8), so the question was whether that support also made it into the Android-specific compilers. With the LLVM libc++ library, a lot of very specific platform code such as support for atomic operations was stubbed out, which would cascade down into problems with the mutual exclusion mechanisms and threads.

Based on a review of an existing codebase, the features most interesting to me were contained in the following headers: atomic, chrono, condition_variable (condition_variable), memory (shared_ptr, unique_ptr), mutex (lock_guard, mutex, unique_lock), thread (thread). Also of interest was compiler support for lambdas and auto keyword support.

So let’s see what’s available, by modifying the android-ndk-r9/samples/test-libstdc++ native executable to utilize a number of C++11 features to perform the same race condition-prone task. Namely, the program generates a random number of threads which each attempt to simultaneously increment some global variable by one, one hundred times.

C++ gives you a few ways to solve the problem, and I’ve tried each of them here. The logic of the incrementation isn’t exactly identical, and in some cases incredibly inefficient (the conditional_variable case basically has all threads waiting for a single thread to complete, before they can acquire a shared resource mutex and begin executing). In any case, this is more a proof of library completeness than a proof of algorithmic efficiency.

The test source code looks like this:

I added an Application.mk file to the jni folder. Debugging is activated, so that the assert() macro isn’t disabled.

APP_ABI    := armeabi
APP_STL    := gnustl_shared
APP_CFLAGS := --std=c++11
APP_OPTIM  := debug

NDK_TOOLCHAIN_VERSION := 4.8

Building works fine:

$ ndk-build
Compile++ thumb  : test-libstl <= test-libstl.cpp
Prebuilt       : libgnustl_shared.so <= /sources/cxx-stl/gnu-libstdc++/4.8/libs/armeabi/
Executable     : test-libstl
Install        : test-libstl => libs/armeabi/test-libstl
Install        : libgnustl_shared.so => libs/armeabi/libgnustl_shared.so
$ adb push libs/armeabi/libgnustl_shared.so /data/tmp
366 KB/s (804484 bytes in 2.143s)
$ adb push libs/armeabi/test-libstl /data/tmp
284 KB/s (50536 bytes in 0.173s)

After pushing the test-libstl executable to the device, make sure the /data/tmp folder is added to the LD_LIBRARY_PATH:

localhost tmp # LD_LIBRARY_PATH=$LD_LIBRARY_PATH:/data/tmp

Then just run the executable, and you should see:

localhost tmp # ./test-libstl 
std::atomic + std::random + std::thread + auto + ranged-for test
  -- std::random rolled: 11
  -- atomicInt final value: 1100
std::condition_variable + std::mutex + std::unique_lock + std::random + std::thread + lambda test
  -- std::random rolled: 15
  -- nonAtomicInt final value: 1500
std::lock_guard + std::mutex + std::random + std::thread + lambda test
  -- std::random rolled: 7
  -- lockGuardInt final value: 700
std::unique_ptr + std::shared_ptr + std::make_shared tests
  --  PtrTest(): std::unique_ptr
  --  PtrTest(): std::shared_ptr
  -- ~PtrTest(): std::shared_ptr
  -- ~PtrTest(): std::unique_ptr

To run the tests, I used a rooted phone running Android 2.3.7.

In real deployments where you’re building a loadable shared-library using the Java Native Interface, you’ll need to follow the instructions from the NDK’s CPLUSPLUS-SUPPORT.html file and call System.loadLibrary on libgnustl_shared.so before loading the eventual shared library form of your app. (Managing standalone executable lifecycles tends to be a pain in the ass inside of Android apps and services, at least based on the experiences we had at my previous company.)

Overall, I’m pretty positive about the support for concurrency in g++ 4.8 on Android, and am thrilled to see that it may now be possible to write a single modern C++ codebase across all of the major desktop and mobile platforms.

3 thoughts on “C++11 support on Android with g++ 4.8”

  1. THANKS for this post. It illuminated the source of a compiling/linking problem I was having getting Android NDK and Google Play Games Service C++ SDK v1.2 to build (in the end I needed the a modern GCC compiler [c++11] and the explicit use of NDK 4.8 toolkit)

    If we should ever meet IRL I owe you a meal or drink! 🙂

    Regarding a line in the jni/Application.mk , specifically:
    “APP_CFLAGS := –std=c++11” a typo?

    Should it be, if not can you elaborate why?
    “APP_CFLAGS := -std=c++11”

    If this did need to be the way you specified I truly want to understand the situation. It may be something I simply may not be privy too! I am not knowledge trolling!

    1. I think you might be right about “-std=” being used with one hyphen instead of two, though I wonder if the options parser accepts it anyway.

Leave a Reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.