ikerhurtado.com
You're in
Iker Hurtado's pro blog
Developer | Entrepreneur | Investor
Software engineer (entrepreneur and investor at times). These days doing performant frontend and graphics on the web platform at Barcelona Supercomputing Center

C++ support on Android NDK

22 Jan 2015   |   iker hurtado  
Share on Twitter Share on Google+ Share on Facebook
In this post I gather some basic and relevant info about the Android NDK C++ support. The official documentation is quite complete on this topic but is not on-line (it goes bundled in NDK package)

By default, the Android platform provides a very basic support of C++ standard library, but it's easy to set up the application for complete one. In addition, since 9d NDK revision it was added experimental libc++ support that seems to be the default and modern (C++11 implementation) Android C++ library in the future.

The Android platform provides a very minimal C++ runtime library (/system/lib/libstdc++) and corresponding headers for it in the NDK. By default, this 'system' runtime does not provide the following: Standard C++ Library support (except a few trivial headers), C++ exceptions support and RTTI support.

However, the NDK provides various "helper C++ runtimes" which can provide them, or a subset of these features: GAbi++, STLport, GNU STL and LLVM libc++.

To select a runtime, we have to define APP_STL inside the Application.mk. The 'system' runtime is the default if there is no APP_STL definition.

Enabling C++ Exceptions and RTTI

The NDK toolchain supports C++ exceptions, however all C++ sources are compiled with -fno-exceptions and -fno-rtti support by default, for compatibility reasons with previous releases.

To enable both of them (or either), we can use this ways:

  • Use the new LOCAL_CPP_FEATURES variable in your Android.mk, as in:
    LOCAL_CPP_FEATURES += exceptions
    LOCAL_CPP_FEATURES += rtti
  • Or more simply, add a single line to your Application.mk, the setting will automatically apply to all your project's NDK modules:
    APP_CPPFLAGS += -fexceptions
    APP_CPPFLAGS += -frtti

Static versus shared runtime

As for what to choose: static or shared runtime, I excerpt the text about from NDK documentation:

Please keep in mind that the static library variant of a given C++ runtime SHALL ONLY BE LINKED INTO A SINGLE BINARY for optimal conditions.

What this means is that if your project consists of a single shared library, you can link against, e.g., stlport_static, and everything will work correctly.

On the other hand, if you have two shared libraries in your project (e.g. libfoo.so and libbar.so) which both link against the same static runtime, each one of them will include a copy of the runtime's code in its final binary image. This is problematic because certain global variables used/provided internally by the runtime are duplicated.

This is likely to result in code that doesn't work correctly, for example:

- memory allocated in one library, and freed in the other would leak or even corrupt the heap.

- exceptions raised in libfoo.so cannot be caught in libbar.so (and may simply crash the program).

- the buffering of std::cout not working properly

This problem also happens if you want to link an executable and a shared library to the same static library.

In other words, if your project requires several shared library modules, then use the shared library variant of your C++ runtime.

Due to an issue which is fixed in JB-MR2 API level 18 (issue 41790 and 34416 ), if you use the shared library variant of a given C++ runtime, keep in mind that you must load it before any library that depends on it when your application starts.

As an example, let's consider the case where we have the following modules

    libfoo.so
    libbar.so which is used by libfoo.so
    libstlport_shared.so, used by both libfoo and libbar

You will need to load the libraries in reverse dependency order, as in:

    static {
      System.loadLibrary("stlport_shared");
      System.loadLibrary("bar");
      System.loadLibrary("foo");
    }

Note that you shouldn't use the 'lib' prefix when calling System.loadLibrary(), unless you specify the full path as in:

System.loadLibrary("/path/to/libstlport_shared.so")
Which is not recommended, since this hard-codes the path in your code.

Thread Safety of C++ Runtime

All C++ runtime implementations are thread safe, what means that simultaneous read access to shared containers is safe; however, the application is responsible for ensuring mutual exclusion if threads are both reading from and writing to shared containers.

C++ Runtime Debug Mode

The C++ runtimes are optimized for performance, so they perform little or no error checking. Some runtimes provide a debug mode to make it easier to detect incorrect use of the C++ standard library and difficult bugs.

For example: the debug mode replaces unsafe but efficient containers and iterators with similar but safe versions of them. These containers can perform runtime checking of the iterator’s validity and ownership.

POST A COMMENT: