टूलचेन

समस्या की शिकायत करें सोर्स देखें

इस पेज पर टूलचेन फ़्रेमवर्क के बारे में बताया गया है. इससे नियम बनाने वाले लोग, प्लैटफ़ॉर्म के आधार पर चुने गए टूल से अपने नियम के लॉजिक को हटा सकते हैं. हमारा सुझाव है कि आगे बढ़ने से पहले, नियम और प्लैटफ़ॉर्म के पेजों को पढ़ें. इस पेज पर बताया गया है कि टूलचेन की ज़रूरत क्यों होती है, उन्हें कैसे तय किया जाता है, और कैसे इस्तेमाल किया जाता है. साथ ही, इस पेज पर बताया गया है कि प्लैटफ़ॉर्म कंस्ट्रेंट के आधार पर, 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 परिभाषाएं बनाई जाती हैं. ये परिभाषाएं, भाषा के हिसाब से टारगेट को टूलचेन टाइप से जोड़ती हैं. साथ ही, इनसे वे कंस्ट्रेंट की जानकारी देती हैं जिससे Bazel को पता चलता है कि किसी प्लैटफ़ॉर्म के लिए टूलचेन सही है या नहीं.

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:barc_linux_toolchain के //bar_tools:toolchain_type रेफ़रंस का इस्तेमाल करें. इससे //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](/reference/command-line-reference#flag--extra_execution_platforms) and [--extra_toolchains`](/reference/command-line-reference#flag--extra_toolchains) में दिए गए कॉल से ली जाती है. होस्ट प्लैटफ़ॉर्म, एक्ज़ीक्यूशन के लिए उपलब्ध प्लैटफ़ॉर्म के तौर पर अपने-आप शामिल हो जाता है. उपलब्ध प्लैटफ़ॉर्म और टूलचेन को डिटरमिनिज़्म के लिए, क्रम वाली सूचियों के तौर पर ट्रैक किया जाता है. इसमें, सूची में पहले मौजूद आइटम को प्राथमिकता दी जाती है.

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

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

ध्यान दें: :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. उपलब्ध टूलचेन की सूची को फ़िल्टर करके, उन सभी टूलचेन को हटाया जाता है जो target_settings के बारे में बताती हैं, जो मौजूदा कॉन्फ़िगरेशन से मेल नहीं खाते.

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

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

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

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

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

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

अगर किसी मौजूदा नियम में टूलचेन सहायता जोड़ी जा रही है, तो --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