Channels ▼
RSS

C/C++

Accessing C++11 Features of the Android NDK


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

C++11andANDROID NDK
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:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL_MODULE    := cplusplus11
LOCAL_SRC_FILES := cplusplus11.cpp

include $(BUILD_SHARED_LIBRARY)

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:

LOCAL_PATH := $(call my-dir)

include $(CLEAR_VARS)

LOCAL
_MODULE    := Cplusplus11
LOCAL_SRC_FILES := Cplusplus11.cpp
# Generate a module that links to /system/lib/liblog.so at load time to enable logging
LOCAL_LDLIBS    := -llog

include $(BUILD_SHARED_LIBRARY)

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:

NDK_TOOLCHAIN_VERSION := 4.8
APP_ABI := armeabi armeabi-v7a x86 mips
#  Enable C++11. However, pthread, rtti and exceptions aren’t enabled 
APP_CPPFLAGS += -std=c++11
# Instruct to use the static GNU STL implementation
APP_STL := gnustl_static
LOCAL_C_INCLUDES += ${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include

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.

LOCAL_C_INCLUDES += ${ANDROID_NDK}/sources/cxx-stl/gnu-libstdc++/4.8/include


Related Reading


More Insights






Currently we allow the following HTML tags in comments:

Single tags

These tags can be used alone and don't need an ending tag.

<br> Defines a single line break

<hr> Defines a horizontal line

Matching tags

These require an ending tag - e.g. <i>italic text</i>

<a> Defines an anchor

<b> Defines bold text

<big> Defines big text

<blockquote> Defines a long quotation

<caption> Defines a table caption

<cite> Defines a citation

<code> Defines computer code text

<em> Defines emphasized text

<fieldset> Defines a border around elements in a form

<h1> This is heading 1

<h2> This is heading 2

<h3> This is heading 3

<h4> This is heading 4

<h5> This is heading 5

<h6> This is heading 6

<i> Defines italic text

<p> Defines a paragraph

<pre> Defines preformatted text

<q> Defines a short quotation

<samp> Defines sample computer code text

<small> Defines small text

<span> Defines a section in a document

<s> Defines strikethrough text

<strike> Defines strikethrough text

<strong> Defines strong text

<sub> Defines subscripted text

<sup> Defines superscripted text

<u> Defines underlined text

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.

 
Disqus Tips To upload an avatar photo, first complete your Disqus profile. | View the list of supported HTML tags you can use to style comments. | Please read our commenting policy.
 

Comments:

GastonHillar
2014-06-30T18:44:39

For some weird reason I still couldn't discover, my Eclipse ADT installations didn't allow me to work with for range loops, as if it weren't supported by any compiler option. I sill don't know why, but I followed the steps to test in a clean environment and I could make range based loops work.

So, the following code compiles without problems with the steps I explained in the article:

int sum = 0;

for (auto n : numbers) {

sum += n;

}

The following lines show the complete sample code with the usage of a range based loop instead of for_each.

#include <jni.h>

#include <algorithm>
#include <iterator>
#include <vector>

// In order to log
#include <android log.h="">

#define LOG_TAG "CPlusPlus11_sumArray"

using namespace std;

extern "C" {

JNIEXPORT jint JNICALL

Java_com_example_MainActivity_sumArray

(JNIEnv *env, jobject obj, jintArray arr)

{

auto len = env->GetArrayLength(arr);

__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "arr length is %d", len);

jint *body = env->GetIntArrayElements(arr,0);

vector<int> numbers(body, body + len);

int sum = 0;

for (auto n : numbers) {

sum += n;

}

env->ReleaseIntArrayElements(arr,body,0);

__android_log_print(ANDROID_LOG_INFO, LOG_TAG, "sum(arr) = %d", sum);

return sum;

}

}


Permalink
ubm_techweb_disqus_sso_-0cd02431100cced55cb6ba2793570183
2014-06-28T06:09:27

Range based for are surely supported. I am using them on my NDK applications.


Permalink

Video