Bazel ile Android Yerel Geliştirme Kiti'ni kullanma

Sorun bildir Kaynağı görüntüleyin Nightly · 7.4 .

Bazel'i kullanmaya yeni başladıysanız lütfen Bazel ile Android geliştirme eğitimiyle başlayın.

Genel Bakış

Bazel, Android Native Development Kit (NDK) araç zincirini kullananlar 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 depo kuralını kullanarak yapar.

Ö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 Build Ansiklopedisi girişine bakın.

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:

Örnek sonuçlar

Şekil 1. cc_library bağımlılıkları olan Android projesinin grafiğini oluşturun.

Uygulamayı derlemek için şunları ç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'ya 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'yi hedefleyen tek bir paylaşılan nesne (.so) dosyasında derleyebilir. 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 yer almaktadır.

BUILD.bazel dosyasında android_binary, android_library ve cc_library kurallarıyla üç hedef tanımlanmıştır.

android_binary üst düzey hedefi APK'yı oluşturur.

cc_library hedefi, JNI işlev uygulamasını içeren 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 cc_library hedefine olan bağımlılığı belirtir. Bu örnekte MainActivity.java, paylaşılan nesne dosyasını libapp.so yükler ve JNI işlevinin 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();

}

Hedef ABI'yi yapılandırma

Hedef ABI'yi yapılandırmak için --android_platforms işaretini aşağıdaki gibi kullanın:

bazel build //:app --android_platforms=comma-separated list of platforms

--platforms işareti gibi, --android_platforms'a iletilen değerler de cihazınızı tanımlamak için standart kısıtlama değerlerini kullanan platform hedeflerinin etiketleridir.

Örneğin, 64 bit ARM işlemciye sahip bir Android cihaz için platformunuzu şu şekilde tanımlarsınız:

platform(
    name = "android_arm64",
    constraint_values = [
        "@platforms//os:android",
        "@platforms//cpu:arm64",
    ],
)

Her Android platform, @platforms//os:android OS kısıtlamasını kullanmalıdır. CPU kısıtlamasını taşımak için bu grafiği kontrol edin:

CPU Değeri Platform
armeabi-v7a @platforms//cpu:armv7
arm64-v8a @platforms//cpu:arm64
x86 @platforms//cpu:x86_32
x86_64 @platforms//cpu:x86_64

Elbette çok mimarili bir APK için birden fazla etiket iletmeniz gerekir. Örneğin: --android_platforms=//:arm64,//:x86_64 (bunları üst düzey BUILD.bazel dosyanızda tanımladığınız varsayılır).

Bazel varsayılan bir Android platformu seçemez. Bu nedenle, bir platform tanımlanmalı ve --android_platforms ile belirtilmelidir.

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 dokümanlarına bakın.

Çoklu ABI'li büyük APK'lar, APK'nın boyutunu artırdığından sürüm derlemeleri için önerilmez ancak geliştirme ve kalite kontrol derlemeleri için yararlı olabilir.

C++ standardı seçme

C++ standardına göre derlemek için aşağıdaki işaretleri kullanın:

C++ Standard İşaret
C++98 Varsayılan, işaret gerekmez
C++11 --cxxopt=-std=c++11
C++14 --cxxopt=-std=c++14
C++17 --cxxopt=-std=c++17

Ö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, 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
)

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 --platforms işaretini kullanın.

Örneğin, my/platforms/BUILD içinde Android platformlarını tanımladığınızı varsayarsak:

bazel build //my/cc/jni:target \
      --platforms=//my/platforms:x86_64

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 --platforms=//my/platforms:x86

common:android_armeabi-v7a --platforms=//my/platforms:armeabi-v7a

# In general
common:android_<abi> --platforms=//my/platforms:<abi>

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.