Bazel ile Android Yerel Geliştirme Kiti'ni kullanma

. Sorun bildirin Kaynağı göster Gece · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Bazel'i kullanmaya yeni başladıysanız lütfen Google ile Android Oluşturma Bazel eğitimi.

Genel Bakış

Bazel, birçok farklı derleme yapılandırmasında çalışabilir. Bunlardan bazıları, Android Yerel Geliştirme Kiti (NDK) araç zincirini kullanıyor. Bu, normal verilerin cc_library ve cc_binary kuralları doğrudan Android için derlenebilir Bazel. Bazel, bu işlemi android_ndk_repository deposunu kullanarak gerçekleştirir kuralı.

Ö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 bkz. Oluşturma Ansiklopedi girişi.

Android NDK'nın son sürümünü (r22 ve sonrası) kullanıyorsanız android_ndk_repository için Starlark uygulaması. Şu adresteki talimatları uygulayın: BENİ OKU

Hızlı başlangıç

Android için C++ geliştirmek üzere hesabınıza cc_library bağımlılıkları eklemeniz android_binary veya android_library kuralları.

Ö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:

Örnek sonuçlar

Ş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 adlı dosyaları tek bir paylaşılan nesne (.so) dosyasında derler, varsayılan olarak armeabi-v7a ABI için hedeflenir. 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 ile üç hedef tanımlanmıştır. android_library ve cc_library kuralları.

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 bağımlılık. 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 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 ü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.

18. sürümden itibaren STLport ve gnustl'ın , Böylece libc++, NDK'daki tek STL'dir.

NDK'ya göz atın belgeleri 'na göz atın.

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 derleme (örneğin emülatörler için) --fat_apk_cpu=x86 değerini geçirin. 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 düzeltmesine ve Android API düzeyine bağlı olarak aşağıdaki ABI'ler şunlardır: mevcut:

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

NDK dokümanlarına göz atın bu ABI'ler hakkında daha fazla bilgi edinin.

Ç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

--cxxopt, --copt ve bağlayıcı işaretleriyle derleyici ve bağlayıcı işaretlerini iletme hakkında daha fazla bilgi Kullanıcı Kılavuzu'ndaki --linkopt

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ç zincirleri gibidir. 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, Google Etiket Yöneticisi'nin sağladığı android_arm64_cgo araç zinciriyle entegrasyon emin olmak için, aşağıdaki kurallara ek olarak --extra_toolchains=@androidndk//:all --platforms işareti.

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'dan Android ile uyumlu bir yapılandırma, böylece Bazel derlemesinin arka arkaya çalışması için için --fat_apk_cpu ve --android_crosstool_top haricindeki tüm özel işaretler ABI ve STL yapılandırması.

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'e geçişi tetikleyen tek yerleşik konum yapılandırma, android_binary öğesinin deps özelliğidir.

Örneğin, cc_library ile android_library hedefi oluşturmaya çalışırsanız bağımlılığınız yoksa eksik bir JNI hatasıyla ilgili üstbilgi:

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 neden olur. Ancak, Bazel komut satırındaki hedef zaten belirli bir geçiş kurallarını test eden C++ geliştiricileri gibi, cc_library, ardından ö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 oluşturulmuştur. çok kolay bir şekilde yapabilirsiniz. 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 tüm yapı ağacı 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

Bu yöntemi genellikle düşük düzeyli hedefler (ör. cc_library) için veya tam olarak ne inşa ettiğinizi bilirsiniz. her gün otomatik olarak beklediğinizden daha üst düzey hedefler için android_binary kontrol edemediğiniz çok sayıda hedef oluşturmanıza yardımcı olur.