Common problems and solutions

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 minSdkVersions 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.