इस पेज पर, टूलचेन फ़्रेमवर्क के बारे में बताया गया है. इसकी मदद से, नियम लिखने वाले लोग, टूल के प्लैटफ़ॉर्म के हिसाब से चुने जाने की प्रोसेस से, अपने नियम की लॉजिक को अलग कर सकते हैं. हमारा सुझाव है कि आगे बढ़ने से पहले, नियमों और प्लैटफ़ॉर्म के बारे में जानकारी देने वाले पेज पढ़ लें. इस पेज पर, टूलचेन की ज़रूरत क्यों होती है, उन्हें कैसे तय और इस्तेमाल किया जाता है, और प्लैटफ़ॉर्म की पाबंदियों के आधार पर Bazel, सही टूलचेन कैसे चुनता है, इस बारे में बताया गया है.
वजह
सबसे पहले, उस समस्या के बारे में जानते हैं जिसे हल करने के लिए टूलचेन बनाए गए हैं. मान लें कि "बार" प्रोग्रामिंग भाषा के लिए नियम लिखे जा रहे हैं. आपका 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 उपयोगकर्ता से ऐसा करने के लिए कहना सही नहीं है.
अगर इस स्टाइल का इस्तेमाल, पूरे वर्कस्पेस में एक जैसा नहीं किया जाता है, तो ऐसे बिल्ड बनते हैं जो किसी एक प्लैटफ़ॉर्म पर तो ठीक से काम करते हैं, लेकिन मल्टी-प्लैटफ़ॉर्म वाले सिनेरियो में काम नहीं करते. साथ ही, इससे मौजूदा नियमों या टारगेट में बदलाव किए बिना, नए प्लैटफ़ॉर्म और कंपाइलर के लिए सहायता जोड़ने की समस्या भी हल नहीं होती.
टूलचेन फ़्रेमवर्क, इनडायरेक्शन का एक और लेवल जोड़कर इस समस्या को हल करता है. असल में, आपको यह एलान करना होता है कि आपके नियम में, टारगेट के किसी परिवार (टूलचेन टाइप) के किसी सदस्य पर कोई ऐब्स्ट्रैक्ट डिपेंडेंसी है. इसके बाद, 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 होता है.
The 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 []
टूलचेन तय करना
किसी दिए गए टूलचेन टाइप के लिए कुछ टूलचेन तय करने के लिए, आपको इन तीन चीज़ों की ज़रूरत होती है:
भाषा के हिसाब से कोई नियम. यह नियम, टूल या टूल सुइट के टाइप को दिखाता है. आम तौर पर, इस नियम के नाम के आखिर में "_toolchain" जोड़ा जाता है.
- ध्यान दें:
\_toolchainनियम, कोई भी बिल्ड ऐक्शन नहीं बना सकता. इसके बजाय, यह अन्य नियमों से आर्टफ़ैक्ट इकट्ठा करता है और उन्हें उस नियम को फ़ॉरवर्ड करता है जो टूलचेन का इस्तेमाल करता है. सभी बिल्ड ऐक्शन बनाने की ज़िम्मेदारी उस नियम की होती है.
- ध्यान दें:
इस नियम टाइप के कई टारगेट. ये टारगेट, अलग-अलग प्लैटफ़ॉर्म के लिए टूल या टूल सुइट के वर्शन दिखाते हैं.
ऐसे हर टारगेट के लिए, सामान्य
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 और टूलचेन टाइप के लेबल का इस्तेमाल करके वापस पाता है. ToolchainInfo, struct की तरह, फ़ील्ड-वैल्यू के जोड़े को सेव कर सकता है. 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",
)
आखिर में, toolchain के दो bar_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 तय नहीं करती, क्योंकि "target" डिफ़ॉल्ट है), उसे
पैरंट के जैसे ही टारगेट प्लैटफ़ॉर्म के लिए बनाया जाता है. इससे, टूलचेन के नियम, बिल्ड के उन नियमों में लाइब्रेरी (system_lib एट्रिब्यूट) और टूल (compiler एट्रिब्यूट) दोनों को शामिल कर सकते हैं जिनकी उन्हें ज़रूरत होती है. सिस्टम लाइब्रेरी को फ़ाइनल आर्टफ़ैक्ट में लिंक किया जाता है. इसलिए, उन्हें एक ही प्लैटफ़ॉर्म के लिए बनाया जाना चाहिए. वहीं, कंपाइलर एक ऐसा टूल है जिसे बिल्ड के दौरान इस्तेमाल किया जाता है. इसलिए, यह एक्ज़ीक्यूशन प्लैटफ़ॉर्म पर चल सकता है.
टूलचेन रजिस्टर करना और उनकी मदद से बिल्ड करना
इस समय, सभी बिल्डिंग ब्लॉक इकट्ठा हो गए हैं. अब आपको सिर्फ़ Bazel की रिज़ॉल्यूशन प्रोसेस के लिए टूलचेन उपलब्ध कराने हैं. इसके लिए, टूलचेन को रजिस्टर करें. इसके लिए, MODULE.bazel फ़ाइल में register_toolchains() का इस्तेमाल करें या --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.bazel फ़ाइलों में इकट्ठा किए जाते हैं.
कमांड लाइन पर --extra_execution_platforms
और
--extra_toolchains के ज़रिए, अतिरिक्त एक्ज़ीक्यूशन प्लैटफ़ॉर्म और टूलचेन भी तय किए जा सकते हैं.
होस्ट प्लैटफ़ॉर्म को, उपलब्ध एक्ज़ीक्यूशन प्लैटफ़ॉर्म के तौर पर अपने-आप शामिल किया जाता है.
उपलब्ध प्लैटफ़ॉर्म और टूलचेन को, तय क्रम में सूचियों के तौर पर ट्रैक किया जाता है. इसमें, सूची में मौजूद पहले आइटम को प्राथमिकता दी जाती है.
प्राथमिकता के क्रम में, उपलब्ध टूलचेन का सेट, --extra_toolchains और register_toolchains से बनाया जाता है:
--extra_toolchainsका इस्तेमाल करके रजिस्टर किए गए टूलचेन, सबसे पहले जोड़े जाते हैं. (इनमें, आखिरी टूलचेन को सबसे ज़्यादा प्राथमिकता मिलती है.)- ट्रांज़िटिव बाहरी डिपेंडेंसी ग्राफ़ में,
register_toolchainsका इस्तेमाल करके रजिस्टर किए गए टूलचेन. इन्हें इस क्रम में रजिस्टर किया जाता है: (इनमें, पहले बताए गए टूलचेन को सबसे ज़्यादा प्राथमिकता मिलती है.)- रूट मॉड्यूल से रजिस्टर किए गए टूलचेन (जैसे, वर्कस्पेस रूट पर मौजूद
MODULE.bazel); - उपयोगकर्ता की
WORKSPACEफ़ाइल में रजिस्टर किए गए टूलचेन. इनमें, वहां से शुरू किए गए मैक्रो भी शामिल हैं. - नॉन-रूट मॉड्यूल से रजिस्टर किए गए टूलचेन (जैसे, रूट मॉड्यूल से तय की गई डिपेंडेंसी और उनकी डिपेंडेंसी वगैरह);
- "WORKSPACE सफ़िक्स" में रजिस्टर किए गए टूलचेन. इसका इस्तेमाल सिर्फ़ Bazel इंस्टॉलेशन के साथ बंडल किए गए कुछ नेटिव नियमों से किया जाता है.
- रूट मॉड्यूल से रजिस्टर किए गए टूलचेन (जैसे, वर्कस्पेस रूट पर मौजूद
ध्यान दें: :all, :*, और
/... जैसे स्यूडो-टारगेट को, Bazel के पैकेज
लोड करने के मैकेनिज़्म के हिसाब से क्रम में लगाया जाता है. यह मैकेनिज़्म, लेक्सिकोग्राफ़िक क्रम का इस्तेमाल करता है.
इन्हें हल करने का तरीका यहां दिया गया है.
अगर किसी प्लैटफ़ॉर्म की सूची में मौजूद हर
constraint_value, प्लैटफ़ॉर्म में भी मौजूद है, तोtarget_compatible_withयाexec_compatible_withक्लॉज़, उस प्लैटफ़ॉर्म से मैच करता है. ऐसा तब होता है, जब प्लैटफ़ॉर्म में वहconstraint_valueसाफ़ तौर पर या डिफ़ॉल्ट के तौर पर मौजूद हो.अगर प्लैटफ़ॉर्म में
constraint_settingसेconstraint_valueमौजूद हैं और क्लॉज़ में उनका रेफ़रंस नहीं दिया गया है, तो इनसे मैचिंग पर कोई असर नहीं पड़ता.अगर बिल्ड किए जा रहे टारगेट में
exec_compatible_withएट्रिब्यूट तय किया गया है (या उसके नियम की डेफ़िनिशन मेंexec_compatible_withआर्ग्युमेंट तय किया गया है), तो उपलब्ध एक्ज़ीक्यूशन प्लैटफ़ॉर्म की सूची को फ़िल्टर किया जाता है. इसमें से, एक्ज़ीक्यूशन की पाबंदियों से मैच न करने वाले प्लैटफ़ॉर्म हटा दिए जाते हैं.उपलब्ध टूलचेन की सूची को फ़िल्टर किया जाता है. इसमें से,
target_settingsतय करने वाले ऐसे टूलचेन हटा दिए जाते हैं जो मौजूदा कॉन्फ़िगरेशन से मैच नहीं करते.हर उपलब्ध एक्ज़ीक्यूशन प्लैटफ़ॉर्म के लिए, हर टूलचेन टाइप को पहले उपलब्ध टूलचेन से जोड़ा जाता है. ऐसा तब किया जाता है, जब वह टूलचेन, इस एक्ज़ीक्यूशन प्लैटफ़ॉर्म और टारगेट प्लैटफ़ॉर्म के साथ काम करता हो.
ऐसे सभी एक्ज़ीक्यूशन प्लैटफ़ॉर्म को हटा दिया जाता है जिनके लिए, टूलचेन टाइप में से किसी एक के लिए, काम करने वाला ज़रूरी टूलचेन नहीं मिला. बाकी बचे प्लैटफ़ॉर्म में से, पहला प्लैटफ़ॉर्म, मौजूदा टारगेट का एक्ज़ीक्यूशन प्लैटफ़ॉर्म बन जाता है. साथ ही, उससे जुड़े टूलचेन (अगर कोई हो) टारगेट की डिपेंडेंसी बन जाते हैं.
चुने गए एक्ज़ीक्यूशन प्लैटफ़ॉर्म का इस्तेमाल, टारगेट से जनरेट होने वाली सभी कार्रवाइयों को चलाने के लिए किया जाता है.
ऐसे मामलों में जहां एक ही टारगेट को एक ही बिल्ड में, कई कॉन्फ़िगरेशन (जैसे, अलग-अलग सीपीयू के लिए) में बिल्ड किया जा सकता है, वहां टारगेट के हर वर्शन पर, रिज़ॉल्यूशन की प्रोसेस अलग-अलग लागू की जाती है.
अगर नियम, एक्ज़ीक्यूशन ग्रुप का इस्तेमाल करता है, तो हर एक्ज़ीक्यूशन ग्रुप, टूलचेन को हल करने की प्रोसेस अलग से करता है. साथ ही, हर ग्रुप का अपना एक्ज़ीक्यूशन प्लैटफ़ॉर्म और टूलचेन होता है.
टूलचेन को डीबग करना
अगर किसी मौजूदा नियम में टूलचेन की सहायता जोड़ी जा रही है, तो --toolchain_resolution_debug=regex फ़्लैग का इस्तेमाल करें. टूलचेन को हल करने की प्रोसेस के दौरान, यह फ़्लैग, regex वैरिएबल से मैच करने वाले टूलचेन टाइप या टारगेट के नामों के लिए ज़्यादा जानकारी वाला आउटपुट देता है. सभी जानकारी का आउटपुट पाने के लिए, .* का इस्तेमाल किया जा सकता है. Bazel, रिज़ॉल्यूशन की प्रोसेस के दौरान, उन टूलचेन के नाम आउटपुट करेगा जिनकी वह जांच करता है और जिन्हें छोड़ देता है.
अगर आपको यह देखना है कि cquery की कौनसी डिपेंडेंसी, टूलचेन
को हल करने की प्रोसेस से मिली हैं, तो cquery's --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