Nếu bạn mới sử dụng Bazel, vui lòng bắt đầu với hướng dẫn Xây dựng Android bằng Bazel.
Tổng quan
Bazel có thể chạy ở nhiều cấu hình bản dựng, trong đó có một số cấu hình sử dụng chuỗi công cụ Android Native Development Kit (NDK). Tức là các quy tắc cc_library
và cc_binary
thông thường có thể được biên dịch trực tiếp cho Android trong Bazel. Bazel thực hiện việc này bằng cách sử dụng quy tắc kho lưu trữ android_ndk_repository
.
Điều kiện tiên quyết
Hãy đảm bảo rằng bạn đã cài đặt SDK và NDK Android.
Để thiết lập SDK và NDK, hãy thêm đoạn mã sau vào WORKSPACE
:
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.
)
Để biết thêm thông tin về quy tắc android_ndk_repository
, hãy xem mục Tạo bách khoa toàn thư.
Nếu bạn đang dùng phiên bản Android NDK gần đây (r22 trở lên), hãy sử dụng phương thức triển khai Starlark của android_ndk_repository
.
Làm theo hướng dẫn trong phần README của ứng dụng đó.
Bắt đầu nhanh
Để tạo C++ cho Android, bạn chỉ cần thêm các phần phụ thuộc cc_library
vào quy tắc android_binary
hoặc android_library
.
Ví dụ: với tệp BUILD
sau đây cho một ứng dụng 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",
)
Tệp BUILD
này dẫn đến biểu đồ mục tiêu sau:
Hình 1. Xây dựng biểu đồ của dự án Android bằng các phần phụ thuộc cc_library.
Để tạo ứng dụng, bạn chỉ cần chạy:
bazel build //app/src/main:app
Lệnh bazel build
biên dịch các tệp Java, tệp tài nguyên Android và các quy tắc cc_library
, đồng thời đóng gói mọi thứ thành một tệp 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 biên dịch tất cả thư viện cc_library thành một tệp đối tượng dùng chung (.so
), được nhắm mục tiêu cho ABI armeabi-v7a
theo mặc định. Để thay đổi chế độ này hoặc bản dựng cho nhiều ABI cùng lúc, hãy xem phần định cấu hình ABI mục tiêu.
Thiết lập mẫu
Ví dụ này có trong kho lưu trữ mẫu Bazel.
Trong tệp BUILD.bazel
, 3 mục tiêu được xác định bằng các quy tắc android_binary
, android_library
và cc_library
.
Mục tiêu cấp cao nhất của android_binary
sẽ tạo APK.
Mục tiêu cc_library
chứa một tệp nguồn C++ duy nhất có hoạt động triển khai hàm 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());
}
Mục tiêu android_library
chỉ định các nguồn Java, tệp tài nguyên và phần phụ thuộc vào mục tiêu cc_library
. Trong ví dụ này, MainActivity.java
tải tệp đối tượng dùng chung libapp.so
và xác định chữ ký phương thức cho hàm JNI:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("app");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
}
public native String stringFromJNI();
}
Định cấu hình ABI đích
Để định cấu hình ABI mục tiêu, hãy sử dụng cờ --android_platforms
như sau:
bazel build //:app --android_platforms=comma-separated list of platforms
Tương tự như cờ --platforms
, giá trị được chuyển đến --android_platforms
là nhãn của các mục tiêu platform
, sử dụng các giá trị ràng buộc tiêu chuẩn để mô tả thiết bị của bạn.
Ví dụ: đối với thiết bị Android có bộ xử lý ARM 64 bit, bạn sẽ xác định nền tảng của mình như sau:
platform(
name = "android_arm64",
constraint_values = [
"@platforms//os:android",
"@platforms//cpu:arm64",
],
)
Mọi platform
trên Android đều phải sử dụng giới hạn hệ điều hành @platforms//os:android
. Để di chuyển quy tắc ràng buộc đối với CPU, hãy xem biểu đồ sau:
Giá trị CPU | Nền tảng |
---|---|
armeabi-v7a |
@platforms//cpu:arm |
arm64-v8a |
@platforms//cpu:arm64 |
x86 |
@platforms//cpu:x86_32 |
x86_64 |
@platforms//cpu:x86_64 |
Và tất nhiên, đối với APK đa kiến trúc, bạn sẽ chuyển nhiều nhãn, ví dụ: --android_platforms=//:arm64,//:x86_64
(giả sử bạn đã xác định các nhãn đó trong tệp BUILD.bazel
cấp cao nhất).
Bazel không thể chọn một nền tảng Android mặc định, vì vậy, một nền tảng phải được xác định và chỉ định bằng --android_platforms
.
Tuỳ thuộc vào bản sửa đổi NDK và cấp độ API Android, bạn có thể sử dụng các ABI sau:
Bản sửa đổi NDK | ABI |
---|---|
16 trở xuống | armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64 |
17 trở lên | armeabi-v7a, arm64-v8a, x86, x86_64 |
Hãy xem tài liệu về NDK để biết thêm thông tin về các ABI này.
Bạn không nên sử dụng tệp APK nhiều ABI cho bản phát hành vì chúng làm tăng kích thước của tệp APK, nhưng có thể hữu ích cho hoạt động phát triển và bản dựng đảm bảo chất lượng.
Chọn một tiêu chuẩn C++
Sử dụng các cờ sau để xây dựng theo tiêu chuẩn C++:
Tiêu chuẩn C++ | Cờ |
---|---|
C++98 | Mặc định, không cần gắn cờ |
C++11 | --cxxopt=-std=c++11 |
C++14 | --cxxopt=-std=c++14 |
C++17 | --cxxopt=-std=c++17 |
Ví dụ:
bazel build //:app --cxxopt=-std=c++11
Đọc thêm về cách truyền cờ trình biên dịch và trình liên kết bằng --cxxopt
, --copt
và --linkopt
trong Hướng dẫn sử dụng.
Bạn cũng có thể chỉ định cờ trình biên dịch và trình liên kết làm các thuộc tính trong cc_library
bằng cách sử dụng copts
và linkopts
. Ví dụ:
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
copts = ["-std=c++11"],
linkopts = ["-ldl"], # link against libdl
)
Tạo cc_library
cho Android mà không cần sử dụng android_binary
Để tạo một cc_binary
hoặc cc_library
độc lập cho Android mà không cần sử dụng android_binary
, hãy sử dụng cờ --platforms
.
Ví dụ: giả sử bạn đã xác định các nền tảng Android trong my/platforms/BUILD
:
bazel build //my/cc/jni:target \
--platforms=//my/platforms:x86_64
Với phương pháp này, toàn bộ cây bản dựng sẽ bị ảnh hưởng.
Bạn có thể đặt những cờ này vào cấu hình bazelrc
(một cờ cho mỗi ABI) trong 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>
Sau đó, để tạo cc_library
cho x86
, ví dụ: hãy chạy:
bazel build //my/cc/jni:target --config=android_x86
Nhìn chung, hãy sử dụng phương thức này cho các mục tiêu cấp thấp (như cc_library
) hoặc khi bạn biết chính xác bạn đang xây dựng gì; hãy dựa vào quá trình chuyển đổi cấu hình tự động từ android_binary
cho các mục tiêu cấp cao mà bạn đang muốn tạo nhiều mục tiêu mà bạn không kiểm soát.