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](https://android.googlesource.com/platform/ndk/+/master/docs/UnifiedHeaders.md), 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](https://android-developers.googleblog.com/2017/09/introducing-android-native-development.html) and in the [bionic
documentation](https://android.googlesource.com/platform/bionic/+/master/docs/32-bit-abi.md).

**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.
| **Note:** `mmap` is only the most common manifestation of this problem. The same is true of any function in the C library that has an `off_t` parameter.
| **Note:** Since r16 beta 2, the C library exposes `mmap64` as an inline function to mitigate this instance of this issue.

## `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`.
| **Note:** If you're using [externalNativeBuild](https://developer.android.com/reference/tools/gradle-api/current/com/android/build/api/dsl/ExternalNativeBuild), it automatically uses your `minSdkVersion`.

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](https://developer.android.com/ndk/guides/application_mk)                                                                  | `APP_PLATFORM`          |
| [CMake](https://developer.android.com/ndk/guides/cmake)                                                                               | `ANDROID_PLATFORM`      |
| [externalNativeBuild](https://developer.android.com/reference/tools/gradle-api/current/com/android/build/api/dsl/ExternalNativeBuild) | `android.minSdkVersion` |

For other build systems, see [Use the NDK with other build
systems](https://developer.android.com/ndk/guides/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](https://github.com/android-ndk/ndk/issues/126)

### Cannot locate symbol `rand`

For the following error log message:
> UnsatisfiedLinkError: dlopen failed: cannot locate symbol "`rand`"

See this detailed [Stack Overflow
answer](http://stackoverflow.com/a/27338365/632035).

## 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_`.
| **Note:** ndk-build and CMake handle this for you. For other build systems, you may need to do this manually.

## 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](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#vague-vtable) 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](https://github.com/android-ndk/ndk/issues/533#issuecomment-335977747).

The [C++ ABI](https://itanium-cxx-abi.github.io/cxx-abi/abi.html#rtti) 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.
| **Note:** For non-polymorphic types, the type cannot have a key function. For non-polymorphic types, RTTI is unnecessary, since `std::is_same` can be used to determine type equality at compile time.

## 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](https://developer.android.com/ndk/guides/cpp-support#sr).

  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.