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

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

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

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

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

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

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

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

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

शर्तों और प्लैटफ़ॉर्म तय करना

प्लैटफ़ॉर्म के लिए संभावित विकल्पों की जगह, constraint_setting और constraint_value नियमों का इस्तेमाल करके BUILD फ़ाइलों में तय की जाती है. 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 के साथ, प्लैटफ़ॉर्म की यह खास परिभाषा शामिल है: @platforms//host (इसे @bazel_tools//tools:host_platform के तौर पर भी जाना जाता है). यह अपने-आप पता लगाया गया होस्ट प्लैटफ़ॉर्म वैल्यू है. यह उस सिस्टम के लिए अपने-आप पता लगाए गए प्लैटफ़ॉर्म को दिखाता है जिस पर Bazel चल रहा है.

किसी बिल्ड के लिए प्लैटफ़ॉर्म तय करना

कमांड-लाइन फ़्लैग का इस्तेमाल करके, किसी बिल्ड के लिए होस्ट और टारगेट प्लैटफ़ॉर्म तय किए जा सकते हैं:

  • --host_platform - डिफ़ॉल्ट रूप से @bazel_tools//tools:host_platform
      पर सेट होता है
    • इस टारगेट को @platforms//host के तौर पर भी जाना जाता है. यह एक ऐसे रेपो नियम पर आधारित है जो होस्ट ओएस और सीपीयू का पता लगाता है और प्लैटफ़ॉर्म टारगेट लिखता है.
    • @platforms//host:constraints.bzl भी है, जो HOST_CONSTRAINTS नाम का एक अरे दिखाता है. इसका इस्तेमाल अन्य BUILD और Starlark फ़ाइलों में किया जा सकता है.
  • --platforms - डिफ़ॉल्ट रूप से होस्ट प्लैटफ़ॉर्म पर सेट होता है
    • इसका मतलब है कि जब कोई अन्य फ़्लैग सेट नहीं किया जाता है, तो @platforms//host टारगेट प्लैटफ़ॉर्म होता है.
    • अगर --host_platform सेट है और --platforms नहीं, तो --host_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

अगर --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"],
    }),
)

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

  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 output format में 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

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

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