Jika Anda baru menggunakan Bazel, mulailah dengan tutorial Membangun Android dengan Bazel.
Ringkasan
Bazel dapat berjalan dalam berbagai konfigurasi build, termasuk beberapa yang menggunakan toolchain Android Native Development Kit (NDK). Artinya, aturan cc_library dan cc_binary normal dapat dikompilasi untuk Android langsung dalam Bazel. Bazel melakukannya dengan menggunakan aturan repositori android_ndk_repository.
Prasyarat
Pastikan Anda telah menginstal Android SDK dan NDK.
Untuk menyiapkan SDK dan NDK, tambahkan cuplikan berikut ke WORKSPACE Anda:
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.
)
Untuk mengetahui informasi selengkapnya tentang aturan android_ndk_repository, lihat entri Ensiklopedia Build.
Jika Anda menggunakan Android NDK versi terbaru (r22 dan yang lebih baru), gunakan implementasi Starlark dari android_ndk_repository.
Ikuti petunjuk di
README-nya.
Mulai cepat
Untuk membuat C++ untuk Android, cukup tambahkan dependensi cc_library ke aturan
android_binary atau android_library Anda.
Misalnya, dengan file BUILD berikut untuk aplikasi Android:
# In <project>/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",
)
File BUILD ini menghasilkan grafik target berikut:

Gambar 1. Bangun grafik project Android dengan dependensi cc_library.
Untuk mem-build aplikasi, cukup jalankan:
bazel build //app/src/main:appPerintah bazel build mengompilasi file Java, file resource Android, dan
aturan cc_library, serta memaketkan semuanya ke dalam 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.MFBazel mengompilasi semua cc_library menjadi satu file objek bersama (.so),
yang ditargetkan untuk ABI armeabi-v7a secara default. Untuk mengubahnya atau membuat build untuk
beberapa ABI secara bersamaan, lihat bagian tentang mengonfigurasi ABI
target.
Contoh penyiapan
Contoh ini tersedia di repositori contoh Bazel.
Dalam file BUILD.bazel, tiga target ditentukan dengan aturan android_binary, android_library, dan cc_library.
Target tingkat teratas android_binary membangun APK.
Target cc_library berisi satu file sumber C++ dengan implementasi fungsi JNI:
#include <jni.h>
#include <string>
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());
}
Target android_library menentukan sumber Java, file resource, dan
dependensi pada target cc_library. Untuk contoh ini, MainActivity.java memuat
file objek bersama libapp.so, dan menentukan tanda tangan metode untuk fungsi
JNI:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("app");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
}
public native String stringFromJNI();
}
Mengonfigurasi STL
Untuk mengonfigurasi STL C++, gunakan tanda --android_crosstool_top.
bazel build //:app --android_crosstool_top=target labelSTL yang tersedia di @androidndk adalah:
| STL | Label target |
|---|---|
| STLport | @androidndk//:toolchain-stlport |
| libc++ | @androidndk//:toolchain-libcpp |
| gnustl | @androidndk//:toolchain-gnu-libstdcpp |
Untuk r16 dan yang lebih lama, STL default adalah gnustl. Untuk r17 dan yang lebih baru, nilainya adalah
libc++. Untuk mempermudah, target @androidndk//:default_crosstool diberi alias ke STL default masing-masing.
Perlu diperhatikan bahwa mulai r18 dan seterusnya, STLport dan gnustl akan dihapus, sehingga libc++ menjadi satu-satunya STL di NDK.
Lihat dokumentasi NDK untuk mengetahui informasi selengkapnya tentang STL ini.
Mengonfigurasi ABI target
Untuk mengonfigurasi ABI target, gunakan tanda --fat_apk_cpu sebagai berikut:
bazel build //:app --fat_apk_cpu=comma-separated list of ABIsSecara default, Bazel mem-build kode Android native untuk armeabi-v7a. Untuk mem-build untuk x86
(seperti untuk emulator), teruskan --fat_apk_cpu=x86. Untuk membuat APK gemuk untuk beberapa arsitektur, Anda dapat menentukan beberapa CPU: --fat_apk_cpu=armeabi-v7a,x86.
Jika lebih dari satu ABI ditentukan, Bazel akan membuat APK yang berisi objek bersama untuk setiap ABI.
Bergantung pada revisi NDK dan level API Android, ABI berikut tersedia:
| Revisi NDK | ABI |
|---|---|
| 16 dan yang lebih rendah | armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64 |
| 17 ke atas | armeabi-v7a, arm64-v8a, x86, x86_64 |
Lihat dokumen NDK untuk mengetahui informasi selengkapnya tentang ABI ini.
APK Fat Multi-ABI tidak direkomendasikan untuk build rilis karena meningkatkan ukuran APK, tetapi dapat berguna untuk build pengembangan dan QA.
Memilih standar C++
Gunakan tanda berikut untuk membangun sesuai dengan standar C++:
| Standar C++ | Bendera |
|---|---|
| C++98 | Default, tidak memerlukan tanda |
| C++11 | --cxxopt=-std=c++11 |
| C++14 | --cxxopt=-std=c++14 |
Contoh:
bazel build //:app --cxxopt=-std=c++11Baca selengkapnya tentang meneruskan flag compiler dan linker dengan --cxxopt, --copt, dan
--linkopt di Panduan Pengguna.
Flag compiler dan linker juga dapat ditentukan sebagai atribut di cc_library
menggunakan copts dan linkopts. Contoh:
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
copts = ["-std=c++11"],
linkopts = ["-ldl"], # link against libdl
)
Integrasi dengan platform dan toolchain
Model konfigurasi Bazel bergerak menuju
platform dan
toolchain. Jika build Anda menggunakan flag --platforms untuk memilih arsitektur atau sistem operasi yang akan dibangun, Anda harus meneruskan flag --extra_toolchains ke Bazel agar dapat menggunakan NDK.
Misalnya, untuk berintegrasi dengan toolchain android_arm64_cgo yang disediakan oleh
aturan Go, teruskan --extra_toolchains=@androidndk//:all selain flag
--platforms.
bazel build //my/cc:lib \
--platforms=@io_bazel_rules_go//go/toolchain:android_arm64_cgo \
--extra_toolchains=@androidndk//:allAnda juga dapat mendaftarkannya langsung dalam file WORKSPACE:
android_ndk_repository(name = "androidndk")
register_toolchains("@androidndk//:all")
Mendaftarkan toolchain ini akan memberi tahu Bazel untuk mencarinya di file BUILD NDK (untuk NDK 20) saat menyelesaikan batasan arsitektur dan sistem operasi:
toolchain(
name = "x86-clang8.0.7-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:x86_32",
],
toolchain = "@androidndk//:x86-clang8.0.7-libcpp",
)
toolchain(
name = "x86_64-clang8.0.7-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:x86_64",
],
toolchain = "@androidndk//:x86_64-clang8.0.7-libcpp",
)
toolchain(
name = "arm-linux-androideabi-clang8.0.7-v7a-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:arm",
],
toolchain = "@androidndk//:arm-linux-androideabi-clang8.0.7-v7a-libcpp",
)
toolchain(
name = "aarch64-linux-android-clang8.0.7-libcpp_toolchain",
toolchain_type = "@bazel_tools//tools/cpp:toolchain_type",
target_compatible_with = [
"@platforms//os:android",
"@platforms//cpu:aarch64",
],
toolchain = "@androidndk//:aarch64-linux-android-clang8.0.7-libcpp",
)
Cara kerjanya: memperkenalkan transisi konfigurasi Android
Aturan android_binary dapat secara eksplisit meminta Bazel untuk membangun dependensinya dalam konfigurasi yang kompatibel dengan Android sehingga build Bazel berfungsi tanpa tanda khusus, kecuali --fat_apk_cpu dan --android_crosstool_top untuk konfigurasi ABI dan STL.
Di balik layar, konfigurasi otomatis ini menggunakan transisi konfigurasi Android.
Aturan yang kompatibel, seperti android_binary, otomatis mengubah
konfigurasi dependensinya menjadi konfigurasi Android, sehingga hanya
subpohon build khusus Android yang terpengaruh. Bagian lain dari grafik build diproses menggunakan konfigurasi target tingkat teratas. Bahkan, satu target dapat diproses dalam kedua konfigurasi, jika ada jalur melalui grafik build untuk mendukungnya.
Setelah Bazel berada dalam konfigurasi yang kompatibel dengan Android, baik yang ditentukan di tingkat teratas maupun karena titik transisi tingkat yang lebih tinggi, titik transisi tambahan yang ditemui tidak akan mengubah konfigurasi lebih lanjut.
Satu-satunya lokasi bawaan yang memicu transisi ke konfigurasi
Android adalah atribut deps android_binary.
Misalnya, jika Anda mencoba mem-build target android_library dengan dependensi cc_library
tanpa flag apa pun, Anda mungkin mengalami error tentang header JNI yang tidak ada:
ERROR: project/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 <jni.h>
^~~~~~~
1 error generated.
Target //app/src/main:lib failed to build
Use --verbose_failures to see the command lines of failed build steps.
Idealnya, transisi otomatis ini akan membuat Bazel melakukan hal yang benar dalam
sebagian besar kasus. Namun, jika target pada command line Bazel sudah
berada di bawah aturan transisi ini, seperti developer C++ yang menguji
cc_library tertentu, maka --crosstool_top kustom harus digunakan.
Membangun cc_library untuk Android tanpa menggunakan android_binary
Untuk membuat cc_binary atau cc_library mandiri untuk Android tanpa menggunakan
android_binary, gunakan flag --crosstool_top, --cpu, dan --host_crosstool_top.
Contoh:
bazel build //my/cc/jni:target \
--crosstool_top=@androidndk//:default_crosstool \
--cpu=<abi> \
--host_crosstool_top=@bazel_tools//tools/cpp:toolchainDalam contoh ini, target cc_library dan cc_binary tingkat teratas dibuat menggunakan toolchain NDK. Namun, hal ini menyebabkan alat host Bazel sendiri dibangun dengan toolchain NDK (dan dengan demikian untuk Android), karena toolchain host disalin dari toolchain target. Untuk mengatasi masalah ini, tentukan nilai
--host_crosstool_top menjadi @bazel_tools//tools/cpp:toolchain untuk
menetapkan toolchain C++ host secara eksplisit.
Dengan pendekatan ini, seluruh hierarki build akan terpengaruh.
Flag ini dapat dimasukkan ke dalam konfigurasi bazelrc (satu untuk setiap ABI), di
project/.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_<abi> --crosstool_top=@androidndk//:default_crosstool
common:android_<abi> --cpu=<abi>
common:android_<abi> --host_crosstool_top=@bazel_tools//tools/cpp:toolchain
Kemudian, untuk membuat cc_library untuk x86 misalnya, jalankan:
bazel build //my/cc/jni:target --config=android_x86Secara umum, gunakan metode ini untuk target tingkat rendah (seperti cc_library) atau saat
Anda tahu persis apa yang Anda buat; andalkan transisi konfigurasi otomatis
dari android_binary untuk target tingkat tinggi saat Anda berharap
untuk membuat banyak target yang tidak Anda kontrol.