Bazel, अलग-अलग हार्डवेयर, ऑपरेटिंग सिस्टम, और सिस्टम कॉन्फ़िगरेशन पर कोड को बना और टेस्ट कर सकता है. इसके लिए, यह बिल्ड टूल के कई वर्शन का इस्तेमाल करता है. जैसे, लिंक करने वाले टूल और कंपाइलर. इस जटिलता को मैनेज करने के लिए, Bazel में constraints और platforms का कॉन्सेप्ट है. बाधा एक ऐसा डाइमेंशन है जिसमें बिल्ड या प्रोडक्शन एनवायरमेंट अलग-अलग हो सकते हैं. जैसे, सीपीयू आर्किटेक्चर, जीपीयू का होना या न होना या सिस्टम में इंस्टॉल किए गए कंपाइलर का वर्शन. प्लैटफ़ॉर्म, इन शर्तों के लिए विकल्पों का एक ऐसा कलेक्शन होता है जिसे नाम दिया गया हो. यह उन खास संसाधनों को दिखाता है जो किसी एनवायरमेंट में उपलब्ध हैं.
एनवायरमेंट को प्लैटफ़ॉर्म के तौर पर मॉडल करने से, Bazel को बिल्ड ऐक्शन के लिए सही टूलचेन अपने-आप चुनने में मदद मिलती है. config_setting नियम के साथ भी प्लैटफ़ॉर्म का इस्तेमाल किया जा सकता है, ताकि कॉन्फ़िगर किए जा सकने वाले एट्रिब्यूट लिखे जा सकें.
Bazel, तीन भूमिकाओं को पहचानता है जो एक प्लैटफ़ॉर्म निभा सकता है:
- होस्ट - वह प्लैटफ़ॉर्म जिस पर Bazel खुद चलता है.
- एक्ज़ीक्यूशन - यह एक ऐसा प्लैटफ़ॉर्म है जिस पर बिल्ड टूल, बिल्ड ऐक्शन को एक्ज़ीक्यूट करते हैं, ताकि इंटरमीडिएट और फ़ाइनल आउटपुट जनरेट किए जा सकें.
- टारगेट - एक ऐसा प्लैटफ़ॉर्म जहां फ़ाइनल आउटपुट मौजूद होता है और उसे लागू किया जाता है.
Bazel, प्लैटफ़ॉर्म के हिसाब से इन बिल्ड के साथ काम करता है:
सिंगल-प्लैटफ़ॉर्म बिल्ड (डिफ़ॉल्ट) - होस्ट, एक्ज़ीक्यूशन, और टारगेट प्लैटफ़ॉर्म एक ही होते हैं. उदाहरण के लिए, Intel x64 CPU पर चलने वाले Ubuntu पर Linux एक्ज़ीक्यूटेबल बनाना.
क्रॉस-कंपाइलेशन बिल्ड - होस्ट और एक्ज़ीक्यूशन प्लैटफ़ॉर्म एक ही होते हैं, लेकिन टारगेट प्लैटफ़ॉर्म अलग होता है. उदाहरण के लिए, MacBook Pro पर macOS का इस्तेमाल करके iOS ऐप्लिकेशन बनाना.
एक से ज़्यादा प्लैटफ़ॉर्म पर काम करने वाले बिल्ड - होस्ट, एक्ज़ीक्यूशन, और टारगेट प्लैटफ़ॉर्म, सभी अलग-अलग होते हैं.
पाबंदियां और प्लैटफ़ॉर्म तय करना
BUILD
फ़ाइलों में constraint_setting
और constraint_value
नियमों का इस्तेमाल करके, प्लैटफ़ॉर्म के लिए उपलब्ध विकल्पों की जानकारी दी जाती है.
constraint_setting
एक नया डाइमेंशन बनाता है, जबकि
constraint_value
किसी दिए गए डाइमेंशन के लिए नई वैल्यू बनाता है. ये दोनों मिलकर
किसी enum और उसकी संभावित वैल्यू को असरदार तरीके से तय करते हैं. उदाहरण के लिए, BUILD
फ़ाइल का यह स्निपेट, सिस्टम के glibc वर्शन के लिए एक शर्त तय करता है. इसकी दो संभावित वैल्यू हैं.
constraint_setting(name = "glibc_version")
constraint_value(
name = "glibc_2_25",
constraint_setting = ":glibc_version",
)
constraint_value(
name = "glibc_2_26",
constraint_setting = ":glibc_version",
)
वर्कस्पेस में अलग-अलग पैकेज के लिए, पाबंदियां और उनकी वैल्यू तय की जा सकती हैं. इन्हें लेबल के हिसाब से रेफ़र किया जाता है. साथ ही, ये सामान्य तौर पर दिखने वाले कंट्रोल के दायरे में आते हैं. अगर विज्ञापन दिखने की अनुमति है, तो मौजूदा पाबंदी की सेटिंग को बढ़ाया जा सकता है. इसके लिए, आपको अपनी वैल्यू तय करनी होगी.
platform
नियम, एक नया प्लैटफ़ॉर्म पेश करता है. इसमें कुछ पाबंदियों की वैल्यू चुनने के विकल्प होते हैं. नीचे दिए गए उदाहरण में, linux_x86
नाम का एक प्लैटफ़ॉर्म बनाया गया है. इसमें बताया गया है कि यह किसी भी ऐसे एनवायरमेंट के बारे में बताता है जो x86_64 आर्किटेक्चर पर Linux ऑपरेटिंग सिस्टम चलाता है. साथ ही, इसमें glibc का वर्शन 2.25 है. (Bazel की पहले से मौजूद पाबंदियों के बारे में ज़्यादा जानने के लिए, यहां देखें.)
platform(
name = "linux_x86",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:x86_64",
":glibc_2_25",
],
)
आम तौर पर काम आने वाली शर्तें और प्लैटफ़ॉर्म
इकोसिस्टम को एक जैसा बनाए रखने के लिए, Bazel टीम एक ऐसी रिपॉज़िटरी मैनेज करती है जिसमें सबसे लोकप्रिय सीपीयू आर्किटेक्चर और ऑपरेटिंग सिस्टम के लिए, कंस्ट्रेंट की परिभाषाएं होती हैं. ये सभी https://github.com/bazelbuild/platforms पर मौजूद हैं.
Bazel में, प्लैटफ़ॉर्म की यह खास परिभाषा शामिल होती है:
@local_config_platform//:host
. यह अपने-आप पता लगाई गई होस्ट प्लैटफ़ॉर्म वैल्यू है. यह उस सिस्टम के लिए अपने-आप पता लगाए गए प्लैटफ़ॉर्म को दिखाती है जिस पर Bazel चल रहा है.
बिल्ड के लिए प्लैटफ़ॉर्म तय करना
नीचे दिए गए कमांड-लाइन फ़्लैग का इस्तेमाल करके, किसी बिल्ड के लिए होस्ट और टारगेट प्लैटफ़ॉर्म तय किए जा सकते हैं:
--host_platform
- डिफ़ॉल्ट रूप से@local_config_platform//:host
पर सेट होता है@local_config_platform
एक रिपॉज़िटरी नियम है. यह होस्ट ओएस और सीपीयू का पता लगाता है. साथ ही, प्लैटफ़ॉर्म टारगेट लिखता है.- यह
@local_config_platform//:constraintz.bzl
भी बनाता है, जोHOST_CONSTRAINTS
नाम की एक कैटगरी को दिखाता है. इसका इस्तेमाल अन्य BUILD और Starlark फ़ाइलों में किया जा सकता है.
--platforms
- डिफ़ॉल्ट रूप से होस्ट प्लैटफ़ॉर्म पर सेट होता है- इसका मतलब है कि जब कोई अन्य फ़्लैग सेट नहीं किया जाता है, तब
@local_config_platform//:host
टारगेट प्लैटफ़ॉर्म होता है. - अगर
--host_platform
सेट है और--platforms
नहीं, तो--host_platform
की वैल्यू, होस्ट और टारगेट प्लैटफ़ॉर्म, दोनों के लिए होती है.
- इसका मतलब है कि जब कोई अन्य फ़्लैग सेट नहीं किया जाता है, तब
ज़रूरी शर्तें पूरी न करने वाले टारगेट को स्किप किया जा रहा है
किसी खास टारगेट प्लैटफ़ॉर्म के लिए ऐप्लिकेशन बनाते समय, अक्सर उन टारगेट को छोड़ना बेहतर होता है जो उस प्लैटफ़ॉर्म पर कभी काम नहीं करेंगे. उदाहरण के लिए, //...
के साथ Linux मशीन पर बिल्ड करते समय, आपके Windows डिवाइस ड्राइवर में कंपाइलर से जुड़ी कई गड़बड़ियां हो सकती हैं. target_compatible_with
एट्रिब्यूट का इस्तेमाल करके, Bazel को बताएं कि आपके कोड पर टारगेट प्लैटफ़ॉर्म की कौनसी पाबंदियां लागू हैं.
इस एट्रिब्यूट का सबसे आसान इस्तेमाल, किसी टारगेट को एक ही प्लैटफ़ॉर्म तक सीमित कर देता है.
अगर कोई प्लैटफ़ॉर्म सभी शर्तों को पूरा नहीं करता है, तो उसके लिए टारगेट नहीं बनाया जाएगा. यहां दिए गए उदाहरण में, win_driver_lib.cc
को 64-बिट Windows तक सीमित किया गया है.
cc_library(
name = "win_driver_lib",
srcs = ["win_driver_lib.cc"],
target_compatible_with = [
"@platforms//cpu:x86_64",
"@platforms//os:windows",
],
)
:win_driver_lib
, 64-बिट Windows के साथ सिर्फ़ काम करता है. यह किसी और के साथ काम नहीं करता. साथ काम न करने की समस्या एक से दूसरे डिवाइस में भी हो सकती है. ऐसे सभी टारगेट जो किसी ऐसे टारगेट पर ट्रांज़िटिव तरीके से निर्भर होते हैं जो काम नहीं करता उन्हें भी काम न करने वाला टारगेट माना जाता है.
टारगेट कब स्किप किए जाते हैं?
जब टारगेट को काम न करने वाला माना जाता है, तब उन्हें स्किप कर दिया जाता है. साथ ही, उन्हें टारगेट पैटर्न के विस्तार के हिस्से के तौर पर बिल्ड में शामिल किया जाता है. उदाहरण के लिए, यहां दिए गए दो इनवोकेशन, टारगेट पैटर्न एक्सपैंशन में मिले किसी भी ऐसे टारगेट को छोड़ देते हैं जो काम नहीं करता.
$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all
अगर कमांड लाइन पर --expand_test_suites
के साथ test_suite
को तय किया जाता है, तो test_suite
में मौजूद ऐसे टेस्ट को भी स्किप कर दिया जाता है जो काम नहीं करते.
दूसरे शब्दों में कहें, तो कमांड लाइन पर मौजूद test_suite
, :all
और ...
की तरह काम करते हैं. --noexpand_test_suites
का इस्तेमाल करने से, टारगेटिंग का दायरा नहीं बढ़ता. साथ ही, इससे ऐसे test_suite
टारगेट भी काम नहीं करते जिन पर काम न करने वाले टेस्ट लागू किए गए हैं.
कमांड लाइन पर, साफ़ तौर पर ऐसे टारगेट के बारे में बताने पर गड़बड़ी का मैसेज दिखता है जो काम नहीं करता. साथ ही, बिल्ड नहीं हो पाता.
$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully
अगर --skip_incompatible_explicit_targets
चालू है, तो साफ़ तौर पर बताए गए ऐसे टारगेट को चुपचाप तरीके से स्किप कर दिया जाता है जो काम नहीं करते.
ज़्यादा इमोशन दिखाने वाली पाबंदियां
पाबंदियों को ज़्यादा आसानी से लागू करने के लिए, @platforms//:incompatible
constraint_value
का इस्तेमाल करें. यह किसी भी प्लैटफ़ॉर्म के लिए उपलब्ध नहीं है.
ज़्यादा जटिल पाबंदियों को दिखाने के लिए, select()
का इस्तेमाल @platforms//:incompatible
के साथ करें. उदाहरण के लिए, इसका इस्तेमाल बुनियादी OR लॉजिक को लागू करने के लिए करें. यहां दी गई लाइब्रेरी, macOS और Linux के साथ काम करती है. हालांकि, यह किसी दूसरे प्लैटफ़ॉर्म के साथ काम नहीं करती.
cc_library(
name = "unixish_lib",
srcs = ["unixish_lib.cc"],
target_compatible_with = select({
"@platforms//os:osx": [],
"@platforms//os:linux": [],
"//conditions:default": ["@platforms//:incompatible"],
}),
)
ऊपर दी गई जानकारी को इस तरह समझा जा सकता है:
- macOS को टारगेट करते समय, टारगेट पर कोई पाबंदी नहीं होती.
- Linux को टारगेट करते समय, टारगेट पर कोई पाबंदी नहीं होती.
- ऐसा न होने पर, टारगेट पर
@platforms//:incompatible
की पाबंदी लागू होती है.@platforms//:incompatible
किसी भी प्लैटफ़ॉर्म का हिस्सा नहीं है. इसलिए, टारगेट को काम न करने वाला माना जाता है.
अपनी पाबंदियों को ज़्यादा आसानी से समझने के लिए, skylib के
selects.with_or()
का इस्तेमाल करें.
इसी तरह, पुराने सिस्टम के साथ काम न करने की सुविधा के बारे में बताया जा सकता है. यहां दिए गए उदाहरण में, ऐसी लाइब्रेरी के बारे में बताया गया है जो ARM को छोड़कर सभी के साथ काम करती है.
cc_library(
name = "non_arm_lib",
srcs = ["non_arm_lib.cc"],
target_compatible_with = select({
"@platforms//cpu:arm": ["@platforms//:incompatible"],
"//conditions:default": [],
}),
)
bazel cquery
का इस्तेमाल करके, ऐसे टारगेट का पता लगाना जो काम नहीं करते
IncompatiblePlatformProvider
bazel cquery
के Starlark आउटपुट फ़ॉर्मैट का इस्तेमाल करके, उन टारगेट के बीच अंतर किया जा सकता है जो एक-दूसरे के साथ काम नहीं करते हैं.
इसका इस्तेमाल, उन टारगेट को फ़िल्टर करने के लिए किया जा सकता है जो काम नहीं करते. नीचे दिए गए उदाहरण में, सिर्फ़ उन टारगेट के लेबल प्रिंट किए जाएंगे जो इसके साथ काम करते हैं. काम न करने वाले टारगेट प्रिंट नहीं किए जाते.
$ cat example.cquery
def format(target):
if "IncompatiblePlatformProvider" not in providers(target):
return target.label
return ""
$ bazel cquery //... --output=starlark --starlark:file=example.cquery
आम समस्याएं
असंगत टारगेट, दिखने से जुड़ी पाबंदियों को अनदेखा करते हैं.