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

अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है किसी समस्या की शिकायत करें सोर्स देखें रात · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

अगर आप बाज़ार में नए हैं, तो कृपया Android ऐप्लिकेशन बनाने के साथ-साथ, Basel का ट्यूटोरियल.

खास जानकारी

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

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

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

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 का स्टारलार्क लागू करना. इसमें दिए गए निर्देशों का पालन करें इसे रीडमी करें.

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

Android के लिए C++ बनाने के लिए, अपनेcc_library android_binary या android_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

Baज़र, सभी cc_libraries को शेयर किए गए एक ऑब्जेक्ट (.so) फ़ाइल में इकट्ठा करता है, डिफ़ॉल्ट रूप से, armeabi-v7a एबीआई को टारगेट करता है. इसे बदलने या इसके लिए बिल्ड बनाने के लिए एक साथ कई एबीआई, टारगेट कॉन्फ़िगर करने का सेक्शन देखें एबीआई.

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

यह उदाहरण बेज़ल के उदाहरणों में उपलब्ध है डेटा स्टोर करने की जगह के लिए.

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 और जेएनआई के लिए मेथड सिग्नेचर तय करता है फ़ंक्शन:

public class MainActivity extends AppCompatActivity {

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

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

    public native String stringFromJNI();

}

STL को कॉन्फ़िगर करना

C++ STL को कॉन्फ़िगर करने के लिए, --android_crosstool_top फ़्लैग का इस्तेमाल करें.

bazel build //:app --android_crosstool_top=target label

@androidndk में उपलब्ध एसटीएल ये हैं:

STL टारगेट लेबल
STLport @androidndk//:toolchain-stlport
libc++ @androidndk//:toolchain-libcpp
ग्लूस्टल @androidndk//:toolchain-gnu-libstdcpp

r16 और उससे पहले के वर्शन के लिए, डिफ़ॉल्ट एसटीएल gnustl है. r17 और उसके बाद के वर्शन के लिए, यह libc++. सुविधा के लिए, टारगेट @androidndk//:default_crosstool यह है इन्हें संबंधित डिफ़ॉल्ट एसटीएल में एलियास किया गया है.

कृपया ध्यान दें कि r18 और उसके बाद के वर्शन में, STLport और gnustl हटाया गया, इस वजह से, एनडीके में सिर्फ़ libc++ ही एसटीएल है.

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

टारगेट एबीआई को कॉन्फ़िगर करना

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

bazel build //:app --fat_apk_cpu=comma-separated list of ABIs

डिफ़ॉल्ट रूप से, Basel, armeabi-v7a के लिए नेटिव Android कोड बनाता है. x86 वर्शन बनाने के लिए (जैसे, एम्युलेटर के लिए), --fat_apk_cpu=x86 पास करें. एक से ज़्यादा ब्राउज़र के लिए फ़ैट APK बनाने के लिए आर्किटेक्चर के लिए, आपके पास एक से ज़्यादा सीपीयू तय करने का विकल्प है: --fat_apk_cpu=armeabi-v7a,x86.

एक से ज़्यादा एबीआई दिए जाने पर, Basel एक ऐसा APK बनाएगा जिसमें शेयर किया गया ऑब्जेक्ट सबमिट करते हैं.

एनडीके वर्शन और Android एपीआई लेवल के आधार पर, ये एबीआई उपलब्ध:

एनडीके (NDK) में बदलाव एबीआई
16 और उससे कम Armeabi, Armeabi-v7a, arm64-v8a, mips, mips64, x86, x86_64
17 साल और इससे ज़्यादा Armeabi-v7a, arm64-v8a, x86, x86_64

NDK दस्तावेज़ देखें देखें.

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

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

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

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

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

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
)

प्लैटफ़ॉर्म और टूलचेन के साथ इंटिग्रेशन

Basel के कॉन्फ़िगरेशन मॉडल को platforms और टूलचेन. अगर आपके बिल्ड, आर्किटेक्चर या ऑपरेटिंग सिस्टम को चुनने के लिए --platforms फ़्लैग का इस्तेमाल करता है बनाने के लिए, आपको बेज़ल को --extra_toolchains फ़्लैग पास करना होगा ताकि एनडीके का इस्तेमाल किया जा सके.

उदाहरण के लिए, इन्होंने उपलब्ध कराए android_arm64_cgo टूलचेन के साथ इंटिग्रेट करने के लिए Go के नियमों का पालन करने के लिए, --extra_toolchains=@androidndk//:all --platforms फ़्लैग.

bazel build //my/cc:lib \
  --platforms=@io_bazel_rules_go//go/toolchain:android_arm64_cgo \
  --extra_toolchains=@androidndk//:all

इन्हें सीधे WORKSPACE फ़ाइल में भी रजिस्टर किया जा सकता है:

android_ndk_repository(name = "androidndk")
register_toolchains("@androidndk//:all")

इन टूलचेन को रजिस्टर करने से, बेज़ल उन्हें एनडीके BUILD में ढूंढने के लिए कह सकते हैं फ़ाइल (NDK 20 के लिए) का इस्तेमाल करें:

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

यह कैसे काम करता है: Android कॉन्फ़िगरेशन ट्रांज़िशन की शुरुआत करना

android_binary नियम साफ़ तौर पर, Basel से अपनी डिपेंडेंसी बनाने के लिए कह सकता है एक ऐसा कॉन्फ़िगरेशन है जो Android के साथ काम करता है. इससे Baज़र का बिल्ड वर्शन, डिवाइस के बिना बस काम कर पाएगा --fat_apk_cpu और --android_crosstool_top को छोड़कर, इसके लिए कोई खास फ़्लैग एबीआई और एसटीएल का कॉन्फ़िगरेशन.

पर्दे के पीछे, यह अपने-आप होने वाला कॉन्फ़िगरेशन Android कॉन्फ़िगरेशन का इस्तेमाल करता है ट्रांज़िशन.

काम करने वाला नियम, जैसे कि android_binary, आपकी वेबसाइट के अपनी डिपेंडेंसी का एक Android कॉन्फ़िगरेशन के लिए कॉन्फ़िगरेशन, इसलिए केवल Android से जुड़ी खास सबट्री पर इसका असर पड़ा है. बिल्ड के अन्य हिस्से ग्राफ़, टॉप-लेवल टारगेट कॉन्फ़िगरेशन का इस्तेमाल करके प्रोसेस किए जाते हैं. यह भी हो सकता है कि दोनों कॉन्फ़िगरेशन में एक ही टारगेट प्रोसेस करना चाहिए, अगर बनाने के लिए ग्राफ़ बनाना होगा.

जब Basel, Android के साथ काम करने वाले कॉन्फ़िगरेशन में हो, तो इसके बारे में यहां बताया गया है या एक उच्च-स्तरीय ट्रांज़िशन पॉइंट की वजह से, अतिरिक्त ट्रांज़िशन मिले पॉइंट, कॉन्फ़िगरेशन में और बदलाव नहीं करते हैं.

पहले से मौजूद सिर्फ़ ऐसी जगह जो Android पर ट्रांज़िशन को ट्रिगर करती है कॉन्फ़िगरेशन, android_binary की deps एट्रिब्यूट है.

उदाहरण के लिए, अगर cc_library की मदद से android_library टारगेट बनाने की कोशिश की जाती है बिना फ़्लैग के डिपेंडेंसी है, तो आपको JNI के मौजूद न होने पर गड़बड़ी का सामना करना पड़ सकता है हेडर:

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.

आम तौर पर, अपने-आप होने वाले इन ट्रांज़िशन के इस्तेमाल से, Bagel सही तरीके से काम कर पाएगा. ज़्यादातर मामलों में. हालांकि, अगर Basel कमांड-लाइन पर टारगेट पहले से ही जैसे कि C++ डेवलपर किसी खास नियम के तहत cc_library है, तो कस्टम --crosstool_top का इस्तेमाल करना ज़रूरी है.

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

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

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

bazel build //my/cc/jni:target \
      --crosstool_top=@androidndk//:default_crosstool \
      --cpu=<abi> \
      --host_crosstool_top=@bazel_tools//tools/cpp:toolchain

इस उदाहरण में, टॉप-लेवल cc_library और cc_binary टारगेट बनाए गए हैं NDK टूलचेन का इस्तेमाल करके. हालांकि, इसकी वजह से बेज़ल के अपने होस्ट टूल बन जाते हैं एनडीके टूलचेन के साथ काम करता है (और इसलिए Android के लिए). ऐसा इसलिए, क्योंकि होस्ट टूलचेन टारगेट टूलचेन से कॉपी किया जाता है. इससे बचने के लिए, --host_crosstool_top में @bazel_tools//tools/cpp:toolchain होना है, ताकि साफ़ तौर पर होस्ट के C++ टूलचेन को सेट कर सकती है.

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

इन फ़्लैग को bazelrc कॉन्फ़िगरेशन (हर एबीआई के लिए एक) में रखा जा सकता है 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

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

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

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