टूलचेन

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

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

वजह

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

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

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

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

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

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

# 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 प्रोवाइडर की जानकारी दिखाता है. ऐसा करने पर, Basel के टूलचेन डिपेंडेंसी को रिज़ॉल्व किया गया. ToolchainInfo ऑब्जेक्ट के फ़ील्ड, मौजूदा टूल के नियम से सेट किए जाते हैं. अगले सेक्शन में, इस नियम के बारे में बताया गया है कि इसमें एक barcinfo फ़ील्ड है, जिसमें BarcInfo ऑब्जेक्ट है.

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

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

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

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

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

आइए, 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

Basel को दिखेगा कि //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 नहीं.

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

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

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

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

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

ध्यान दें: :all, :*, और /... जैसे बदली नहीं जा सकने वाले टारगेट को, Baze के पैकेज लोडिंग मैकेनिज़्म के हिसाब से क्रम में लगाया जाता है. इसमें, लेक्सिकोग्राफ़िक ऑर्डर का इस्तेमाल होता है.

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

  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 फ़्लैग का इस्तेमाल करें. टूलचेन रिज़ॉल्यूशन के दौरान, फ़्लैग ऐसे टूलचेन टाइप या टारगेट नामों के लिए ज़्यादा शब्दों में जानकारी देता है जो रेगुलर एक्सप्रेशन वैरिएबल से मेल खाते हैं. सारी जानकारी देने के लिए, .* का इस्तेमाल किया जा सकता है. रिज़ॉल्यूशन प्रोसेस के दौरान, Basel की जांच और स्किप करने वाले टूलचेन के नाम जनरेट किए जाएंगे.

अगर आपको यह देखना है कि कौनसी 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