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
<atomic>
and
<type_traits>
.
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.