अगर आप बाज़ार में नए हैं, तो कृपया Android ऐप्लिकेशन बनाने के साथ-साथ, Basel का ट्यूटोरियल.
खास जानकारी
Bazel, कई अलग-अलग बिल्ड कॉन्फ़िगरेशन में काम कर सकता है. इनमें से कई ऐसे कॉन्फ़िगरेशन हैं जिनमें Android नेटिव डेवलपमेंट किट (NDK) टूलचेन का इस्तेमाल किया जाता है. इसका मतलब है कि सामान्य
Android के लिए cc_library
और cc_binary
नियमों को सीधे इसमें इकट्ठा किया जा सकता है
बेज़ल. Bazel, 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
के 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
Basel की सभी cc_libraries को शेयर किए गए एक ऑब्जेक्ट (.so
) फ़ाइल में इकट्ठा किया जाता है,
डिफ़ॉल्ट रूप से, armeabi-v7a
एबीआई को टारगेट करता है. इसे बदलने या इसके लिए बिल्ड बनाने के लिए
एक साथ कई एबीआई, टारगेट कॉन्फ़िगर करने से जुड़ा सेक्शन देखें
एबीआई.
सेटअप का उदाहरण
यह उदाहरण, 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
और जेएनआई के लिए मेथड सिग्नेचर तय करता है
फ़ंक्शन:
public class MainActivity extends AppCompatActivity {
static {
System.loadLibrary("app");
}
@Override
protected void onCreate(Bundle savedInstanceState) {
// ...
}
public native String stringFromJNI();
}
एसटीएल कॉन्फ़िगर करना
C++ STL को कॉन्फ़िगर करने के लिए, फ़्लैग --android_crosstool_top
का इस्तेमाल करें.
bazel build //:app --android_crosstool_top=target label
@androidndk
में ये STL उपलब्ध हैं:
STL | टारगेट लेबल |
---|---|
STLport | @androidndk//:toolchain-stlport |
libc++ | @androidndk//:toolchain-libcpp |
gnustl | @androidndk//:toolchain-gnu-libstdcpp |
r16 और उससे पहले के वर्शन के लिए, डिफ़ॉल्ट एसटीएल gnustl
है. r17 और उसके बाद के वर्शन के लिए, यह
libc++
है. सुविधा के लिए, टारगेट @androidndk//:default_crosstool
को संबंधित डिफ़ॉल्ट एसटीएल के नाम से जाना जाता है.
कृपया ध्यान दें कि r18 से, STLport और gnustl को हटा दिया जाएगा. इससे NDK में libc++
ही एक STL रहेगा.
NDK देखें दस्तावेज़ इन एसटीएल के बारे में ज़्यादा जानें.
टारगेट एबीआई को कॉन्फ़िगर करना
टारगेट एबीआई को कॉन्फ़िगर करने के लिए, --fat_apk_cpu
फ़्लैग का इस्तेमाल इस तरह करें:
bazel build //:app --fat_apk_cpu=comma-separated list of ABIs
डिफ़ॉल्ट रूप से, Bazel 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 |
इन एबीआई के बारे में ज़्यादा जानकारी के लिए, एनडीके के दस्तावेज़ देखें.
रिलीज़ बंडल के लिए, मल्टी-एबीआई फ़ैट APK का सुझाव नहीं दिया जाता, क्योंकि इससे APK का साइज़ बढ़ जाता है. हालांकि, ये डेवलपमेंट और क्यूए बंडल के लिए काम के हो सकते हैं.
C++ स्टैंडर्ड चुनना
C++ स्टैंडर्ड के हिसाब से बनाने के लिए, इन फ़्लैग का इस्तेमाल करें:
C++ स्टैंडर्ड | झंडा |
---|---|
C++98 | डिफ़ॉल्ट, फ़्लैग की ज़रूरत नहीं है |
सी++11 | --cxxopt=-std=c++11 |
C++14 | --cxxopt=-std=c++14 |
उदाहरण के लिए:
bazel build //:app --cxxopt=-std=c++11
--cxxopt
, --copt
, और
--linkopt
के साथ कंपाइलर और लिंकर फ़्लैग पास करने के बारे में ज़्यादा जानने के लिए, उपयोगकर्ता मैन्युअल पढ़ें.
copts
और linkopts
का इस्तेमाल करके, cc_library
में कंपाइलर और लिंकर फ़्लैग को एट्रिब्यूट के तौर पर भी दिखाया जा सकता है. उदाहरण के लिए:
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")
इन टूलचेन को रजिस्टर करने से, Bazel को यह पता चलता है कि आर्किटेक्चर और ऑपरेटिंग सिस्टम की पाबंदियों को हल करते समय, उन्हें NDK 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 सही तरीके से काम कर पाएगा.
ज़्यादातर मामलों में. हालांकि, अगर Bazel कमांड-लाइन पर टारगेट पहले से ही इनमें से किसी भी ट्रांज़िशन नियम के तहत है, जैसे कि C++ डेवलपर किसी खास cc_library
की जांच कर रहे हैं, तो कस्टम --crosstool_top
का इस्तेमाल करना होगा.
android_binary
का इस्तेमाल किए बिना Android के लिए cc_library
बनाना
android_binary
का इस्तेमाल किए बिना, Android के लिए स्टैंडअलोन cc_binary
या cc_library
बनाने के लिए, --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 टूलचेन का इस्तेमाल करके. हालांकि, इससे Bazel के होस्ट टूल, NDK टूलचेन (और इसलिए Android के लिए) के साथ बनाए जाते हैं, क्योंकि होस्ट टूलचेन को टारगेट टूलचेन से कॉपी किया जाता है. इस समस्या को हल करने के लिए, होस्ट के C++ टूलचेन को साफ़ तौर पर सेट करने के लिए, --host_crosstool_top
की वैल्यू को @bazel_tools//tools/cpp:toolchain
पर सेट करें.
इस तरीके से पूरे बिल्ड ट्री पर असर पड़ता है.
इन फ़्लैग को 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
से ट्रांज़िशन जिनकी आपको उम्मीद है
ताकि आप बहुत सारे टारगेट का इस्तेमाल कर सकें.