Android NDK r21 is now in beta! It’s been a longer than usual development cycle (four months since NDK r20), so there’s quite a lot to discuss for this release.
We have the usual toolchain updates, improved defaults for better security and performance, and are making changes to our release process to better accommodate users that need stability without hindering those that want new features.
New Minimum System Requirements
This release comes with new minimum system requirements. Following Android Studio and the SDK, 32-bit Windows is no longer supported. While this change will not affect most developers, this change does have an impact if you use 32-bit versions of Microsoft® Windows®. Linux users must have glibc 2.17 or newer.
Release Cycle Changes and LTS
One release a year will be our Long Term Support (LTS) release for users that want stability more than they need new features. The release will undergo a longer beta cycle before being released, and will receive bug fixes as backports until next year’s LTS release. Generally releasing in Q4, our first LTS release will be NDK r21.
The non-LTS releases each year, which we call the “rolling” release, will be similar to our current process. These will be approximately quarterly releases of our latest set of features, which will only be patched later for critical toolchain fixes. If you want the latest features from Clang and libc++, this is the release for you.
More detail, including the criteria we will use to determine what will be backported, what kinds of bugs will trigger a point release, and the bar we hold each release to can be found documented on our GitHub Wiki.
New Features and Updates
There are quite a lot of new things in this release, resolving bugs and helping you write better, safer code.
We’ve updated GNU Make to version 4.2, which enables
--output-sync to avoid interleaving output with error messages. This is enabled by default with ndk-build. This also includes a number of bug fixes, including fixing the pesky
CreateProcess errors on Windows.
GDB has been updated to version 8.3, which includes fixes for debugging modern Intel CPUs.
As always, we’ve updated LLVM and all of its components (Clang, lld, libc++, etc) which includes many improvements.
The toolchain has been updated to r365631 (the master branch as of 10 July 2019). This includes fixes for quite a few bugs in the previous release, perhaps most importantly LLD no longer hangs when using multithreaded linking on Windows. OpenMP is now available as a dynamic library (and this is the new default behavior, so link with
-static-openmp if you want to stick with the static runtime).
A handful of driver improvements have been made to reduce the amount of compiler configuration required by each build system as well. Build system owners should check the updated Build System Maintainers guide.
libc++ has been updated to r369764.
Fortify is now enabled by default when using ndk-build or the CMake toolchain file (this includes
ExternalNativeBuild users). Fortify enables additional checks in the standard library that can help catch bugs sooner and mitigate security issues. For example, without fortify the following code compiles fine:
const char src = "this string is too long"; char dst; strcpy(dst, src);
With fortify, the buffer overflow is diagnosed at compile-time:
test.cpp:10:18: error: 'strcpy' called with string bigger than buffer strcpy(dst, src); ^
It is not always possible for the compiler to detect this issue at compile-time. In those cases, a run-time check will be used instead that will cause the program to abort rather than continue unsafely.
If you’re using a build system other than ndk-build or CMake via the NDK’s toolchain file, this will not be enabled by default. To enable, simply define
_FORTIFY_SOURCE=2. The most reliable way to do this is by adding
-D_FORTIFY_SOURCE=2 to your compiler flags.
Clang can also statically detect some of these issues by using
-Wfortify-source (also new in r21). This is on by default, but it’s recommended to enforce fixing issues with
-Werror=fortify-source. Use this in addition to the C library features, not instead of, since the warnings do not cover the same cases as the C library extension, nor can it add run-time checks.
Note that because run-time support is required for fortify and the feature was gradually added to Android over time, the exact set of APIs protected by fortify depends on your
minSdkVersion. Fortify is an improvement, but it is not a replacement for good tests, ASan, and writing safe code.
See FORTIFY in Android for an in-depth explanation of fortify.
Since August 2019, all existing and new apps are now required to support 64-bit before they can be released to Google Play; there’s an extension for a limited set of apps. For more information and help on adding support for 64-bit, see our guide.
Neon by default
Arm code is now built with Neon by default. In a previous release we enabled it conditionally based on minSdkVersion, but given the very small number of devices that don’t support Neon we now enable it unconditionally. This offers improved performance on all 32-bit Arm devices (64-bit Arm always had this, and it does not affect Intel ABIs).
As before, this behavior can be disabled for apps that need to continue supporting devices without Neon. Alternatively, those devices can be blacklisted in the Play Console. See https://developer.android.com/ndk/guides/cpu-arm-neon for more information.