Bazel के साथ Android नेटिव डेवलपमेंट किट का इस्तेमाल करना

समस्या की शिकायत करें सोर्स देखें Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

अगर आपने Bazel का इस्तेमाल पहले कभी नहीं किया है, तो कृपया Bazel की मदद से Android ऐप्लिकेशन बनाना ट्यूटोरियल से शुरुआत करें.

खास जानकारी

Bazel को कई अलग-अलग बिल्ड कॉन्फ़िगरेशन में चलाया जा सकता है. इनमें से कई, Android Native Development Kit (NDK) टूलचेन का इस्तेमाल करते हैं. इसका मतलब है कि Android के लिए, सामान्य cc_library और cc_binary नियमों को सीधे Bazel में कंपाइल किया जा सकता है. Bazel, android_ndk_repository रिपॉज़िटरी के नियम का इस्तेमाल करके ऐसा करता है.

ज़रूरी शर्तें

कृपया पक्का करें कि आपने Android SDK और NDK इंस्टॉल किया हो.

एसडीके और एनडीके सेट अप करने के लिए, अपने WORKSPACE में यह स्निपेट जोड़ें:

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 नियम के बारे में ज़्यादा जानने के लिए, एनसाइक्लोपीडिया एंट्री बनाना लेख पढ़ें.

अगर Android NDK (r22 और इसके बाद के वर्शन) का इस्तेमाल किया जा रहा है, तो android_ndk_repository के Starlark वर्शन का इस्तेमाल करें. इसके README में दिए गए निर्देशों का पालन करें.

तुरंत शुरू करना

Android के लिए C++ बनाने के लिए, बस अपनी android_binary या android_library नियमों में cc_library डिपेंडेंसी जोड़ें.

उदाहरण के लिए, Android ऐप्लिकेशन के लिए यहां दी गई BUILD फ़ाइल देखें:

# 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",
)

इस BUILD फ़ाइल से, यह टारगेट ग्राफ़ मिलता है:

परिणामों के उदाहरण

पहली इमेज. cc_library डिपेंडेंसी के साथ Android प्रोजेक्ट का ग्राफ़ बनाता है.

ऐप्लिकेशन बनाने के लिए, यह कमांड चलाएं:

bazel build //app/src/main:app

bazel build कमांड, Java फ़ाइलों, Android रिसॉर्स फ़ाइलों, और cc_library नियमों को कंपाइल करती है. साथ ही, इन सभी को एक APK में पैकेज करती है:

$ 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, सभी cc_libraries को एक ही शेयर किए गए ऑब्जेक्ट (.so) फ़ाइल में कंपाइल करता है. यह फ़ाइल, डिफ़ॉल्ट रूप से armeabi-v7a ABI के लिए टारगेट की जाती है. इसे बदलने या एक ही समय में कई एबीआइ के लिए बनाने के लिए, टारगेट एबीआइ को कॉन्फ़िगर करना सेक्शन देखें.

सेटअप का उदाहरण

यह उदाहरण, Bazel के उदाहरणों वाली रिपॉज़िटरी में उपलब्ध है.

BUILD.bazel फ़ाइल में, android_binary, android_library, और cc_library नियमों के साथ तीन टारगेट तय किए गए हैं.

android_binary टॉप-लेवल टारगेट, APK बनाता है.

cc_library टारगेट में, JNI फ़ंक्शन को लागू करने वाली एक C++ सोर्स फ़ाइल शामिल होती है:

#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 टारगेट, Java सोर्स, संसाधन फ़ाइलों, और cc_library टारगेट पर निर्भरता के बारे में बताता है. इस उदाहरण में, MainActivity.java शेयर की गई ऑब्जेक्ट फ़ाइल libapp.so को लोड करता है. साथ ही, JNI फ़ंक्शन के लिए, तरीके के सिग्नेचर को तय करता है:

public class MainActivity extends AppCompatActivity {

    static {
        System.loadLibrary("app");
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
       // ...
    }

    public native String stringFromJNI();

}

टारगेट किए गए ABI को कॉन्फ़िगर करना

टारगेट एबीआई को कॉन्फ़िगर करने के लिए, --android_platforms फ़्लैग का इस्तेमाल इस तरह करें:

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

--platforms फ़्लैग की तरह ही, --android_platforms को पास की गई वैल्यू, platform टारगेट के लेबल होती हैं. इनमें स्टैंडर्ड कंस्ट्रेंट वैल्यू का इस्तेमाल करके, आपके डिवाइस के बारे में बताया जाता है.

उदाहरण के लिए, 64-बिट ARM प्रोसेसर वाले Android डिवाइस के लिए, आपको अपना प्लैटफ़ॉर्म इस तरह से तय करना होगा:

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

हर Android platform को @platforms//os:android ओएस की ज़रूरी शर्त का इस्तेमाल करना चाहिए. सीपीयू की सीमा को माइग्रेट करने के लिए, यह चार्ट देखें:

सीपीयू की वैल्यू प्लैटफ़ॉर्म
armeabi-v7a @platforms//cpu:armv7
arm64-v8a @platforms//cpu:arm64
x86 @platforms//cpu:x86_32
x86_64 @platforms//cpu:x86_64

इसके अलावा, मल्टी-आर्किटेक्चर वाले APK के लिए, एक से ज़्यादा लेबल पास किए जाते हैं. उदाहरण के लिए: --android_platforms=//:arm64,//:x86_64 (मान लें कि आपने उन्हें टॉप-लेवल की BUILD.bazel फ़ाइल में तय किया है).

Bazel, डिफ़ॉल्ट Android प्लैटफ़ॉर्म नहीं चुन सकता. इसलिए, आपको एक प्लैटफ़ॉर्म तय करना होगा और उसे --android_platforms के साथ तय करना होगा.

एनडीके के वर्शन और Android एपीआई लेवल के हिसाब से, ये एबीआइ उपलब्ध हैं:

एनडीके का वर्शन एबीआई
16 साल और इससे कम उम्र के लोगों के लिए armeabi, armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64
17 साल और इससे ज़्यादा armeabi-v7a, arm64-v8a, x86, x86_64

इन एबीआइ के बारे में ज़्यादा जानने के लिए, NDK के दस्तावेज़ देखें.

रिलीज़ बिल्ड के लिए, मल्टी-एबीआई फ़ैट APK इस्तेमाल करने का सुझाव नहीं दिया जाता, क्योंकि इससे APK का साइज़ बढ़ जाता है. हालांकि, डेवलपमेंट और QA बिल्ड के लिए इनका इस्तेमाल किया जा सकता है.

C++ स्टैंडर्ड चुनना

C++ स्टैंडर्ड के मुताबिक बनाने के लिए, इन फ़्लैग का इस्तेमाल करें:

C++ स्टैंडर्ड झंडा
C++98 डिफ़ॉल्ट, किसी फ़्लैग की ज़रूरत नहीं है
C++11 --cxxopt=-std=c++11
C++14 --cxxopt=-std=c++14
C++17 --cxxopt=-std=c++17

उदाहरण के लिए:

bazel build //:app --cxxopt=-std=c++11

उपयोगकर्ता गाइड में, --cxxopt, --copt, और --linkopt की मदद से कंपाइलर और लिंकर फ़्लैग पास करने के बारे में ज़्यादा पढ़ें.

कंपाइलर और लिंकर फ़्लैग को भी cc_library में एट्रिब्यूट के तौर पर तय किया जा सकता है. इसके लिए, copts और linkopts का इस्तेमाल करें. उदाहरण के लिए:

cc_library(
    name = "jni_lib",
    srcs = ["cpp/native-lib.cpp"],
    copts = ["-std=c++11"],
    linkopts = ["-ldl"], # link against libdl
)

android_binary का इस्तेमाल किए बिना, Android के लिए cc_library बनाना

android_binary का इस्तेमाल किए बिना, Android के लिए स्टैंडअलोन cc_binary या cc_library बनाने के लिए, --platforms फ़्लैग का इस्तेमाल करें.

उदाहरण के लिए, मान लें कि आपने my/platforms/BUILD में Android प्लैटफ़ॉर्म तय किए हैं:

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

इस तरीके से, पूरे बिल्ड ट्री पर असर पड़ता है.

इन फ़्लैग को bazelrc config (हर ABI के लिए एक) में रखा जा सकता है. इसके लिए, project/.bazelrc का इस्तेमाल करें:

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>

इसके बाद, x86 के लिए x86 बनाने के लिए, उदाहरण के तौर पर यह कमांड चलाएं:cc_library

bazel build //my/cc/jni:target --config=android_x86

आम तौर पर, इस तरीके का इस्तेमाल छोटे लेवल के टारगेट (जैसे, cc_library) के लिए करें. इसके अलावा, इसका इस्तेमाल तब करें, जब आपको पता हो कि आपको क्या बनाना है. बड़े लेवल के टारगेट के लिए, android_binary से ऑटोमैटिक कॉन्फ़िगरेशन ट्रांज़िशन पर भरोसा करें. ऐसा तब करें, जब आपको ऐसे कई टारगेट बनाने हों जिन्हें कंट्रोल नहीं किया जा सकता.