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
dan ekstensi bzlmod terkait.
Untuk kompilasi Android umum, gunakan rules_android
.
Tutorial ini menunjukkan cara mengintegrasikan dependensi library C++ ke dalam
aplikasi Android dan menggunakan
rules_android_ndk
untuk penemuan dan pendaftaran toolchain NDK.
Prasyarat
Pastikan Anda telah menginstal Android SDK dan NDK.
Penyiapan NDK dan SDK
Penyiapan repositori eksternal bervariasi bergantung pada apakah Anda menggunakan WORKSPACE atau bzlmod (MODULE.bazel). Bzlmod adalah solusi yang lebih disukai untuk Bazel 7+. Perhatikan bahwa stanza penyiapan MODULE.bazel dan WORKSPACE tidak bergantung satu sama lain. Jika Anda menggunakan satu solusi pengelolaan dependensi, Anda tidak perlu menambahkan boilerplate untuk solusi lainnya.
Penyiapan MODULE.bazel Bzlmod
Tambahkan cuplikan berikut ke MODULE.bazel Anda:
# NDK
bazel_dep(name = "rules_android_ndk", version = "0.1.3")
android_ndk_repository_extension = use_extension("@rules_android_ndk//:extension.bzl", "android_ndk_repository_extension")
use_repo(android_ndk_repository_extension, "androidndk")
register_toolchains("@androidndk//:all")
# SDK
bazel_dep(name = "rules_android", version = "0.6.6")
register_toolchains(
"@rules_android//toolchains/android:android_default_toolchain",
"@rules_android//toolchains/android_sdk:android_sdk_tools",
)
android_sdk_repository_extension = use_extension("@rules_android//rules/android_sdk_repository:rule.bzl", "android_sdk_repository_extension")
use_repo(android_sdk_repository_extension, "androidsdk")
register_toolchains("@androidsdk//:sdk-toolchain", "@androidsdk//:all")
Penyiapan WORKSPACE lama
Tambahkan cuplikan berikut ke WORKSPACE
Anda:
load("@rules_android//rules:rules.bzl", "android_sdk_repository")
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.
)
load("@rules_android_ndk//:rules.bzl", "android_ndk_repository")
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.
)
Catatan kompatibilitas untuk WORKSPACE:
- Aturan
rules_android
danrules_android_ndk
memerlukan boilerplate tambahan yang tidak digambarkan dalam cuplikan RUANG KERJA di atas. Untuk stanza instansiasi yang terbaru dan lengkap, lihat file WORKSPACE dari aplikasi contoh dasarrules_android_ndk
.
Untuk mengetahui informasi selengkapnya tentang aturan android_ndk_repository
, lihat
docstring-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
load("@rules_cc//cc:cc_library.bzl", "cc_library")
load("@rules_android//rules:rules.bzl", "android_binary", "android_library")
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:app --android_platforms=<your platform>
Perhatikan bahwa jika Anda tidak menentukan --android_platforms
, build Anda akan gagal dengan
error tentang header JNI yang tidak ada.
Perintah 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.MF
Bazel mengompilasi semua cc_library menjadi satu file objek bersama (.so
),
yang menargetkan arsitektur yang ditentukan oleh --android_platforms
.
Lihat bagian tentang mengonfigurasi ABI target untuk
mengetahui detail selengkapnya.
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 ABI target
Untuk mengonfigurasi ABI target, gunakan tanda --android_platforms
sebagai berikut:
bazel build //:app --android_platforms=comma-separated list of platforms
Sama seperti tanda --platforms
, nilai yang diteruskan ke --android_platforms
adalah
label target platform
, menggunakan nilai batasan standar untuk mendeskripsikan perangkat Anda.
Misalnya, untuk perangkat Android dengan prosesor ARM 64-bit, Anda akan menentukan platform seperti ini:
platform(
name = "android_arm64",
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:arm64",
],
)
Setiap platform
Android harus menggunakan batasan OS @platforms//os:android
. Untuk memigrasikan batasan CPU, lihat diagram ini:
Nilai CPU | Platform |
---|---|
armeabi-v7a |
@platforms//cpu:armv7 |
arm64-v8a |
@platforms//cpu:arm64 |
x86 |
@platforms//cpu:x86_32 |
x86_64 |
@platforms//cpu:x86_64 |
Dan, tentu saja, untuk APK multiarsitektur, Anda meneruskan beberapa label, misalnya: --android_platforms=//:arm64,//:x86_64
(dengan asumsi Anda menentukannya dalam file BUILD.bazel
tingkat teratas).
Bazel tidak dapat memilih platform Android default, jadi platform harus ditentukan dan
ditentukan dengan --android_platforms
.
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 |
C++17 | --cxxopt=-std=c++17 |
Contoh:
bazel build //:app --cxxopt=-std=c++11
Baca 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
)
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 --platforms
.
Misalnya, dengan asumsi Anda telah menentukan platform Android di
my/platforms/BUILD
:
bazel build //my/cc/jni:target \
--platforms=//my/platforms:x86_64
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 --platforms=//my/platforms:x86
common:android_armeabi-v7a --platforms=//my/platforms:armeabi-v7a
# In general
common:android_<abi> --platforms=//my/platforms:<abi>
Kemudian, untuk membuat cc_library
untuk x86
misalnya, jalankan:
bazel build //my/cc/jni:target --config=android_x86
Secara umum, gunakan metode ini untuk target tingkat rendah (seperti cc_library
) atau saat
Anda tahu persis apa yang Anda bangun; andalkan transisi konfigurasi otomatis
dari android_binary
untuk target tingkat tinggi saat Anda berharap
untuk membangun banyak target yang tidak Anda kontrol.