प्लैटफ़ॉर्म

Bazel कई तरह के हार्डवेयर, ऑपरेटिंग सिस्टम और सिस्टम कॉन्फ़िगरेशन पर कोड बना सकता है और उसकी जाँच कर सकता है. इसके लिए वह लिंकर और कंपाइलर जैसे बिल्ड टूल के कई अलग-अलग वर्शन का इस्तेमाल कर सकता है. इस जटिलता को मैनेज करने में मदद करने के लिए, Bazel ने सीमाएं और प्लैटफ़ॉर्म का एक सिद्धांत दिया है. कंस्ट्रेंट एक ऐसा डाइमेंशन है जिसमें बिल्ड या प्रोडक्शन एनवायरमेंट में अंतर हो सकता है. जैसे, सीपीयू आर्किटेक्चर, जीपीयू का मौजूद होना या न होना या सिस्टम पर इंस्टॉल किए गए कंपाइलर का वर्शन. प्लैटफ़ॉर्म, इन पाबंदियों के हिसाब से चुने गए विकल्पों का कलेक्शन होता है. ये ऐसे संसाधनों को दिखाते हैं जो कुछ एनवायरमेंट में उपलब्ध होते हैं.

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

Bazel तीन भूमिकाओं की पहचान करता है, जो एक प्लैटफ़ॉर्म पर मिल सकता है:

  • होस्ट - वह प्लैटफ़ॉर्म जिस पर Bazel चलता है.
  • एक्ज़ीक्यूशन - ऐसा प्लैटफ़ॉर्म जिस पर बिल्ड टूल इंटरमीडिएट और फ़ाइनल आउटपुट बनाने के लिए, बिल्ड ऐक्शन करता है.
  • टारगेट - वह प्लैटफ़ॉर्म जिस पर फ़ाइनल आउटपुट मौजूद होता है और एक्ज़ीक्यूट होता है.

Bazel, प्लैटफ़ॉर्म के बारे में नीचे दी गई बिल्ड स्थितियों में काम करता है:

  • सिंगल-प्लैटफ़ॉर्म बिल्ड (डिफ़ॉल्ट) - होस्ट, एक्ज़ीक्यूशन, और टारगेट प्लैटफ़ॉर्म एक जैसे होते हैं. उदाहरण के लिए, Intel x64 सीपीयू पर चल रहे Ubuntu पर Linux को एक्ज़ीक्यूट किया जा सकता है, बनाना.

  • क्रॉस-कंपाइलेशन बिल्ड - होस्ट और प्रोग्राम चलाने के प्लैटफ़ॉर्म एक जैसे होते हैं, लेकिन टारगेट प्लैटफ़ॉर्म अलग-अलग होता है. उदाहरण के लिए, MacOS पर MacOS पर चलने वाला iOS ऐप्लिकेशन बनाना.

  • मल्टी-प्लैटफ़ॉर्म बिल्ड - होस्ट, एक्ज़ीक्यूशन, और टारगेट प्लैटफ़ॉर्म, ये सभी अलग-अलग होते हैं.

पाबंदियां और प्लैटफ़ॉर्म तय करना

BUILD फ़ाइलों में constraint_setting और constraint_value नियमों का इस्तेमाल करके, प्लैटफ़ॉर्म के लिए संभावित विकल्पों के विकल्प तय किए जाते हैं. constraint_setting एक नया डाइमेंशन बनाता है, जबकि constraint_value किसी दिए गए डाइमेंशन के लिए एक नई वैल्यू बनाता है. साथ ही, वे साथ मिलकर एनम और उसकी संभावित वैल्यू को असरदार तरीके से तय करते हैं. उदाहरण के लिए, 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 नाम का एक प्लैटफ़ॉर्म बनाया गया है. साथ ही, यह बताया गया है कि यह ऐसे किसी भी माहौल के बारे में बताता है जो 2.25 के glibc वर्शन पर, x86_64 आर्किटेक्चर पर Linux ऑपरेटिंग सिस्टम चलाता है. (Bzel के बिल्ट-इन कंस्ट्रेंट के बारे में ज़्यादा जानने के लिए यहां देखें.)

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 - डिफ़ॉल्ट रूप से @bazel_tools//platforms:host_platform सेट होती है
  • --platforms - डिफ़ॉल्ट रूप से @bazel_tools//platforms:target_platform सेट होती है

असंगत टारगेट को छोड़ा जा रहा है

किसी खास टारगेट प्लैटफ़ॉर्म के लिए बनाते समय, आपको उन टारगेट को छोड़ देना चाहिए जो उस प्लैटफ़ॉर्म पर कभी काम नहीं करेंगे. उदाहरण के लिए, //... वाला Linux मशीन बनाते समय, आपके Windows डिवाइस का ड्राइवर कंपाइलर से जुड़ी बहुत सारी गड़बड़ियां जनरेट कर सकता है. target_compatible_with एट्रिब्यूट का इस्तेमाल करके, Bazel को बताएं कि आपके कोड में कौनसा टारगेट प्लैटफ़ॉर्म लागू है.

इस एट्रिब्यूट का सबसे आसान इस्तेमाल, टारगेट को सिर्फ़ एक प्लैटफ़ॉर्म पर सीमित कर देता है. टारगेट, ऐसे किसी भी प्लैटफ़ॉर्म के लिए नहीं बनाया जाएगा जो सभी तरह की शर्तों को पूरा नहीं करता. नीचे दिए गए उदाहरण में, Windows के लिए win_driver_lib.cc से 64-बिट तक सीमित इस्तेमाल किया जा रहा है.

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 वाले डिवाइसों पर इस्तेमाल किया जा सकता है. यह Windows के अन्य वर्शन के साथ काम नहीं करता. साथ काम नहीं करता, लेकिन एक ही जगह पर दूसरे तरीके से काम नहीं किया जाता. जो टारगेट, काम न करने वाले टारगेट पर अस्थायी रूप से निर्भर करते हैं, उन्हें उनके साथ काम नहीं करने वाला टारगेट माना जाता है.

लक्ष्यों को कब स्किप किया जाता है?

अगर टारगेट को काम का नहीं माना जाता है और उन्हें टारगेट पैटर्न को बड़ा करने के हिस्से के तौर पर बिल्ड में शामिल किया जाता है, तो उन्हें छोड़ दिया जाता है. उदाहरण के लिए, नीचे दिए गए दो मैसेज, टारगेट पैटर्न एक्सपैंशन में काम न करने वाले टारगेट को छोड़ देते हैं.

$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all

test_suite में काम न करने वाले टेस्ट को भी --expand_test_suites के साथ कमांड लाइन पर 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

ज़्यादा एक्सप्रेसिव कंस्ट्रेंट

पाबंदियों को आसानी से समझाने के लिए, @platforms//:incompatible constraint_value का इस्तेमाल करें, जो कोई भी प्लैटफ़ॉर्म काम नहीं करता.

ज़्यादा मुश्किल पाबंदियों को दिखाने के लिए, @platforms//:incompatible के साथ select() का इस्तेमाल करें. उदाहरण के लिए, इसे बेसिक 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"],
    }),
)

ऊपर दिए गए मतलब को इस तरह समझा जा सकता है:

  1. macOS को टारगेट करते समय, टारगेट में कोई सीमा नहीं होती.
  2. Linux को टारगेट करते समय, टारगेट में कोई सीमा नहीं होती.
  3. ऐसा न होने पर, टारगेट में @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 का इस्तेमाल करके, काम न करने वाले टारगेट का पता लगाया जा रहा है

bazel cquery के Starlark आउटपुट फ़ॉर्मैट में, IncompatiblePlatformProvider का इस्तेमाल किया जा सकता है. इससे, काम न करने वाले टारगेट और काम न करने वाले टारगेट में फ़र्क़ किया जा सकता है.

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

$ cat example.cquery

def format(target):
  if "IncompatiblePlatformProvider" not in providers(target):
    return target.label
  return ""


$ bazel cquery //... --output=starlark --starlark:file=example.cquery

समस्याएं जिनके बारे में जानकारी है

काम न करने वाले टारगेट दिखने से जुड़ी पाबंदियों को अनदेखा करते हैं.