प्‍लेटफ़ॉर्म

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

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

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

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

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

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

  • क्रॉस-कंपाइलेशन बिल्ड - होस्ट और एक्ज़ीक्यूशन प्लैटफ़ॉर्म एक ही होते हैं, लेकिन टारगेट प्लैटफ़ॉर्म अलग होता है. उदाहरण के लिए, MacBook Pro पर चलने वाले 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 नाम का एक प्लैटफ़ॉर्म बनता है. साथ ही, यह बताता है कि यह किसी ऐसे एनवायरमेंट के बारे में बताता है जो 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 - डिफ़ॉल्ट रूप से @bazel_tools//platforms:host_platform पर सेट होता है
  • --platforms - डिफ़ॉल्ट रूप से @bazel_tools//platforms:target_platform पर सेट होता है

काम न करने वाले टारगेट को छोड़ना

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

इस एट्रिब्यूट का सबसे आसान इस्तेमाल, किसी टारगेट को एक प्लैटफ़ॉर्म तक सीमित करना है. जिस प्लैटफ़ॉर्म पर सभी शर्तें पूरी नहीं होती हैं उसके लिए, टारगेट बिल्ड नहीं किया जाएगा. यहां दिए गए उदाहरण में, 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

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's 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's 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

आम तौर पर होने वाली समस्याएं

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