Bazel'i kullanmaya yeni başladıysanız lütfen Bazel ile Android Oluşturma eğitimiyle başlayın.
Genel bakış
Bazel, Android Yerel Geliştirme Kiti (NDK) araç zincirini kullanan birkaç yapılandırma da dahil olmak üzere birçok farklı derleme yapılandırmasında çalışabilir. Bu, normal cc_library
ve cc_binary
kurallarının Android için doğrudan Bazel'da derlenebileceği anlamına gelir. Bazel, bu işlemi android_ndk_repository
deposu kuralını kullanarak gerçekleştirir.
Ön koşullar
Lütfen Android SDK ve NDK'yı yüklediğinizden emin olun.
SDK ve NDK'yı ayarlamak için WORKSPACE
cihazınıza aşağıdaki snippet'i ekleyin:
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.
)
android_ndk_repository
kuralı hakkında daha fazla bilgi için Derleme Ansiklopedisi girişi bölümüne bakın.
Android NDK'nın son sürümünü (r22 ve sonrası) kullanıyorsanız android_ndk_repository
Starlark uygulamasını kullanın.
BENİ OKU bölümündeki talimatları uygulayın.
Hızlı başlangıç
Android için C++ geliştirmek üzere android_binary
veya android_library
kurallarınıza cc_library
bağımlılıkları eklemeniz yeterlidir.
Örneğin, bir Android uygulaması için aşağıdaki BUILD
dosyasını ele alalım:
# 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",
)
Bu BUILD
dosyası, aşağıdaki hedef grafikle sonuçlanır:
Şekil 1. cc_library bağımlılarını içeren Android projesinin grafiğini oluşturma
Uygulamayı derlemek için şu komutu çalıştırın:
bazel build //app/src/main:app
bazel build
komutu Java dosyalarını, Android kaynak dosyalarını ve cc_library
kurallarını derler ve her şeyi bir APK şeklinde paketler:
$ 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, tüm cc_libraries adlı dosyaları tek bir paylaşılan nesne (.so
) dosyasında derler ve varsayılan olarak armeabi-v7a
ABI'yi hedefler. Bunu değiştirmek veya aynı anda birden fazla ABI için derleme yapmak istiyorsanız hedef ABI'yi yapılandırma bölümüne bakın.
Örnek kurulum
Bu örnek, Bazel örnekleri deposunda bulunmaktadır.
BUILD.bazel
dosyasında android_binary
, android_library
ve cc_library
kurallarıyla üç hedef tanımlanmıştır.
APK'yı üst düzey android_binary
hedefi oluşturur.
cc_library
hedefi, JNI işlevi uygulamasına sahip tek bir C++ kaynak dosyası içerir:
#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());
}
android_library
hedefi; Java kaynaklarını, kaynak dosyalarını ve bir cc_library
hedefine bağımlılığı belirtir. Bu örnekte MainActivity.java
, libapp.so
paylaşılan nesne dosyasını yükler ve JNI işlevi için yöntem imzasını tanımlar:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("app");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
}
public native String stringFromJNI();
}
STL'yi yapılandırma
C++ STL'yi yapılandırmak için --android_crosstool_top
işaretini kullanın.
bazel build //:app --android_crosstool_top=target label
@androidndk
içinde kullanılabilen STL'ler:
STL | Hedef etiket |
---|---|
STLport | @androidndk//:toolchain-stlport |
libc++ | @androidndk//:toolchain-libcpp |
Gnustl | @androidndk//:toolchain-gnu-libstdcpp |
r16 ve önceki sürümler için varsayılan STL gnustl
'dir. r17 ve sonraki sürümlerde libc++
. Kolaylık sağlaması açısından, @androidndk//:default_crosstool
hedefi ilgili varsayılan STL'lerle eşleştirilmektedir.
18 sürümünden itibaren STLport ve gnustl'ın kaldırılacağını, dolayısıyla libc++
ürününün NDK'daki tek STL olacağını lütfen unutmayın.
Bu STL'ler hakkında daha fazla bilgi için NDK belgelerini inceleyin.
Hedef ABI'yı yapılandırma
Hedef ABI'yı yapılandırmak için --fat_apk_cpu
işaretini aşağıdaki şekilde kullanın:
bazel build //:app --fat_apk_cpu=comma-separated list of ABIs
Varsayılan olarak Bazel, armeabi-v7a
için yerel Android kodu oluşturur. x86 için derlemek
(örneğin emülatörlerde) için --fat_apk_cpu=x86
değerini iletin. Birden fazla mimari için yağ APK'sı oluşturmak isterseniz birden fazla CPU belirtebilirsiniz: --fat_apk_cpu=armeabi-v7a,x86
.
Birden fazla ABI belirtilirse Bazel, her ABI için paylaşılan nesne içeren bir APK oluşturur.
NDK düzeltmesine ve Android API düzeyine bağlı olarak aşağıdaki ABI'ler kullanılabilir:
NDK düzeltmesi | ABI'lar |
---|---|
16 ve altı | armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64 |
17 ve üzeri | armeabi-v7a, arm64-v8a, x86, x86_64 |
Bu ABI'ler hakkında daha fazla bilgi için NDK dokümanlarına bakın.
Çoklu ABI Yağ APK'ları, APK'nın boyutunu artırdığından sürüm derlemeleri için önerilmez ancak geliştirme ve QA derlemeleri için yararlı olabilir.
C++ standardı seçme
C++ standardına göre derleme yapmak için aşağıdaki flag'leri kullanın:
C++ Standart | İşaret |
---|---|
C++98 | Varsayılan, işaret gerekmez |
C++11 | --cxxopt=-std=c++11 |
C++14 | --cxxopt=-std=c++14 |
Örneğin:
bazel build //:app --cxxopt=-std=c++11
Kullanıcı Kılavuzu'nda derleyici ve bağlayıcı işaretlerini --cxxopt
, --copt
ve --linkopt
ile iletme hakkında daha fazla bilgi edinin.
Derleyici ve bağlayıcı işaretleri, copts
ve linkopts
kullanılarak cc_library
içinde özellik olarak da belirtilebilir. Örneğin:
cc_library(
name = "jni_lib",
srcs = ["cpp/native-lib.cpp"],
copts = ["-std=c++11"],
linkopts = ["-ldl"], # link against libdl
)
Platformlar ve araç zincirleriyle entegrasyon
Bazel'in yapılandırma modeli platformlar ve araç zincirlerine taşınıyor. Derlemenizde, derleme yapılacak mimariyi veya işletim sistemini seçmek için --platforms
işaretini kullanıyorsa NDK'yı kullanmak için --extra_toolchains
işaretini Bazel'a iletmeniz gerekir.
Örneğin, Go kuralları tarafından sağlanan android_arm64_cgo
araç zinciriyle entegrasyon yapmak için --platforms
işaretine ek olarak --extra_toolchains=@androidndk//:all
değerini de iletin.
bazel build //my/cc:lib \
--platforms=@io_bazel_rules_go//go/toolchain:android_arm64_cgo \
--extra_toolchains=@androidndk//:all
Bunları doğrudan WORKSPACE
dosyasına da kaydedebilirsiniz:
android_ndk_repository(name = "androidndk")
register_toolchains("@androidndk//:all")
Bu araç zincirlerinin kaydedilmesi, Bazel'e mimari ve işletim sistemi kısıtlamalarını çözümlerken onları NDK BUILD
dosyasında (NDK 20 için) aramasını söyler:
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",
)
İşleyiş şekli: Android yapılandırma geçişleri tanıtımı
android_binary
kuralı, Bazel'dan bağımlılıklarını Android uyumlu bir yapılandırmada oluşturmasını açık bir şekilde isteyebilir. Böylece, Bazel derlemesi ABI ve STL yapılandırması için --fat_apk_cpu
ve --android_crosstool_top
hariç herhangi bir özel işaret olmadan çalışmak için kullanılır.
Bu otomatik yapılandırma, perde arkasında Android yapılandırma geçişlerini kullanır.
android_binary
gibi uyumlu bir kural, bağımlılarının yapılandırmasını otomatik olarak bir Android yapılandırmasıyla değiştirir. Bu nedenle, derlemenin yalnızca Android'e özgü alt ağaçları etkilenir. Derleme grafiğinin diğer bölümleri, üst düzey hedef yapılandırması kullanılarak işlenir. Derleme grafiğinde bir hedefi destekleyen yollar varsa her iki yapılandırmada da tek bir hedefi işleyebilir.
Bazel, en üst düzeyde veya daha üst düzeydeki bir geçiş noktası nedeniyle Android ile uyumlu bir yapılandırmaya sahip olduğunda, karşılaşılan ek geçiş noktaları yapılandırmada başka değişiklik yapmaz.
Android yapılandırmasına geçişi tetikleyen tek yerleşik konum android_binary
ürününün deps
özelliğidir.
Örneğin, herhangi bir işaret olmadan cc_library
bağımlılığına sahip bir android_library
hedefi oluşturmaya çalışırsanız eksik bir JNI üstbilgisiyle ilgili hatayla karşılaşabilirsiniz:
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.
İdeal olarak, bu otomatik geçişler Bazel'in çoğu durumda doğru şeyi yapmasını sağlamalıdır. Bununla birlikte, belirli bir cc_library
testini test eden C++ geliştiricileri gibi Bazel komut satırındaki hedef zaten bu geçiş kurallarından herhangi birinin altındaysa özel bir --crosstool_top
kullanılmalıdır.
android_binary
kullanmadan Android için cc_library
oluşturma
android_binary
kullanmadan Android için bağımsız bir cc_binary
veya cc_library
oluşturmak isterseniz --crosstool_top
, --cpu
ve --host_crosstool_top
işaretlerini kullanın.
Örneğin:
bazel build //my/cc/jni:target \
--crosstool_top=@androidndk//:default_crosstool \
--cpu=<abi> \
--host_crosstool_top=@bazel_tools//tools/cpp:toolchain
Bu örnekte, üst düzey cc_library
ve cc_binary
hedefleri NDK araç zinciri kullanılarak oluşturulmuştur. Ancak bu, ana makine araç zincirinin hedef araç zincirinden kopyalanmasından dolayı Bazel'in kendi ana makine araçlarının NDK araç zinciriyle (ve dolayısıyla Android için) derlenmesine neden olur. Bu sorunu çözmek için --host_crosstool_top
değerini @bazel_tools//tools/cpp:toolchain
olarak belirtin ve ana makinenin C++ araç zincirini açıkça ayarlayın.
Bu yaklaşımda tüm yapı ağacı etkilenir.
Bu işaretler, project/.bazelrc
içinde bir bazelrc
yapılandırmasına (her ABI için bir adet) yerleştirilebilir:
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
Ardından, örneğin x86
için bir cc_library
oluşturmak üzere şu komutu çalıştırın:
bazel build //my/cc/jni:target --config=android_x86
Genel olarak, bu yöntemi cc_library
gibi alt düzey hedefler için veya ne oluşturduğunuzu tam olarak bildiğiniz durumlarda kullanın. Kontrol etmediğiniz çok sayıda hedef oluşturmayı beklediğiniz üst düzey hedefler için android_binary
tarafından yapılan otomatik yapılandırma geçişlerini kullanın.