This document is a partial list of the most commonly encountered non-bugs you might encounter when using the NDK, and their solutions (if available).
Using _FILE_OFFSET_BITS=64
with older API levels
Prior to unified headers, the NDK did not support _FILE_OFFSET_BITS=64
. If
you defined it when building your app, it was silently ignored. The
_FILE_OFFSET_BITS=64
option is now supported with unified headers, but on old
versions of Android very few of the off_t
APIs were available as an off64_t
variant. Therefore, using this feature with old API levels results in fewer
functions being available.
This problem is explained in detail in the r16 blog post and in the bionic documentation.
Problem: Your build is asking for APIs that do not exist in your
minSdkVersion
.
Solution: Disable _FILE_OFFSET_BITS=64
or raise your minSdkVersion
.
Undeclared or implicit definition of mmap
You may see the following error in C++:
error: use of undeclared identifier 'mmap'
or the following error in C:
warning: implicit declaration of function 'mmap' is invalid in C99
Using _FILE_OFFSET_BITS=64
instructs the C library to use mmap64
instead of
mmap
. mmap64
was not available until android-21
. If your minSdkVersion
value is lower than 21, the C library does not contain an mmap
that is
compatible with _FILE_OFFSET_BITS=64
, so the function is unavailable.
minSdkVersion
set higher than device API level
The API level you build against with the NDK has a very different meaning than
compileSdkVersion
does for Java. The NDK API level is your app's minimum
supported API level. In ndk-build, this is your APP_PLATFORM
setting. With
CMake, this is -DANDROID_PLATFORM
.
Since references to functions are typically resolved when libraries are loaded rather than when they are first called, you cannot reference APIs that are not always present and guard their use with API level checks. If they are referred to at all, they must be present.
Problem: Your NDK API level is higher than the API supported by your device.
Solution: Set your NDK API level (APP_PLATFORM
) to the minimum version
of Android your app supports.
Build System | Setting |
---|---|
ndk-build | APP_PLATFORM |
CMake | ANDROID_PLATFORM |
externalNativeBuild | android.minSdkVersion |
For other build systems, see Use the NDK with other build systems.
Cannot locate __aeabi
Symbols
The following message:
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
__aeabi_memcpy
"
is one example of possible runtime errors. These errors appear in the log when
you attempt to load your native libraries. The symbol might be any of
__aeabi_*
; __aeabi_memcpy
and __aeabi_memclr
seem to be the most common.
This problem is documented in Issue 126
Cannot locate symbol rand
For the following error log message:
UnsatisfiedLinkError: dlopen failed: cannot locate symbol "
rand
"
See this detailed Stack Overflow answer.
Undefined reference to __atomic_*
Problem: Some ABIs need libatomic
to provide some implementations for
atomic operations.
Solution: Add -latomic
when linking.
For the following error message:
error: undefined reference to '
__atomic_exchange_4
'
the actual symbol here might be anything prefixed with __atomic_
.
RTTI/exceptions not working across library boundaries
Problem: Exceptions are not being caught when thrown across shared library
boundaries, or dynamic_cast
is failing.
Solution: Add a key function to your types. A key function is the first non-pure, out-of-line virtual function for a type. For an example, see the discussion on Issue 533.
The C++ ABI states that two objects have the same type if and
only if their type_info
pointers are identical. Exceptions may only be caught
if the type_info
for the catch matches the thrown exception. The same rule
applies for dynamic_cast
.
When a type does not have a key function, its typeinfo
is emitted as a weak
symbol and matching type infos are merged when libraries are loaded. When
loading libraries dynamically after the executable has been loaded (in other
words, via dlopen
or System.loadLibrary
), it may not be possible for the
loader to merge type infos for the loaded libraries. When this happens, the
two types are not considered equal.
Using mismatched prebuilt libraries
Using prebuilt libraries—these are typically third-party libraries—in your application requires a bit of extra care. In general, be aware of the following rules:
The resulting app's minimum API level is the maximum of the
minSdkVersion
s of all the app's libraries.If your
minSdkVersion
is 16, but you're using a prebuilt library that was built against 21, the resulting app's minimum API level is 21. Failure to adhere to this will be visible at build time if the prebuilt library is static, but may not appear until run time for prebuilt shared libraries.All libraries should be generated with the same NDK version.
This rule is a bit more flexible than most since breakages are rare, but compatibility between libraries that were built with different major versions of the NDK is not guaranteed. The C++ ABI is not stable and has changed in the past.
Apps with multiple shared libraries must use a shared STL.
As with mismatched STLs, the problems caused by this can be avoided if great care is taken, but it's better to just avoid the problem. The best way to avoid this problem is to avoid having multiple shared libraries in your app.