Overview
Bazel can run in many different build configurations, including several that use the Android Native Development Kit (NDK) toolchain. This means that normalcc_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 yourWORKSPACE:
android_ndk_repository rule, see the Build
Encyclopedia entry.
If you’re using a recent version of the Android NDK (r22 and beyond), use the
Starlark implementation of android_ndk_repository.
Follow the instructions in
its README.
Quick start
To build C++ for Android, simply addcc_library dependencies to your
android_binary or android_library rules.
For example, given the following BUILD file for an Android app:
BUILD file results in the following target graph:
Figure 1. Build graph of Android project with cc_library dependencies.
To build the app, simply run:
bazel build command compiles the Java files, Android resource files, and
cc_library rules, and packages everything into an APK:
.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.
Example setup
This example is available in the Bazel examples repository. In theBUILD.bazel file, three targets are defined 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:
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:
android_binary target. In this example, it is app.
Configuring the STL
To configure the C++ STL, use the flag--android_crosstool_top.
@androidndk are:
| STL | Target label |
|---|---|
| STLport | @androidndk//:toolchain-stlport |
| libc++ | @androidndk//:toolchain-libcpp |
| gnustl | @androidndk//:toolchain-gnu-libstdcpp |
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,
making libc++ the only STL in the NDK.
See the NDK
documentation
for more information on these STLs.
Configuring the target ABI
To configure the target ABI, use the--fat_apk_cpu flag as follows:
armeabi-v7a. To build for x86
(such as 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 |
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 |
--cxxopt, --copt, and
--linkopt in the User Manual.
Compiler and linker flags can also be specified as attributes in cc_library
using copts and linkopts. For example:
Integration with platforms and toolchains
Bazel’s configuration model is moving towards platforms and toolchains. If your build uses the--platforms flag to select for the architecture or operating system
to build for, you will need to pass the --extra_toolchains flag to Bazel in
order to use the NDK.
For example, to integrate with the android_arm64_cgo toolchain provided by
the Go rules, pass --extra_toolchains=@androidndk//:all in addition to the
--platforms flag.
WORKSPACE file:
BUILD
file (for NDK 20) when resolving architecture and operating system constraints:
How it works: introducing Android configuration transitions
Theandroid_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.
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:
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:
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, 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: 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 like
/... and :all.
These flags can be put into a bazelrc config (one for each ABI), in
<var>project</var>/.bazelrc:
cc_library for x86 for example, run:
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.