C/C++

Accessing C++11 Features of the Android NDK

C++11 language features are supported in the NDK, but they require a non-default configuration.

Once you start working with some of the handy new C++11 features, it is a bit difficult to stop using them simply because you want to work on an Android project. Fortunately, the Android NDK supports C++11 features, although they are not enabled by default. The default Android NDK configuration provides only a minimal C++ runtime support library and doesn't include the necessary flags to activate available C++11 features. In this article, I explain how set up a project to use C++11 features, relying on Eclipse and the latest available Android NDK, version r9d.

Consider a very common scenario in which you want to create a new Android app by reusing existing C++ code. In these cases, a typical solution is to develop the UI in Java and use the Java Native Interface (JNI) to make calls to the C++ code from Java (and the other way around if necessary). If your existing C++ code has been written taking advantage of C++11 features, you certainly would not want to create a new version removing all these C++11 features just to make it fit with the default Android NDK configuration.
Fortunately, you can activate the NDK's C++11 features to allow you to work with modern C++ amenities, and you can go on using the auto keyword, lambda expressions, and other useful C++11 features.

I'll assume that you have basic experience working with Eclipse, Android Development Tools (ADT), and the Android NDK; hence, I won't provide specific instructions for the basic setup of these tools. You will need ADT and NDK installed on your system in order to test the examples. Because ADT and NDK have important changes in each new release, it's important to note that I am using ADT Build v22.6.2-1085508 and NDK Revision 9d. This way, I can focus on the necessary configurations and tweaks related to C++11 and the related features. I'll use a simple example Android app that employs a few C++11 features combined with some use of the Standard Templates Library (STL). Finally, I'll explain additional options and configurations that you might need to consider.

Example Project

Create a new project in Eclipse and select the Android Application Project wizard. I use Cplusplus11 for both Application Name and Project Name, and the package name is com.example. I leave the default options for the different steps within the wizard, and I select the Blank Activity option with the Create Activity checkbox activated. I use the default activity name, MainActivity. This way, the wizard will create a Cplusplus11/src/com.example.cplusplus11/MainActivity.java file that defines the MainActivity Java class as a subclass of ActionBarActivity. I'll go back to the Java code later.

Now, it is necessary to add native support to the project. Right-click on the recently created project in the Project Explorer and select Android Tools | Add Native Support…. I use libCplusplus11.so as the library name. Notice that you simply need to enter cplusplus11 in the dialog box and the Eclipse plugin will add the lib prefix. The Eclipse plugin will add a new jni folder to the project with the following two elements (see Figure 1): cplusplus11.cpp and Android.mk

Figure 1: The sample Android application project structure in the Project Explorer after the native support has been added.

Right-click on the project in the Project Explorer again, and select Properties | C/C++ Build. Deactivate the Use Default Build Command checkbox and enter ndk-build NDK_DEBUG=1 in the Build Command textbox. This way, the NDK debugger is enabled.

The default contents for the Cplusplus11.cpp C++ source file is just a line that includes the jni.h header:

#include <jni.h>

The default contents for the Android.mk build file includes the following lines:

It is often helpful to use the Android logging features when you call C++ code from Java through the JNI, so I add the following line to pass the name of the specific system library that provides Android logging features and tell the linker to generate a module that links to /system/lib/liblog.so at load time. Notice that -llog is decomposed in the -l option followed by log; that is, the library name with neither the lib prefix nor the .so extension.

LOCAL_LDLIBS := -llog

The following lines show the new contents of the Android.mk build file:

Now, it is necessary to add a new build file to the jni folder named Application.mk. This file describes which native modules the Android application requires. The following lines show the initial content that I use for this build file:

The default compiler is GCC 4.6. The NDK_TOOLCHAIN_VERSION key specifies the 4.8 value to define the toolchain to use GCC 4.8 as the compiler. The default configuration of the NDK build system generates the machine code for the armeabi ABI; that is, the ARMv5TE-based CPU. The APP_ABI value allows you to select different ABIs.

If you are developing on Windows and you meet the necessary hardware requirements, it is usually a good idea to install the Intel x86 Emulator Accelerator (HAXM), which speeds up Android emulation on Windows. If you are working with this accelerated emulator, the CPU/ABI of your target Android Virtual Device (AVD) will be Intel Atom (x86), so you will need to include x86 in the APP_ABI values. In this example, I've included all the target ABIs in APP_ABI, but you can specify only the ones you need. Notice that you can achieve the same effect by using APP_ABI := all. There are many additional options for APP_ABI, but I wanted to focus on the importance of this setting because when you use different CPU/ABI configurations in your target AVD, the Java code will raise an exception if you try the load the library and you didn't specify the right values for APP_ABI (since the appropriate library won't be generated).

The APP_CPPFLAGS key specifies the set of C++ compiler flags passed when building C++ source. The following line enables the supported C++11 features for all your modules. However, you must take into account that pthread, RTTI, and exceptions aren't enabled by default. The C++11 support includes the auto keyword and lambda expressions. There is also support for std::thread, but note that there are still some problems with the usage of
std::thread that lead to unexpected app crashes.

APP_CPPFLAGS += -std=c++11

As I explained before, I want to use some STL features, so the following line specifies the static GNU STL implementation. There are other alternatives, such as the STLport library and the experimental libc++ implementation introduced in NDK r9d. You can read more information about libc++ here.

APP_STL := gnustl_static

Finally, it is necessary to specify the path for the GNU STL implementation headers. The following line specifies the path to these headers included in the NDK folders. Because I've specified that the toolchain use GCC 4.8, I make sure the headers path corresponds to version 4.8. Notice that you must have the Android NDK path configured in Eclipse. To do this, select Window | Preferences | Android | NDK, and make sure that the NDK location value is properly configured.

Dr. Dobb's encourages readers to engage in spirited, healthy debate, including taking us to task.
However, Dr. Dobb's moderates all comments posted to our site, and reserves the right to modify or remove any content that it determines to be derogatory, offensive, inflammatory, vulgar, irrelevant/off-topic, racist or obvious marketing or spam. Dr. Dobb's further reserves the right to disable the profile of any commenter participating in said activities.

Video

This month's Dr. Dobb's Journal

This month,
Dr. Dobb's Journal is devoted to mobile programming. We introduce you to Apple's new Swift programming language, discuss the perils of being the third-most-popular mobile platform, revisit SQLite on Android
, and much more!