Bazel'i kullanmaya yeni başladıysanız lütfen Bazel ile Android oluşturma eğiticisiyle 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, bunu android_ndk_repository
deposu kuralını kullanarak gerçekleştirir.
Ö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 aşağıdaki snippet'i WORKSPACE
cihazınıza 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 Ansiklopedi Oluşturma girişi'ne bakın.
Hızlı başlangıç
Android için C++ oluşturmak 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ı göz önünde bulundurulduğunda:
# 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ı şu hedef grafiğinle sonuçlanıyor:
Şekil 1. cc_library bağımlılıkları ile Android projesinin grafiğini oluşturun.
Uygulamayı oluşturmak için şu komutu çalıştırmanız yeterlidir:
bazel build //app/src/main:app
bazel build
komutu; Java dosyalarını, Android kaynak dosyalarını ve cc_library
kurallarını derleyip her şeyi bir APK'da 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 öğelerini varsayılan olarak armeabi-v7a
ABI'yı hedefleyen tek bir paylaşılan nesne (.so
) dosyasında derler. Bunu değiştirmek veya aynı anda birden çok ABI oluşturmak için hedef ABI'yi yapılandırma bölümüne bakın.
Örnek kurulum
Bu örneği Bazel örnekleri deposunda bulabilirsiniz.
BUILD.bazel
dosyasında android_binary
, android_library
ve cc_library
kurallarıyla üç hedef tanımlanır.
APK'yı android_binary
üst düzey 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
bölgesinde kullanılabilen STL'ler şunlardır:
STL | Hedef etiket |
---|---|
STLport | @androidndk//:toolchain-stlport |
libc++ | @androidndk//:toolchain-libcpp |
Gnustl | @androidndk//:toolchain-gnu-libstdcpp |
r16 ve altı için varsayılan STL gnustl
'dir. r17 ve sonraki sürümler için bu değer libc++
şeklindedir. Kolaylık sağlamak amacıyla @androidndk//:default_crosstool
hedefi, ilgili varsayılan STL'ler ile tasfiye edilir.
r18'den itibaren STLport ve gnustl'ın kaldırılacağını ve böylece libc++
'nin NDK'daki tek STL'yi oluşturacağı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'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 amacıyla (ör. emülatörler için) --fat_apk_cpu=x86
aktarın. Birden fazla mimari için yağ APK 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 belgelerine bakın.
Multi-ABI Fat APK'ları, APK'nın boyutunu büyüttükleri için sürüm derlemeleri için önerilmez, ancak geliştirme ve KG derlemeleri için yararlı olabilirler.
C++ standardı seçme
C++ standardına göre derlemek için aşağıdaki işaretleri 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 --cxxopt
, --copt
ve --linkopt
ile derleyici ve bağlayıcı işaretlerini 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, platformlara ve araç zincirlerine doğru hareket etmektedir. Derlemeniz, geliştirme yapılacak mimari veya işletim sistemi için seçim yapmak üzere --platforms
işaretini kullanıyorsa NDK'yı kullanabilmek için --extra_toolchains
işaretini Bazel'e iletmeniz gerekir.
Örneğin, Go kuralları tarafından sağlanan android_arm64_cgo
araç zinciriyle entegrasyon yapmak için --platforms
işaretinin yanı sıra --extra_toolchains=@androidndk//:all
değerini de geçirin.
bazel build //my/cc:lib \
--platforms=@io_bazel_rules_go//go/toolchain:android_arm64_cgo \
--extra_toolchains=@androidndk//:all
Dilerseniz 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 bunları NDK BUILD
dosyasında (NDK 20 için) aramasını bildirir:
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şlerini kullanıma sunuyoruz
android_binary
kuralı, Bazel'dan bağımlılıklarını Android uyumlu bir yapılandırmada oluşturmasını açıkça isteyebilir. Böylece Bazel derlemesi, ABI ve STL yapılandırması için --fat_apk_cpu
ve --android_crosstool_top
dışında herhangi bir özel işaret olmadan tamamen çalışı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ılıklarının yapılandırmasını otomatik olarak Android yapılandırmasıyla değiştirir. Bu nedenle, derlemenin yalnızca Android'e özel alt ağaçları etkilenir. Derleme grafiğinin diğer bölümleri, üst düzey hedef yapılandırması kullanılarak işlenir. Oluşturma grafiğinde bunu destekleyecek yollar varsa her iki yapılandırmada da tek bir hedefi işleyebilir.
Bazel en üst düzeyde belirtilmiş veya daha üst seviyedeki bir geçiş noktası nedeniyle Android uyumlu bir yapılandırmaya ulaştığında, karşılaşılan ek geçiş noktaları yapılandırmayı değiştirmez.
Android yapılandırmasına geçişi tetikleyen tek yerleşik konum, android_binary
uygulaması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 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şlerin Bazel'in vakaların çoğunda doğru olanı yapmasını sağlaması gerekir. Ancak Bazel komut satırındaki hedef bu geçiş kurallarından herhangi birinin zaten altındaysa (örneğin, belirli bir cc_library
öğesini test eden C++ geliştiricilerinin) ö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 istiyorsanız --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ı nedeniyle, Bazel'in kendi ana makine araçlarının NDK araç zinciriyle (ve dolayısıyla Android için) oluşturulmasına neden olur. Bu sorunu gidermek için ana makinenin C++ araç zincirini açıkça ayarlamak üzere --host_crosstool_top
değerini @bazel_tools//tools/cpp:toolchain
olacak şekilde belirtin.
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 tane) eklenebilir:
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 seviyeli hedefler (cc_library
gibi) için veya ne geliştirdiğinizi tam olarak biliyorsanız kullanın. Kontrol etmediğiniz çok sayıda hedef oluşturmayı beklediğiniz üst düzey hedefler için android_binary
ürününden yapılan otomatik yapılandırma geçişlerini kullanın.