टूलचेन

7.3 · 7.2 · 7.1 · 7.0 · 6.5

इस पेज पर टूलचेन फ़्रेमवर्क के बारे में बताया गया है. यह नियम बनाने वाले लोगों के लिए, अपने नियम के लॉजिक को प्लैटफ़ॉर्म के हिसाब से चुने गए टूल से अलग करने का एक तरीका है. हमारा सुझाव है कि जारी रखने से पहले, नियमों और प्लैटफ़ॉर्म के पेजों को पढ़ें. इस पेज पर बताया गया है कि टूलचेन की ज़रूरत क्यों होती है, उन्हें कैसे तय और इस्तेमाल किया जाता है, और प्लैटफ़ॉर्म की सीमाओं के आधार पर Bazel, सही टूलचेन कैसे चुनता है.

वजह

आइए, सबसे पहले उन समस्या टूलचेन पर नज़र डालते हैं जिन्हें हल करने के लिए डिज़ाइन किया गया है. मान लीजिए कि आपको "bar" प्रोग्रामिंग भाषा का इस्तेमाल करने के लिए नियम लिखने हैं. आपका bar_binary नियम, barc कंपाइलर का इस्तेमाल करके *.bar फ़ाइलों को कंपाइल करेगा. यह टूल, आपके वर्कस्पेस में किसी अन्य टारगेट के तौर पर बनाया गया है. bar_binary टारगेट लिखने वाले उपयोगकर्ताओं को कंपाइलर पर डिपेंडेंसी तय करने की ज़रूरत नहीं होती. इसलिए, इसे निजी एट्रिब्यूट के तौर पर नियम की परिभाषा में जोड़कर, इसे डिपेंडेंसी के तौर पर लागू किया जाता है.

bar_binary = rule(
    implementation = _bar_binary_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = True),
        ...
        "_compiler": attr.label(
            default = "//bar_tools:barc_linux",  # the compiler running on linux
            providers = [BarcInfo],
        ),
    },
)

//bar_tools:barc_linux अब हर bar_binary टारगेट की डिपेंडेंसी है. इसलिए, इसे किसी भी bar_binary टारगेट से पहले बनाया जाएगा. इसे किसी भी दूसरे एट्रिब्यूट की तरह, नियम के लागू करने वाले फ़ंक्शन से ऐक्सेस किया जा सकता है:

BarcInfo = provider(
    doc = "Information about how to invoke the barc compiler.",
    # In the real world, compiler_path and system_lib might hold File objects,
    # but for simplicity they are strings for this example. arch_flags is a list
    # of strings.
    fields = ["compiler_path", "system_lib", "arch_flags"],
)

def _bar_binary_impl(ctx):
    ...
    info = ctx.attr._compiler[BarcInfo]
    command = "%s -l %s %s" % (
        info.compiler_path,
        info.system_lib,
        " ".join(info.arch_flags),
    )
    ...

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

_compiler एट्रिब्यूट को 'निजी नहीं' के तौर पर सेट करके, उपयोगकर्ताओं पर बोझ डालना एक अच्छा तरीका नहीं है. इसके बाद, किसी एक प्लैटफ़ॉर्म के लिए बनाने के लिए, अलग-अलग टारगेट को हार्डकोड किया जा सकता है.

bar_binary(
    name = "myprog_on_linux",
    srcs = ["mysrc.bar"],
    compiler = "//bar_tools:barc_linux",
)

bar_binary(
    name = "myprog_on_windows",
    srcs = ["mysrc.bar"],
    compiler = "//bar_tools:barc_windows",
)

इस तरीके को बेहतर बनाया जा सकता है. इसके लिए, select का इस्तेमाल करके compiler को चुनें. ऐसा प्लैटफ़ॉर्म के हिसाब से किया जा सकता है:

config_setting(
    name = "on_linux",
    constraint_values = [
        "@platforms//os:linux",
    ],
)

config_setting(
    name = "on_windows",
    constraint_values = [
        "@platforms//os:windows",
    ],
)

bar_binary(
    name = "myprog",
    srcs = ["mysrc.bar"],
    compiler = select({
        ":on_linux": "//bar_tools:barc_linux",
        ":on_windows": "//bar_tools:barc_windows",
    }),
)

हालांकि, यह हर bar_binary उपयोगकर्ता से पूछना मुश्किल और थोड़ा ज़्यादा है. अगर पूरे वर्कस्पेस में इस स्टाइल का लगातार इस्तेमाल नहीं किया जाता है, तो ऐसे बिल्ड बनते हैं जो एक प्लैटफ़ॉर्म पर ठीक से काम करते हैं, लेकिन कई प्लैटफ़ॉर्म पर काम नहीं करते. इससे, मौजूदा नियमों या टारगेट में बदलाव किए बिना, नए प्लैटफ़ॉर्म और कंपाइलर के लिए सहायता जोड़ने की समस्या भी हल नहीं होती.

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

टूलचेन का इस्तेमाल करने वाले नियम लिखना

टूलचेन फ़्रेमवर्क में, नियम सीधे तौर पर टूल पर निर्भर नहीं होते, बल्कि टूलचेन टाइप पर निर्भर होते हैं. टूलचेन टाइप, एक सामान्य टारगेट होता है. यह ऐसे टूल की कैटगरी को दिखाता है जो अलग-अलग प्लैटफ़ॉर्म के लिए एक ही भूमिका में होते हैं. उदाहरण के लिए, बार कंपाइलर को दिखाने वाला टाइप तय किया जा सकता है:

# By convention, toolchain_type targets are named "toolchain_type" and
# distinguished by their package path. So the full path for this would be
# //bar_tools:toolchain_type.
toolchain_type(name = "toolchain_type")

पिछले सेक्शन में दिए गए नियम की परिभाषा में बदलाव किया गया है, ताकि कंपाइलर को एट्रिब्यूट के तौर पर इस्तेमाल करने के बजाय, यह बताया जाए कि वह //bar_tools:toolchain_type टूलचेन का इस्तेमाल करता है.

bar_binary = rule(
    implementation = _bar_binary_impl,
    attrs = {
        "srcs": attr.label_list(allow_files = True),
        ...
        # No `_compiler` attribute anymore.
    },
    toolchains = ["//bar_tools:toolchain_type"],
)

लागू करने का फ़ंक्शन, अब इस डिपेंडेंसी को ctx.attr के बजाय ctx.toolchains में ऐक्सेस करता है. इसके लिए, टूलचेन टाइप को कुंजी के तौर पर इस्तेमाल किया जाता है.

def _bar_binary_impl(ctx):
    ...
    info = ctx.toolchains["//bar_tools:toolchain_type"].barcinfo
    # The rest is unchanged.
    command = "%s -l %s %s" % (
        info.compiler_path,
        info.system_lib,
        " ".join(info.arch_flags),
    )
    ...

ctx.toolchains["//bar_tools:toolchain_type"], उस टारगेट के ToolchainInfo प्रोवाइडर की जानकारी दिखाता है जिसके लिए Bazel ने टूलचेन की डिपेंडेंसी को हल किया है. ToolchainInfo ऑब्जेक्ट के फ़ील्ड, मौजूदा टूल के नियम से सेट किए जाते हैं. अगले सेक्शन में, इस नियम के बारे में बताया गया है कि इसमें एक barcinfo फ़ील्ड है, जो BarcInfo ऑब्जेक्ट को रैप करता है.

टारगेट के लिए टूलचेन को हल करने के Bazel के तरीके के बारे में यहां बताया गया है. असल में, सिर्फ़ समाधान हो चुके टूलचेन टारगेट को bar_binary टारगेट पर निर्भर करता है, न कि उम्मीदवार के टूलचेन के पूरे स्पेस पर.

ज़रूरी और वैकल्पिक टूलचेन

डिफ़ॉल्ट रूप से, जब कोई नियम बिना लेबल के (जैसा कि ऊपर दिखाया गया है) टूलचेन टाइप की डिपेंडेंसी दिखाता है, तो टूलचेन टाइप को ज़रूरी माना जाता है. अगर Bazel, ज़रूरी टूलचेन टाइप के लिए मैच करने वाला टूलचेन (नीचे टूलचेन रिज़ॉल्यूशन देखें) नहीं ढूंढ पाता है, तो यह गड़बड़ी होती है और विश्लेषण रुक जाता है.

इसके बजाय, ज़रूरी नहीं टूलचेन टाइप की डिपेंडेंसी का एलान इस तरह किया जा सकता है:

bar_binary = rule(
    ...
    toolchains = [
        config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False),
    ],
)

अगर किसी वैकल्पिक टूलचेन टाइप को हल नहीं किया जा सकता, तो विश्लेषण जारी रहता है और ctx.toolchains["//bar_tools:toolchain_type"] का नतीजा None होता है.

config_common.toolchain_type फ़ंक्शन, डिफ़ॉल्ट रूप से ज़रूरी पर सेट होता है.

इन फ़ॉर्म का इस्तेमाल किया जा सकता है:

  • ज़रूरी टूलचेन टाइप:
    • toolchains = ["//bar_tools:toolchain_type"]
    • toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type")]
    • toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = True)]
  • टूलचेन के वैकल्पिक टाइप:
    • toolchains = [config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False)]
bar_binary = rule(
    ...
    toolchains = [
        "//foo_tools:toolchain_type",
        config_common.toolchain_type("//bar_tools:toolchain_type", mandatory = False),
    ],
)

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

टूलचेन का इस्तेमाल करने वाले हिस्से लिखना

नियमों की तरह ही, ऐस्पेक्ट के पास भी उसी टूलचेन एपीआई का ऐक्सेस होता है: ज़रूरी टूलचेन टाइप तय किए जा सकते हैं, संदर्भ के ज़रिए टूलचेन ऐक्सेस किए जा सकते हैं, और टूलचेन का इस्तेमाल करके नई कार्रवाइयां जनरेट करने के लिए उनका इस्तेमाल किया जा सकता है.

bar_aspect = aspect(
    implementation = _bar_aspect_impl,
    attrs = {},
    toolchains = ['//bar_tools:toolchain_type'],
)

def _bar_aspect_impl(target, ctx):
  toolchain = ctx.toolchains['//bar_tools:toolchain_type']
  # Use the toolchain provider like in a rule.
  return []

टूलचेन तय करना

किसी टूलचेन टाइप के लिए कुछ टूलचेन तय करने के लिए, आपको तीन चीज़ों की ज़रूरत होगी:

  1. भाषा के हिसाब से बना नियम, जो टूल या टूल सुइट के बारे में बताता है. आम तौर पर, इस नियम के नाम के आखिर में "_toolchain" जोड़ा जाता है.

    1. ध्यान दें: \_toolchain नियम से कोई बिल्ड ऐक्शन नहीं बनाया जा सकता. इसके बजाय, यह दूसरे नियमों से आर्टफ़ैक्ट इकट्ठा करके, उन्हें टूलचेन का इस्तेमाल करने वाले नियम पर भेजता है. यह नियम, सभी बिल्ड ऐक्शन बनाने के लिए ज़िम्मेदार है.
  2. इस तरह के नियम के कई टारगेट, अलग-अलग प्लैटफ़ॉर्म के लिए टूल या टूल सुइट के वर्शन दिखाते हैं.

  3. इस तरह के हर टारगेट के लिए, टूलचेन फ़्रेमवर्क का इस्तेमाल किया जाने वाला मेटाडेटा देने के लिए, सामान्य toolchain नियम से जुड़ा टारगेट. यह toolchain टारगेट, इस टूलचेन से जुड़े toolchain_type को भी रेफ़र करता है. इसका मतलब है कि कोई _toolchain नियम किसी भी toolchain_type से जुड़ा हो सकता है. साथ ही, यह भी कि सिर्फ़ इस _toolchain नियम का इस्तेमाल करने वाले toolchain इंस्टेंस में, नियम toolchain_type से जुड़ा होता है.

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

def _bar_toolchain_impl(ctx):
    toolchain_info = platform_common.ToolchainInfo(
        barcinfo = BarcInfo(
            compiler_path = ctx.attr.compiler_path,
            system_lib = ctx.attr.system_lib,
            arch_flags = ctx.attr.arch_flags,
        ),
    )
    return [toolchain_info]

bar_toolchain = rule(
    implementation = _bar_toolchain_impl,
    attrs = {
        "compiler_path": attr.string(),
        "system_lib": attr.string(),
        "arch_flags": attr.string_list(),
    },
)

नियम से ToolchainInfo प्रोवाइडर दिखना चाहिए. यह वह ऑब्जेक्ट होता है जिसे इस्तेमाल करने वाला नियम, ctx.toolchains और टूलचेन टाइप के लेबल का इस्तेमाल करके, फिर से पाता है. struct की तरह, ToolchainInfo में आर्बिट्रेरी फ़ील्ड-वैल्यू पेयर को होल्ड किया जा सकता है. ToolchainInfo में कौनसे फ़ील्ड जोड़े गए हैं, इसकी जानकारी टूलचेन टाइप में साफ़ तौर पर दी जानी चाहिए. इस उदाहरण में, ऊपर बताए गए स्कीमा का फिर से इस्तेमाल करने के लिए, वैल्यू को BarcInfo ऑब्जेक्ट में लपेटकर दिखाया गया है. पुष्टि करने और कोड का फिर से इस्तेमाल करने के लिए, यह स्टाइल काम की हो सकती है.

अब किसी खास barc कंपाइलर के लिए, टारगेट तय किए जा सकते हैं.

bar_toolchain(
    name = "barc_linux",
    arch_flags = [
        "--arch=Linux",
        "--debug_everything",
    ],
    compiler_path = "/path/to/barc/on/linux",
    system_lib = "/usr/lib/libbarc.so",
)

bar_toolchain(
    name = "barc_windows",
    arch_flags = [
        "--arch=Windows",
        # Different flags, no debug support on windows.
    ],
    compiler_path = "C:\\path\\on\\windows\\barc.exe",
    system_lib = "C:\\path\\on\\windows\\barclib.dll",
)

आखिर में, दो bar_toolchain टारगेट के लिए toolchain डेफ़िनिशन बनाई जाती हैं. ये परिभाषाएं, भाषा के हिसाब से तय किए गए टारगेट को टूलचेन टाइप से लिंक करती हैं. साथ ही, ये कंस्ट्रेंट से जुड़ी जानकारी देती हैं, जिससे बेज़ल को यह पता चलता है कि टूलचेन किसी प्लैटफ़ॉर्म के लिए सही है या नहीं.

toolchain(
    name = "barc_linux_toolchain",
    exec_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
    ],
    target_compatible_with = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
    ],
    toolchain = ":barc_linux",
    toolchain_type = ":toolchain_type",
)

toolchain(
    name = "barc_windows_toolchain",
    exec_compatible_with = [
        "@platforms//os:windows",
        "@platforms//cpu:x86_64",
    ],
    target_compatible_with = [
        "@platforms//os:windows",
        "@platforms//cpu:x86_64",
    ],
    toolchain = ":barc_windows",
    toolchain_type = ":toolchain_type",
)

ऊपर दिए गए रिलेटिव पाथ सिंटैक्स का इस्तेमाल यह बताता है कि ये सभी परिभाषाएं एक ही पैकेज में हैं. हालांकि, टूलचेन टाइप, भाषा के हिसाब से टूलचेन टारगेट, और toolchain डेफ़िनिशन टारगेट, अलग-अलग पैकेज में नहीं हो सकते.

असल दुनिया के उदाहरण के लिए, go_toolchain देखें.

टूलचेन और कॉन्फ़िगरेशन

नियम बनाने वालों के लिए एक अहम सवाल यह है कि जब किसी bar_toolchain टारगेट का विश्लेषण किया जाता है, तो उसे कौनसा कॉन्फ़िगरेशन दिखता है और डिपेंडेंसी के लिए किन ट्रांज़िशन का इस्तेमाल किया जाना चाहिए? ऊपर दिए गए उदाहरण में स्ट्रिंग एट्रिब्यूट का इस्तेमाल किया गया है. हालांकि, Bazel रिपॉज़िटरी में मौजूद अन्य टारगेट पर निर्भर, ज़्यादा जटिल टूलचेन के लिए क्या होगा?

आइए, bar_toolchain का ज़्यादा जटिल वर्शन देखते हैं:

def _bar_toolchain_impl(ctx):
    # The implementation is mostly the same as above, so skipping.
    pass

bar_toolchain = rule(
    implementation = _bar_toolchain_impl,
    attrs = {
        "compiler": attr.label(
            executable = True,
            mandatory = True,
            cfg = "exec",
        ),
        "system_lib": attr.label(
            mandatory = True,
            cfg = "target",
        ),
        "arch_flags": attr.string_list(),
    },
)

attr.label का इस्तेमाल, स्टैंडर्ड नियम के लिए इस्तेमाल किए जाने वाले नियम की तरह ही किया जाता है. हालांकि, cfg पैरामीटर का मतलब थोड़ा अलग है.

टूलचेन रिज़ॉल्यूशन की मदद से, किसी टारगेट (जिसे "पैरंट" कहा जाता है) से टूलचेन पर निर्भरता, "टूलचेन ट्रांज़िशन" नाम के एक खास कॉन्फ़िगरेशन ट्रांज़िशन का इस्तेमाल करती है. टूलचेन ट्रांज़िशन, कॉन्फ़िगरेशन को पहले जैसा ही रखता है. हालांकि, यह ज़रूरी नहीं है कि एक्ज़ीक्यूशन प्लैटफ़ॉर्म को टूलचेन के लिए पैरंट जैसा ही रहे. ऐसा न करने पर, टूलचेन के लिए टूलचेन रिज़ॉल्यूशन किसी भी एक्ज़ीक्यूशन प्लैटफ़ॉर्म को चुन सकता है और यह ज़रूरी नहीं है कि पैरंट के लिए वैसा ही रहे. इससे, टूलचेन की किसी भी exec डिपेंडेंसी को पैरंट की बिल्ड कार्रवाइयों के लिए भी चलाया जा सकता है. टूलचेन की ऐसी सभी डिपेंडेंसी जो cfg = "target" का इस्तेमाल करती हैं (या जो cfg की जानकारी नहीं देती हैं, क्योंकि "टारगेट" डिफ़ॉल्ट है) उन्हें पैरंट के टारगेट प्लैटफ़ॉर्म के लिए बनाया जाता है. इससे टूलचेन के नियमों को, उन बिल्ड नियमों में लाइब्रेरी (ऊपर दिया गया system_lib एट्रिब्यूट) और टूल (compiler एट्रिब्यूट) दोनों का योगदान देने की अनुमति मिलती है जिनमें इनकी ज़रूरत होती है. सिस्टम लाइब्रेरी, आखिरी आर्टफ़ैक्ट से लिंक होती हैं. इसलिए, उन्हें उसी प्लैटफ़ॉर्म के लिए बनाया जाना चाहिए. वहीं, कंपाइलर एक ऐसा टूल है जिसे बिल्ड के दौरान ट्रिगर किया जाता है. साथ ही, उसे उस प्लैटफ़ॉर्म पर चलाया जा सकता है जिस पर प्रोग्राम को चलाया जा रहा है.

टूलचेन की मदद से रजिस्टर करना और बिल्ड करना

इस स्थिति में सभी बिल्डिंग ब्लॉक इकट्ठा हो जाते हैं और आपको बस बेज़ल की रिज़ॉल्यूशन प्रोसेस के लिए टूलचेन उपलब्ध कराने की ज़रूरत होती है. इसके लिए, टूलचेन को रजिस्टर किया जाता है. इसे register_toolchains() का इस्तेमाल करके, MODULE.bazel फ़ाइल में रजिस्टर किया जाता है या कमांड लाइन पर टूलचेन के लेबल पास करने के लिए, --extra_toolchains फ़्लैग का इस्तेमाल किया जाता है.

register_toolchains(
    "//bar_tools:barc_linux_toolchain",
    "//bar_tools:barc_windows_toolchain",
    # Target patterns are also permitted, so you could have also written:
    # "//bar_tools:all",
    # or even
    # "//bar_tools/...",
)

टूलचेन को रजिस्टर करने के लिए टारगेट पैटर्न का इस्तेमाल करते समय, अलग-अलग टूलचेन के रजिस्ट्रेशन का क्रम इन नियमों के आधार पर तय होता है:

  • किसी पैकेज के सबपैकेज में तय किए गए टूलचेन को, पैकेज में बताए गए टूलचेन से पहले रजिस्टर किया जाता है.
  • किसी पैकेज में, टूलचेन उनके नामों के वर्णमाला के क्रम में रजिस्टर किए जाते हैं.

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

# my_pkg/BUILD

platform(
    name = "my_target_platform",
    constraint_values = [
        "@platforms//os:linux",
    ],
)

bar_binary(
    name = "my_bar_binary",
    ...
)
bazel build //my_pkg:my_bar_binary --platforms=//my_pkg:my_target_platform

Bazel को पता चलेगा कि //my_pkg:my_bar_binary को ऐसे प्लैटफ़ॉर्म के साथ बनाया जा रहा है जिसमें @platforms//os:linux है. इसलिए, वह //bar_tools:toolchain_type के रेफ़रंस को //bar_tools:barc_linux_toolchain में बदल देगा. इससे //bar_tools:barc_linux बन जाएगा, लेकिन //bar_tools:barc_windows नहीं.

टूलचेन रिज़ॉल्यूशन

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

उपलब्ध एक्ज़ीक्यूशन प्लैटफ़ॉर्म और टूलचेन register_execution_platforms और register_toolchains कॉल इन MODULE.bazelfiles. Additional execution platforms and toolchains may also be specified on the command line via [--extra_execution_platforms](/versions/7.4.0/reference/command-line-reference#flag--extra_execution_platforms) and [--extra_toolchains`](/versions/7.4.0/reference/command-line-reference#flag--extra_toolchains) के ज़रिए बाहरी डिपेंडेंसी ग्राफ़ से इकट्ठा किए जाते हैं. होस्ट प्लैटफ़ॉर्म, उपलब्ध एक्सीक्यूशन प्लैटफ़ॉर्म के तौर पर अपने-आप शामिल हो जाता है. उपलब्ध प्लैटफ़ॉर्म और टूलचेन को क्रम से लगाई गई सूचियों के तौर पर ट्रैक किया जाता है, ताकि यह तय किया जा सके कि कौनसा प्लैटफ़ॉर्म और टूलचेन इस्तेमाल करना है. सूची में पहले आइटम को प्राथमिकता दी जाती है.

प्राथमिकता के क्रम में, उपलब्ध टूलचेन का सेट, --extra_toolchains और register_toolchains से बनाया जाता है:

  1. --extra_toolchains का इस्तेमाल करके रजिस्टर किए गए टूलचेन पहले जोड़े जाते हैं. (इनमें, पिछले टूलचेन को सबसे ज़्यादा प्राथमिकता दी जाती है.)
  2. नीचे दिए गए क्रम में, ट्रांज़िटिव एक्सटर्नल डिपेंडेंसी ग्राफ़ में register_toolchains का इस्तेमाल करके रजिस्टर किए गए टूलचेन: (इनमें पहले टैग किए गए टूलचेन को सबसे ज़्यादा प्राथमिकता दी जाती है.)
    1. रूट मॉड्यूल से रजिस्टर किए गए टूलचेन (जैसे, वर्कस्पेस रूट में MODULE.bazel);
    2. उपयोगकर्ता की WORKSPACE फ़ाइल में रजिस्टर किए गए टूलचेन. इनमें डिवाइस से सक्रिय हुए सभी मैक्रो भी शामिल हैं;
    3. नॉन-रूट मॉड्यूल की मदद से रजिस्टर किए गए टूलचेन (जैसे, रूट मॉड्यूल की बताई गई डिपेंडेंसी और उनकी डिपेंडेंसी वगैरह);
    4. "वर्कस्पेस सफ़िक्स" में रजिस्टर किए गए टूलचेन. इसका इस्तेमाल सिर्फ़ उन खास स्थानीय नियमों के लिए किया जाता है जो Basel इंस्टॉलेशन के साथ बंडल किए गए हैं.

ध्यान दें: :all, :*, और /... जैसे 'स्यूडो-टारगेट' को, Bazel के पैकेज लोड करने के तरीके के हिसाब से क्रम में लगाया जाता है. यह तरीका, शब्दकोश के क्रम का इस्तेमाल करता है.

समस्या को ठीक करने का तरीका यहां बताया गया है.

  1. target_compatible_with या exec_compatible_with क्लॉज़, किसी प्लैटफ़ॉर्म से मेल खाता है. ऐसा तब होता है, जब प्लैटफ़ॉर्म की सूची में मौजूद हर constraint_value के लिए, वह constraint_value (खास तौर पर या डिफ़ॉल्ट के तौर पर) भी मौजूद हो.

    अगर प्लैटफ़ॉर्म पर constraint_setting से मिले constraint_value हैं, जिनका क्लॉज़ में रेफ़रंस नहीं दिया गया है, तो इनसे मैचिंग पर कोई असर नहीं पड़ता.

  2. अगर बनाया जा रहा टारगेट exec_compatible_with एट्रिब्यूट के बारे में बताता है (या इसके नियम की परिभाषा में exec_compatible_with आर्ग्युमेंट के बारे में बताया गया है), तो उपलब्ध एक्ज़ीक्यूशन प्लैटफ़ॉर्म की सूची, ऐसे किसी भी प्लैटफ़ॉर्म को हटाने के लिए फ़िल्टर की जाती है जो एक्ज़ीक्यूशन कंस्ट्रेंट से मेल नहीं खाता.

  3. हर उपलब्ध एक्सीक्यूशन प्लैटफ़ॉर्म के लिए, हर तरह के टूलचेन को पहले उपलब्ध टूलचेन से जोड़ा जाता है. हालांकि, ऐसा तब ही किया जाता है, जब वह टूलचेन, एक्सीक्यूशन प्लैटफ़ॉर्म और टारगेट प्लैटफ़ॉर्म के साथ काम करता हो.

  4. ऐसा कोई भी एक्ज़ीक्यूशन प्लैटफ़ॉर्म, जो अपने किसी टूलचेन टाइप के साथ काम करने वाला ज़रूरी टूलचेन नहीं ढूंढ पाता है, उसे प्रोसेस नहीं किया जाएगा. बाकी बचे प्लैटफ़ॉर्म में से पहला प्लैटफ़ॉर्म, मौजूदा टारगेट का एक्सीक्यूशन प्लैटफ़ॉर्म बन जाता है. साथ ही, उससे जुड़े टूलचेन (अगर कोई है) टारगेट की डिपेंडेंसी बन जाते हैं.

चुने गए एक्सीक्यूशन प्लैटफ़ॉर्म का इस्तेमाल, उन सभी कार्रवाइयों को चलाने के लिए किया जाता है जिन्हें टारगेट जनरेट करता है.

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

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

टूलचेन डीबग करना

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

अगर आपको यह देखना है कि cquery की कौनसी डिपेंडेंसी, टूलचेन के रिज़ॉल्यूशन से हैं, तो cquery के --transitions फ़्लैग का इस्तेमाल करें:

# Find all direct dependencies of //cc:my_cc_lib. This includes explicitly
# declared dependencies, implicit dependencies, and toolchain dependencies.
$ bazel cquery 'deps(//cc:my_cc_lib, 1)'
//cc:my_cc_lib (96d6638)
@bazel_tools//tools/cpp:toolchain (96d6638)
@bazel_tools//tools/def_parser:def_parser (HOST)
//cc:my_cc_dep (96d6638)
@local_config_platform//:host (96d6638)
@bazel_tools//tools/cpp:toolchain_type (96d6638)
//:default_host_platform (96d6638)
@local_config_cc//:cc-compiler-k8 (HOST)
//cc:my_cc_lib.cc (null)
@bazel_tools//tools/cpp:grep-includes (HOST)

# Which of these are from toolchain resolution?
$ bazel cquery 'deps(//cc:my_cc_lib, 1)' --transitions=lite | grep "toolchain dependency"
  [toolchain dependency]#@local_config_cc//:cc-compiler-k8#HostTransition -> b6df211