Bazel'i kullanmaya yeni başladıysanız lütfen ile Android Geliştirme Bazel eğitimi.
Genel Bakış
Bazel, birçok farklı derleme yapılandırmasında çalışabilir. Bunlardan bazıları,
test edildi. Bu, normal verilerin
cc_library
ve cc_binary
kuralları, Android için doğrudan
Bazel. Bazel, bu işlemi android_ndk_repository
deposunu kullanarak gerçekleştirir
tıklayın.
Ön koşullar
Lütfen Android SDK'sını ve NDK'yı yüklediğinizden emin olun.
SDK'yı ve NDK'yı ayarlamak için WORKSPACE
dosyanı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 bkz. Oluşturma
Ansiklopedi girişi.
Android NDK'nın son sürümünü (r22 ve sonraki sürümler) kullanıyorsanız android_ndk_repository
için Starlark uygulamasını kullanın.
README dosyasında yer alan talimatları uygulayın.
Hızlı başlangıç
Android için C++ derlemek istiyorsanız 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ı verilmiştir:
# 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
kural oluşturuyor ve her şeyi bir APK olarak 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 dosyalarını varsayılan olarak armeabi-v7a
ABI için hedeflenen tek bir paylaşılan nesne (.so
) dosyasında derleyebilir. Bunu değiştirmek veya
için birden fazla ABI'yi kullanıyorsanız hedefi yapılandırma
ABI değerleridir.
Örnek kurulum
Bu örnek, Bazel örneklerinde depo.
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şlevine sahip tek bir C++ kaynak dosyası içeriyor
uygulama:
#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 cc_library
hedefine olan bağımlılığı belirtir. Bu örnekte, MainActivity.java
yüklenir
libapp.so
adlı paylaşılan nesne dosyasını kullanır ve JNI için yöntem imzasını tanımlar
işlev:
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
'te kullanılabilen STL'ler şunlardır:
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 üzeri sürümlerde
libc++
Kolaylık sağlaması açısından hedef @androidndk//:default_crosstool
diğer adı ilgili varsayılan STL'lere atanır.
r18'den itibaren STLport ve gnustl'nin kaldırılacağını, bu nedenle NDK'da yalnızca libc++
STL'sinin kullanılabileceğini lütfen unutmayın.
NDK'ya göz atın belgeleri 'na bakın.
Hedef ABI'yi yapılandırma
Hedef ABI'yi yapılandırmak için --fat_apk_cpu
işaretini aşağıdaki gibi 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 istiyorsanız (ör. emülatörler için) --fat_apk_cpu=x86
değerini iletin. Birden fazla APK için yağ APK'sı
birden fazla CPU belirtebilirsiniz: --fat_apk_cpu=armeabi-v7a,x86
.
Birden fazla ABI belirtilirse Bazel, paylaşılan bir ABI içeren APK nesnesini ifade eder.
NDK revizyonuna ve Android API düzeyine bağlı olarak aşağıdaki ABI'ler kullanılabilir:
NDK sürümü | ABI'lar |
---|---|
16 yaş 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 belgelerine bakın.
Çoklu ABI Yağ APK'ları, yayın derlemeleri için önerilmez çünkü APK'nın boyutunu değiştirebilir ancak geliştirme ve KG 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
Derleyici ve bağlayıcı işaretlerini --cxxopt
, --copt
ve --linkopt
ile iletme hakkında daha fazla bilgiyi Kullanıcı Kılavuzu'nda bulabilirsiniz.
Derleyici ve bağlayıcı işaretleri, cc_library
özelliğinde özellik olarak da belirtilebilir.
copts
ve linkopts
kullanılıyor. Ö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 doğru ilerliyor. Eğer
derleme, mimari veya işletim sistemini seçmek için --platforms
işaretini kullanır
--extra_toolchains
işaretini Bazel'e iletmeniz ve
NDK'yı kullanmak için yeterli.
Örneğin, Go kuralları tarafından sağlanan android_arm64_cgo
araç setiyle entegrasyon yapmak için --platforms
işaretçisine ek olarak --extra_toolchains=@androidndk//:all
işaretçisini 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ç zincirlerini kaydettiğinizde, Bazel bunları NDK'da BUILD
dosyasını (NDK 20 için) kopyalayın:
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'den bağımlılıklarını Android uyumlu bir yapılandırmada derlemesini açıkça 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 sadece çalışır.
Perde arkasında bu otomatik yapılandırma, Android config değiştirilebilir.
android_binary
gibi uyumlu bir kural,
Android yapılandırmasına bağımlıların yapılandırılması. Bu nedenle,
Derlemenin Android'e özgü alt ağaçları bu durumdan etkilenmektedir. Yapının diğer bölümleri
grafiği, üst düzey hedef yapılandırması kullanılarak işlenir. Hatta bir sürü
Bir hedefe giden yollar varsa her iki yapılandırmada da tek bir hedef işleme
bir yapı grafiği oluşturacaksınız.
Bazel, veya daha üst düzeyde bir geçiş noktası nedeniyle yapılandırmada başka değişiklik yapmaz.
Android yapılandırmasına geçişi tetikleyen tek yerleşik konum, android_binary
'ın deps
özelliğidir.
Örneğin, cc_library
bağımlığı olan bir android_library
hedefini herhangi bir işaret olmadan oluşturmaya çalışırsanız eksik JNI başlığıyla ilgili bir 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ğlar. Ancak Bazel komut satırındaki hedef, bu geçiş kurallarının herhangi birinin altındaysa (ör. C++ geliştiricileri belirli bir cc_library
'ü test ediyorsa) özel bir --crosstool_top
kullanılmalıdır.
android_binary
kullanmadan Android için cc_library
oluşturma
Bir uygulama kullanmadan Android için bağımsız bir cc_binary
veya cc_library
oluşturmak istiyorsanız
android_binary
, --crosstool_top
, --cpu
ve --host_crosstool_top
kullanın
işaretidir.
Ö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 derlenir. Ancak bu, Bazel'ın kendi barındırma araçlarının oluşturulmasına neden olur.
olması nedeniyle, ana makine araç zincirinin
hedef araç zincirinden kopyalanır. Bu sorunu çözmek için
@bazel_tools//tools/cpp:toolchain
olarak --host_crosstool_top
ana makinenin C++ araç zincirini açık bir şekilde ayarlamanız gerekir.
Bu yaklaşımda derleme ağacının tamamı etkilenir.
Bu flag'ler bir bazelrc
yapılandırmasına (her ABI için bir adet) yerleştirilebilir.
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
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 düşük düzey hedefler (cc_library
gibi) için veya tam olarak ne oluşturduğunuzu bildiğiniz durumlarda kullanın. Kontrol etmediğiniz çok sayıda hedef oluşturmayı beklediğiniz yüksek düzey hedefler için android_binary
'ten otomatik yapılandırma geçişlerine güvenin.