अगर आपने पहली बार बेज़ल का इस्तेमाल करना शुरू किया है, तो कृपया Ba आवाज़ के साथ Android फ़ोन बनाने के बारे में ट्यूटोरियल देखें.
खास जानकारी
Bazel कई अलग-अलग बिल्ड कॉन्फ़िगरेशन में काम कर सकता है. इनमें Android नेटिव डेवलपमेंट किट (एनडीके) टूलचेन का इस्तेमाल करने वाले कई कॉन्फ़िगरेशन भी शामिल हैं. इसका मतलब है कि Android के लिए, सामान्य
cc_library
और cc_binary
नियमों को सीधे बेज़ल में कंपाइल किया जा सकता है. यह डेटा इकट्ठा करने के लिए, बेज़ल नाम का 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 Android NDK (r22 और उसके बाद के वर्शन) के हाल के वर्शन का इस्तेमाल किया जा रहा है, तो android_ndk_repository
के Starlark तरीके का इस्तेमाल करें.
इसके Read_ME में दिए गए निर्देशों का पालन करें.
तुरंत शुरू करने का तरीका
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_librery को एक शेयर की गई ऑब्जेक्ट (.so
) फ़ाइल में इकट्ठा करता है, जिसे
डिफ़ॉल्ट तौर पर, armeabi-v7a
एबीआई के लिए टारगेट किया जाता है. एक साथ कई एबीआई बनाने या बदलने के लिए, टारगेट एबीआई को कॉन्फ़िगर करने से जुड़ा सेक्शन देखें.
सेट अप का उदाहरण
यह उदाहरण बैज़ल के उदाहरणों की जगह में उपलब्ध है.
BUILD.bazel
फ़ाइल में, तीन टारगेट android_binary
, android_library
, और cc_library
नियमों के साथ तय किए जाते हैं.
android_binary
वाला टॉप लेवल टारगेट, APK बनाता है.
cc_library
टारगेट में, एक C++ सोर्स फ़ाइल होती है, जिसमें JNI फ़ंक्शन लागू होता है:
#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();
}
एसएफ़टीपी को कॉन्फ़िगर करना
C++ STL को कॉन्फ़िगर करने के लिए, फ़्लैग --android_crosstool_top
का इस्तेमाल करें.
bazel build //:app --android_crosstool_top=target label
@androidndk
में उपलब्ध एसटीएल नीचे दिए गए हैं:
एसटीएल | टारगेट लेबल |
---|---|
एसटीएलपोर्ट | @androidndk//:toolchain-stlport |
lib++ | @androidndk//:toolchain-libcpp |
gnustl | @androidndk//:toolchain-gnu-libstdcpp |
r16 और उससे पहले के वर्शन के लिए, डिफ़ॉल्ट एसटीएल gnustl
है. r17 और इसके बाद के वर्शन के लिए, यह
libc++
है. आपकी सुविधा के लिए, टारगेट @androidndk//:default_crosstool
डिफ़ॉल्ट डिफ़ॉल्ट एसटीएल पर निर्भर करता है.
कृपया ध्यान दें कि r18 के बाद से, STLport और gnustl को से हटा दिया जाएगा,
जो libc++
NDK में इकलौता STL बन जाएगा.
इन एसटीएल के बारे में ज़्यादा जानकारी के लिए, एनडीके दस्तावेज़ देखें.
टारगेट एबीआई को कॉन्फ़िगर करना
टारगेट एबीआई को कॉन्फ़िगर करने के लिए, --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
.
अगर एक से ज़्यादा एबीआई तय किए गए हैं, तो बज़ेल एक ऐसा APK बनाएगा जिसमें हर एबीआई के लिए एक शेयर किया गया ऑब्जेक्ट होगा.
NDK में किए गए बदलाव और Android API के लेवल के आधार पर, ये एबीआई उपलब्ध हैं:
NDK वर्शन | एबीआई |
---|---|
16 और उससे कम | Armeabi, Armeabi-v7a, Arm64-v8a, mips, mips64, x86, x86_64 |
17 और उससे ज़्यादा | Armeabi-v7a, Arm64-v8a, x86, x86_64 |
इन एबीआई के बारे में ज़्यादा जानकारी के लिए, एनडीके दस्तावेज़ देखें.
रिलीज़ बिल्ड के लिए मल्टी-एबीआई फ़ैट APK का सुझाव नहीं दिया जाता है, क्योंकि ये APK के साइज़ को बढ़ाते हैं. हालांकि, ये डेवलपमेंट और QA बिल्ड के लिए उपयोगी हो सकते हैं.
C++ मानक चुनना
C++ मानक के हिसाब से बनाने के लिए, इन फ़्लैग का इस्तेमाल करें:
C++ मानक | झंडा |
---|---|
सी+99 | डिफ़ॉल्ट, कोई फ़्लैग ज़रूरी नहीं है |
सी++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
)
प्लैटफ़ॉर्म और टूलचेन के साथ इंटिग्रेशन
Bazel का कॉन्फ़िगरेशन मॉडल,
प्लैटफ़ॉर्म और
टूलचेन की ओर बढ़ रहा है. अगर
आपके बिल्ड में आर्किटेक्चर या ऑपरेटिंग सिस्टम को चुनने के लिए --platforms
फ़्लैग का इस्तेमाल किया गया है, तो NDK का इस्तेमाल करने के लिए, आपको बैजल में --extra_toolchains
फ़्लैग पास करना होगा.
उदाहरण के लिए, Go नियमों के दिए गए android_arm64_cgo
टूलचेन का इस्तेमाल करने के लिए, --platforms
फ़्लैग के साथ-साथ --extra_toolchains=@androidndk//:all
भी पास करें.
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 से एनडीके 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
नियम, Android डिवाइसों के साथ काम करने वाले कॉन्फ़िगरेशन में डिपेंडेंट डिपेंडेंसी बनाने के लिए कह सकता है, ताकि Bazel, किसी खास फ़्लैग के बिना सिर्फ़ काम कर सके. हालांकि, एबीआई और एसटीएल कॉन्फ़िगरेशन के लिए --fat_apk_cpu
और --android_crosstool_top
को छोड़कर, ऐसा नहीं किया जा सकता.
यह सिस्टम अपने-आप Android कॉन्फ़िगरेशन कॉन्फ़िगरेशन का इस्तेमाल करता है.
android_binary
के साथ काम करने वाला नियम, इसकी डिपेंडेंसी के कॉन्फ़िगरेशन को अपने-आप Android कॉन्फ़िगरेशन में बदल देता है. इसलिए, बिल्ड के सिर्फ़ Android के सब-ट्री पर असर पड़ता है. बिल्ड ग्राफ़ के दूसरे हिस्से टॉप-लेवल टारगेट कॉन्फ़िगरेशन का इस्तेमाल करके प्रोसेस किए जाते हैं. अगर सपोर्ट करने के लिए बिल्ड ग्राफ़ में पाथ हैं, तो वे दोनों कॉन्फ़िगरेशन में एक ही टारगेट को प्रोसेस कर सकते हैं.
एक बार Android के साथ काम करने वाले कॉन्फ़िगरेशन में Bazel पर सेट करने के बाद, टॉप लेवल पर बताए गए बदलावों या हाई लेवल ट्रांज़िशन पॉइंट की वजह से कॉन्फ़िगरेशन में और बदलाव नहीं होते.
Android की कॉन्फ़िगरेशन में ट्रांज़िशन ट्रिगर करने वाली इकलौती जगह ही android_binary
की deps
विशेषता है.
उदाहरण के लिए, अगर आप android_library
बिना किसी फ़्लैग के cc_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.
आम तौर पर, अपने-आप होने वाले इन ट्रांज़िशन की वजह से, बेजल आने वाले ज़्यादातर मामलों में,
इवेंट को सही तरीके से किया जा सकता है. हालांकि, अगर Bazecc_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
टारगेट, एनडीके टूलचेन का इस्तेमाल करके बनाए गए हैं. हालांकि, इससे Bazel के खुद के होस्ट टूल, NDK टूलचेन (और Android के लिए) के साथ बनाए जा सकते हैं. ऐसा इसलिए, क्योंकि होस्ट टूलचेन, टारगेट टूलचेन से कॉपी किया जाता है. इस पर काम करने के लिए, --host_crosstool_top
का मान @bazel_tools//tools/cpp:toolchain
रखें और साफ़ तौर पर
होस्ट का C++ टूलचेन सेट करें.
इस तरीके से, पूरा बिल्ड ट्री प्रभावित होता है.
ये फ़्लैग, project/.bazelrc
में 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
से, अपने-आप कॉन्फ़िगरेशन
होने की सुविधा पर भरोसा करें. उम्मीद है कि इससे कई ऐसे टारगेट बन जाएंगे जिन्हें आप कंट्रोल नहीं करते हैं.