Bazel ile Android Yerel Geliştirme Kiti'ni kullanma

Sorun bildir Kaynağı göster

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.

Android NDK'nın yeni bir sürümünü (r22 ve sonrası) kullanıyorsanız android_ndk_repository Starlark uygulamasını kullanın. README bölümündeki talimatları uygulayı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:

Örnek sonuçlar

Ş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();

}

Hedef ABI'yı 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şaretinde olduğu gibi, --android_platforms öğesine iletilen değerler platform hedeflerinin etiketleridir ve cihazınızı tanımlamak için standart kısıtlama değerleri kullanılır.

Ö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 işletim sistemi kısıtlamasını kullanmalıdır. CPU kısıtlamasını taşımak için aşağıdaki grafiği kontrol edin:

CPU Değeri Platform
armeabi-v7a @platforms//cpu:arm
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 geçirirsiniz. Ö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çemediğinden bir platform --android_platforms ile tanımlanmalı ve belirtilmelidir.

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
C++17 --cxxopt=-std=c++17

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

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 bölgesinde 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 tane) eklenebilir:

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 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.