--- layout: documentation title: Using the Android Native Development Kit with Bazel --- # Using the Android Native Development Kit with Bazel _If you're new to Bazel, please start with the [Building Android with Bazel](https://docs.bazel.build/versions/master/tutorial/android-app.html) tutorial._ ## Table of contents - [Overview](#overview) - [Prerequisites](#prerequisites) - [Quick start](#quick-start) - [Example setup](#example-setup) - [Configuring the STL](#configuring-the-stl) - [Configuring the target ABI](#configuring-the-target-abi) - [Selecting a C++ standard](#selecting-a-c-standard) - [How it works: introducing Android configuration transitions](#how-it-works-introducing-android-configuration-transitions) - [Building a `cc_library` for Android without using `android_binary`](#building-a-cc_library-for-android-without-using-android_binary) ## Overview Bazel can run in many different build configurations, including several that use the Android Native Development Kit (NDK) toolchain. This means that normal `cc_library` and `cc_binary` rules can be compiled for Android directly within Bazel. Bazel accomplishes this by using the `android_ndk_repository` repository rule. ## Prerequisites Please ensure that you have installed the Android SDK and NDK. To set up the SDK and NDK, add the following snippet to your `WORKSPACE`: ```python android_sdk_repository( name = "androidsdk", # Required. Name *must* be "androidsdk". path = "/path/to/sdk", # Optional. Can be omitted if `ANDROID_HOME` environment variable is set. ) android_ndk_repository( name = "androidndk", # Required. Name *must* be "androidndk". path = "/path/to/ndk", # Optional. Can be omitted if `ANDROID_NDK_HOME` environment variable is set. ) ``` For more information on the `android_ndk_repository` rule, see its the [Build Encyclopedia entry](https://docs.bazel.build/versions/master/be/android.html#android_ndk_repository). ## Quick start To build C++ for Android, simply add `cc_library` dependencies to your `android_binary` or `android_library` rules. For example, given the following BUILD file for an Android app: ```python # In /app/src/main/BUILD.bazel cc_library( name = "jni_lib", srcs = ["cpp/native-lib.cpp"], ) android_library( name = "lib", srcs = ["java/com/example/android/bazel/MainActivity.java"], resource_files = glob(["res/**/*"]), custom_package = "com.example.android.bazel", manifest = "LibraryManifest.xml", deps = [":jni_lib"], ) android_binary( name = "app", deps = [":lib"], manifest = "AndroidManifest.xml", ) ``` This BUILD file results in the following target graph: Build graph of Android project with cc_library dependencies To build the app, simply run: ``` $ bazel build //app/src/main:app ``` The `bazel build` command compiles the Java files, Android resource files, and `cc_library` rules, and packages everything into an APK: ``` $ zipinfo -1 bazel-bin/app/src/main/app.apk nativedeps lib/armeabi-v7a/libapp.so classes.dex AndroidManifest.xml ... res/... ... META-INF/CERT.SF META-INF/CERT.RSA META-INF/MANIFEST.MF ``` Bazel compiles all of the cc_libraries into a single shared object (`.so`) file, targeted for the `armeabi-v7a` ABI by default. To change this or build for multiple ABIs at the same time, see the section on [configuring the target ABI](#configuring-the-target-abi). ## Example setup This example is available in the [Bazel examples repository](https://github.com/bazelbuild/examples/tree/master/android-ndk). In the `BUILD.bazel` file, we define three targets with the `android_binary`, `android_library` and `cc_library` rules. The `android_binary` top-level target builds the APK. The `cc_library` target contains a single C++ source file with a JNI function implementation: ```c++ #include #include extern "C" JNIEXPORT jstring JNICALL Java_com_example_android_bazel_MainActivity_stringFromJNI( JNIEnv *env, jobject /* this */) { std::string hello = "Hello from C++"; return env->NewStringUTF(hello.c_str()); } ``` The `android_library` target specifies the Java sources, resource files, and the dependency on a `cc_library` target. For this example, `MainActivity.java` loads the shared object file `libapp.so`, and defines the method signature for the JNI function: ```java public class MainActivity extends AppCompatActivity { static { System.loadLibrary("app"); } @Override protected void onCreate(Bundle savedInstanceState) { // ... } public native String stringFromJNI(); } ``` **Note**: The name of the native library is derived from the name of the top level `android_binary` target. In this example, it is `app`. ## Configuring the STL To configure the C++ STL, use the flag `--android_crosstool_top`. ``` bazel build //:app --android_crosstool_top= ``` The available STLs in `@androidndk` are: | STL | Target label | |---------|-----------------------------------------| | STLport | `@androidndk//:toolchain-stlport` | | libc++ | `@androidndk//:toolchain-libcpp` | | gnustl | `@androidndk//:toolchain-gnu-libstdcpp` | For r16 and below, the default STL is `gnustl`. For r17 and above, it is `libc++`. For convenience, the target `@androidndk//:default_crosstool` is aliased to the respective default STLs. Please note that from r18 onwards, [STLport and gnustl will be removed](https://android.googlesource.com/platform/ndk/+/master/docs/Roadmap.md#ndk-r18), making `libc++` the only STL in the NDK. See the [NDK documentation](https://developer.android.com/ndk/guides/cpp-support) for more information on these STLs. ## Configuring the target ABI To configure the target ABI, use the `--fat_apk_cpu` flag as follows: ``` bazel build //:app --fat_apk_cpu= ``` By default, Bazel builds native Android code for `armeabi-v7a`. To build for x86 (e.g. for emulators), pass `--fat_apk_cpu=x86`. To create a fat APK for multiple architectures, you can specify multiple CPUs: `--fat_apk_cpu=armeabi-v7a,x86`. If more than one ABI is specified, Bazel will build an APK containing a shared object for each ABI. Depending on the NDK revision and Android API level, the following ABIs are available: | NDK revision | ABIs | |--------------|-------------------------------------------------------------| | 16 and lower | armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86\_64 | | 17 and above | armeabi-v7a, arm64-v8a, x86, x86\_64 | See [the NDK docs](https://developer.android.com/ndk/guides/abis.html) for more information on these ABIs. Multi-ABI Fat APKs are not recommended for release builds since they increase the size of the APK, but can be useful for development and QA builds. ## Selecting a C++ standard Use the following flags to build according to a C++ standard: | C++ Standard | Flag | |--------------|-------------------------| | C++98 | Default, no flag needed | | C++11 | `--cxxopt=-std=c++11` | | C++14 | `--cxxopt=-std=c++14` | For example: ``` bazel build //:app --cxxopt=-std=c++11 ``` Read more about passing compiler and linker flags with `--cxxopt`, `--copt`, and `--linkopt` in the [User Manual](https://docs.bazel.build/versions/master/user-manual.html#flag--cxxopt). Compiler and linker flags can also be specified as attributes in `cc_library` using `copts` and `linkopts`. For example: ```python cc_library( name = "jni_lib", srcs = ["cpp/native-lib.cpp"], copts = ["-std=c++11"], linkopts = ["-ldl"], # link against libdl ) ``` ## How it works: introducing Android configuration transitions The `android_binary` rule can explicitly ask Bazel to build its dependencies in an Android-compatible configuration so that the Bazel build *just works* without any special flags, except for `--fat_apk_cpu` and `--android_crosstool_top` for ABI and STL configuration. Behind the scenes, this automatic configuration uses Android [configuration transitions](https://docs.bazel.build/versions/master/skylark/rules.html#configurations). A compatible rule, like `android_binary`, automatically changes the configuration of its dependencies to an Android configuration, so only Android-specific subtrees of the build are affected. Other parts of the build graph are processed using the top-level target configuration. It may even process a single target in both configurations, if there are paths through the build graph to support that. Once Bazel is in an Android-compatible configuration, either specified at the top level or due to a higher-level transition point, additional transition points encountered do not further modify the configuration. The only built-in location that triggers the transition to the Android configuration is `android_binary`'s `deps` attribute. **Note:** The `data` attribute of `android_binary` intentionally does *not* trigger the transition. Additionally, `android_local_test` and `android_library` intentionally do *not* trigger the transition at all. For example, if you try to build an `android_library` target with a `cc_library` dependency without any flags, you may encounter an error about a missing JNI header: ``` ERROR: /app/src/main/BUILD.bazel:16:1: C++ compilation of rule '//app/src/main:jni_lib' failed (Exit 1) app/src/main/cpp/native-lib.cpp:1:10: fatal error: 'jni.h' file not found #include ^~~~~~~ 1 error generated. Target //app/src/main:lib failed to build Use --verbose_failures to see the command lines of failed build steps. ``` Ideally, these automatic transitions should make Bazel do the right thing in the majority of cases. However, if the target on the Bazel command-line is already below any of these transition rules, such as C++ developers testing a specific `cc_library`, then a custom `--crosstool_top` must be used. ## Building a `cc_library` for Android without using `android_binary` To build a standalone `cc_binary` or `cc_library` for Android without using an `android_binary`, use the `--crosstool_top`, `--cpu` and `--host_crosstool_top` flags. For example: ``` bazel build //my/cc/jni:target \ --crosstool_top=@androidndk//:default_crosstool \ --cpu= \ --host_crosstool_top=@bazel_tools//tools/cpp:toolchain ``` Here, we specify that top-level `cc_library` and `cc_binary` targets are built using the NDK toolchain. However, this causes Bazel's own host tools to be built with the NDK toolchain (and thus for Android), because the host toolchain is copied from the target toolchain. To work around this, we specify the value of `--host_crosstool_top` to be `@bazel_tools//tools/cpp:toolchain` to explicitly set the host's C++ toolchain. With this approach, the entire build tree is affected. Note that all of the targets on the command line must be compatible with building for Android when specifying these flags, which may make it difficult to use [Bazel wild-cards](https://docs.bazel.build/versions/master/command-line-reference.html#target-pattern-syntax) like `/...` and `:all`. These flags can be put into a `bazelrc` config (one for each ABI), in `/.bazelrc`: ``` common:android_x86 --crosstool_top=@androidndk//:default_crosstool common:android_x86 --cpu=x86 common:android_x86 --host_crosstool_top=@bazel_tools//tools/cpp:toolchain common:android_armeabi-v7a --crosstool_top=@androidndk//:default_crosstool common:android_armeabi-v7a --cpu=armeabi-v7a common:android_armeabi-v7a --host_crosstool_top=@bazel_tools//tools/cpp:toolchain # In general common:android_ --crosstool_top=@androidndk//:default_crosstool common:android_ --cpu= common:android_ --host_crosstool_top=@bazel_tools//tools/cpp:toolchain ``` Then, to build a `cc_library` for `x86` for example, run: ``` bazel build //my/cc/jni:target --config=android_x86 ``` In general, use this method for low-level targets (like `cc_library`) or when you know exactly what you're building; rely on the automatic configuration transitions from `android_binary` for high-level targets where you're expecting to build a lot of targets you don't control.