Introducing Android Native Development Kit r16

Posted by Dan Albert, Android NDK Tech Lead

The latest version of the Android Native Development Kit (NDK), Android NDK r16 Beta 1, is now available for download. It is also available in the SDK manager via Android Studio.

NDK r16 is a big milestone for us, because it’s the first release that we’re ready to recommend that people start migrating to libc++! More on this later.

We’ve also updated libc++ and its related projects, so this release has improved support for C++1z. Keep in mind that until C++1z becomes C++17, everything included is subject to change.

You can find the release notes for this release here.

libc++ and libandroid_support

The NDK has a library called libandroid_support that backports libc APIs that libc++ depends on that weren’t available on older releases. The reason we’ve been unable to endorse libc++ (as implemented in the NDK) until now has been a lack of confidence in this library. The focus of r16 was to rewrite this library for improved stability.

Since libandroid_support is now a smaller library, your app’s behavior should more closely match the behavior of the system. As an example, libandroid_support previously included an alternative implementation of part of stdio. While some features got backported to ICS, it also meant that any bugs in the alternate implementation would be present on all OS releases since the bug was baked into your app. In the new version of libandroid_support, we’ve removed this so you’ll be missing some features on older devices (almost exclusively things that no one uses, like %a support in format strings), but your apps using libc++ will be smaller and more reliable for not having these features.

Switching to libc++

So, why should you switch to libc++? First and foremost, the other STLs will not be supported going forward (this has been noted in our roadmap for quite some time). We’ve been using libc++ for the Android platform since Lollipop, and that’s been a change that our engineers have been overwhelmingly happy with. We were able to make this transition in the platform earlier than we could in the NDK because we didn’t need libandroid_support, and could instead just update libc in place.

In contrast to the other STLs currently available in the NDK, libc++ fully supports C++11, C++14, and most of C++1z! Stlport hasn’t had an update since 2008, and gnustl (what we call GNU’s libstdc++, to avoid confusion with Bionic’s libstdc++, which isn’t an STL) historically hasn’t worked very well with Clang, particularly in headers that are closely tied to compiler builtins like and .

We’ll most likely be making libc++ the default in the next NDK release, but for now you can opt-in if you’re not using it already by following the instructions below.

Like the other STLs, libc++ is available as both a static and shared library. Which one you should use depends on your specific circumstances as described in our docs, but tl;dr use the static version if you have one and only one shared library in your application, and use the shared one in all other cases.

ndk-build

Add the following to your Application.mk file:

APP_STL := c++_shared 

CMake

Pass the following when invoking CMake:

-DANDROID_STL=c++_shared 

If you’re using CMake via Gradle, add the following to your build.gradle:

externalNativeBuild {     cmake {         arguments "-DANDROID_STL=c++_shared"     } } 

Standalone Toolchain

When you create your standalone toolchain, pass --stl=libc++.

The Future of libandroid_support

If you’ve read our roadmap, you’ve seen that we’ve planned to expand libandroid_support to backport as much of libc/libm as possible. Whenever we’ve spoken with people about this, we’ve received lukewarm responses at best. Given that this doesn’t seem to be a thing that people are interested in, and that it would be something that increases library size (and therefore APK size, which is something everyone seems very interested in), we no longer plan to do this.

If we’ve misinterpreted your response or if we haven’t heard from you and this is something you want, please let us know!

_FILE_OFFSET_BITS=64

tl;dr: Don’t set _FILE_OFFSET_BITS=64 if you want to keep the behavior present in old NDKs.

Historically, setting _FILE_OFFSET_BITS=64 in the NDK did nothing. This feature was not present in the deprecated headers at all. With unified headers, the NDK now has up to date headers with support for this feature.

_FILE_OFFSET_BITS=64 is a macro you can define in your application to get support for a 64-bit off_t in 32-bit code. This works by both making off_t 64-bit (by default it is 32-bit in 32-bit code) and by implicitly replacing calls to APIs like lseek with calls to lseek64.

Support for _FILE_OFFSET_BITS=64 was not added to Android in a single release. One API, lseek64, has always been in bionic. Most APIs were added in Lollipop, and a few more were not added until later releases.

If you’re targeting a release that does not support the 64-bit off_t variant of a function you are using and have set _FILE_OFFSET_BITS=64, the function will not be available. This is in contrast to the behavior for r15 and r15b (but matches r15c) where the functions were wrongly exposed with a 32-bit off_t that would be silently truncated.

Note that the 64-bit off_t APIs are still available without _FILE_OFFSET_BITS=64 under different names. For example, instead of lseek, call lseek64. Instead of off_t, use off64_t.

Finally, since this feature is new to the NDK with unified headers, if you just want to return to the pre-unified headers behavior, all you need to do is stop setting _FILE_OFFSET_BITS=64.

For more information about off_t ABI details in bionic, see the Bionic 32-bit ABI bugs doc.


Android Developers Blog