प्लैटफ़ॉर्म

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

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

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

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

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

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

platform(
    name = "linux_x86",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":glibc_2_25",
    ],
)

आम तौर पर काम की शर्तें और प्लैटफ़ॉर्म

नेटवर्क को एक जैसा रखने के लिए, Basel टीम ने सबसे लोकप्रिय सीपीयू आर्किटेक्चर और ऑपरेटिंग सिस्टम के लिए कंस्ट्रेंट डेफ़िनिशन वाली एक रिपॉज़िटरी (डेटा स्टोर करने की जगह) बनाए रखी है. ये सभी यूआरएल https://github.com/bazelbuild/platforms में मौजूद हैं.

Bazel में, प्लैटफ़ॉर्म की खास परिभाषा के तौर पर यह जानकारी शामिल होती है: @local_config_platform//:host. यह होस्ट प्लैटफ़ॉर्म की अपने-आप पहचानी गई वैल्यू है - यह उस प्लैटफ़ॉर्म के लिए अपने-आप पता लगाया गया प्लैटफ़ॉर्म है जिस पर Basel चल रहा है.

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

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

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

टारगेट कब स्किप किए जाते हैं?

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

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

अगर --expand_test_suites के साथ कमांड लाइन पर test_suite तय किया गया है, तो test_suite में काम न करने वाले टेस्ट को भी इसी तरह स्किप कर दिया जाता है. दूसरे शब्दों में, कमांड लाइन पर मौजूद test_suite टारगेट, :all और ... की तरह काम करते हैं. --noexpand_test_suites का इस्तेमाल करने से, टारगेटिंग का दायरा नहीं बढ़ता. साथ ही, जिन टारगेट के लिए काम न करने वाले टेस्ट इस्तेमाल किए गए हैं वे भी काम नहीं करते.

कमांड लाइन में, काम न करने वाला टारगेट साफ़ तौर पर बताने से गड़बड़ी का मैसेज मिलता है. साथ ही, बिल्ड फ़ेल हो जाता है.

$ 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 के 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

आम समस्याएं

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