एक नियम ऐसी कार्रवाइयों की सीरीज़ के बारे में बताता है जिन पर बेज़ल परफ़ॉर्म करते हैं आउटपुट का एक सेट बनाने के लिए इनपुट, जिनका संदर्भ नियम के मुताबिक लौटाए गए providers लागू करने का फ़ंक्शन. उदाहरण के लिए, C++ बाइनरी नियम यह कर सकता है:
.cpp
सोर्स फ़ाइलों (इनपुट) का एक सेट लें.- सोर्स फ़ाइलों (कार्रवाई) पर
g++
चलाएं. - रनटाइम के दौरान उपलब्ध कराने के लिए,
DefaultInfo
प्रोवाइडर को, रन किए जा सकने वाले आउटपुट और अन्य फ़ाइलों के साथ दिखाएं. - इस एपीआई से, C++ की खास जानकारी इकट्ठा करके,
CcInfo
प्रोवाइडर को वापस भेजें टारगेट और उसकी डिपेंडेंसी.
बेज़ल के हिसाब से, g++
और स्टैंडर्ड C++ लाइब्रेरी भी इनपुट हैं
इस नियम का पालन करें. नियम लिखने वाले के तौर पर, आपको नियम में उपयोगकर्ता से मिले इनपुट के साथ-साथ, कार्रवाइयों को लागू करने के लिए ज़रूरी सभी टूल और लाइब्रेरी पर भी ध्यान देना चाहिए.
कोई नियम बनाने या उसमें बदलाव करने से पहले, पक्का करें कि आपको Bazel के बिल्ड फ़ेज़ के बारे में पता हो. बिल्ड के तीन चरणों (लोडिंग, विश्लेषण, और लागू करना) को समझना ज़रूरी है. इसके लिए भी उपयोगी है मैक्रो और नियमों के बीच के अंतर को समझने के लिए मैक्रो. शुरू करने के लिए, पहले नियमों का ट्यूटोरियल देखें. इसके बाद, इस पेज को रेफ़रंस के तौर पर इस्तेमाल करें.
कुछ नियम, Bazel में पहले से मौजूद होते हैं. ये निजी नियम, जैसे
cc_library
और java_binary
, कुछ भाषाओं के लिए कुछ मुख्य सहायता उपलब्ध कराते हैं.
अपने नियम तय करके, भाषाओं और टूल के लिए मिलती-जुलती सहायता जोड़ी जा सकती है
का इस्तेमाल करें.
Basel ने नियमों को लिखने के लिए, एक्सटेंशन को अलग-अलग
Starlark भाषा. ये नियम .bzl
फ़ाइलों में लिखे गए हैं, जो
इन्हें सीधे BUILD
फ़ाइलों से लोड किया जा सकता है.
अपने नियम तय करते समय, यह तय किया जा सकता है कि यह किन एट्रिब्यूट के साथ काम करता है और कैसे आउटपुट जनरेट करता है.
नियम का implementation
फ़ंक्शन,
विश्लेषण का चरण. यह कोई भी फ़ंक्शन नहीं चलता है
बाहरी आदेश शामिल होते हैं. इसके बजाय, यह उन कार्रवाइयों को रजिस्टर करता है जिनका इस्तेमाल, नियम के आउटपुट बनाने के लिए, बाद में, लागू करने के चरण के दौरान किया जाएगा. हालांकि, ऐसा तब ही किया जाएगा, जब ज़रूरत होगी.
नियम बनाना
.bzl
फ़ाइल में, नया नियम तय करने के लिए rule फ़ंक्शन का इस्तेमाल करें और नतीजे को ग्लोबल वैरिएबल में सेव करें. rule
को किया जाने वाला कॉल
एट्रिब्यूट और
लागू करने का फ़ंक्शन:
example_library = rule(
implementation = _example_library_impl,
attrs = {
"deps": attr.label_list(),
...
},
)
इससे example_library
नाम के नियम के टाइप के बारे में पता चलता है.
rule
को कॉल करने पर यह भी बताना ज़रूरी है कि नियम, executable=True
के साथ एक्सीक्यूटेबल आउटपुट बनाता है या खास तौर पर test=True
के साथ टेस्ट एक्सीक्यूटेबल बनाता है. अगर ऐसा है, तो नियम एक टेस्ट नियम है और नियम का नाम _test
पर खत्म होना चाहिए.
टारगेट इंस्टैंशिएशन
नियमों को BUILD
फ़ाइलों में लोड किया जा सकता है और उन्हें कॉल किया जा सकता है:
load('//some/pkg:rules.bzl', 'example_library')
example_library(
name = "example_target",
deps = [":another_target"],
...
)
बिल्ड नियम के लिए की गई हर कॉल कोई वैल्यू नहीं दिखाती है, लेकिन तय करने का खराब असर होता है एक लक्ष्य. इसे नियम को इंस्टैंशिएट करना कहा जाता है. इससे, नए टारगेट का नाम और टारगेट के एट्रिब्यूट की वैल्यू पता चलती है.
नियमों को Starlark फ़ंक्शन से भी कॉल किया जा सकता है और .bzl
फ़ाइलों में लोड किया जा सकता है.
Starlark फ़ंक्शन, जो नियमों को कॉल करते हैं उन्हें Starlark मैक्रो कहा जाता है.
Starlark मैक्रो को आखिर में BUILD
फ़ाइलों से कॉल किया जाना चाहिए. साथ ही, इन्हें सिर्फ़ लोड करने के चरण के दौरान कॉल किया जा सकता है. ऐसा तब होता है, जब टारगेट को इंस्टैंशिएट करने के लिए BUILD
फ़ाइलों का आकलन किया जाता है.
विशेषताएं
एट्रिब्यूट, नियम से जुड़ा आर्ग्युमेंट होता है. एट्रिब्यूट, किसी टारगेट के लागू होने के लिए खास वैल्यू दे सकते हैं. इसके अलावा, वे अन्य टारगेट का रेफ़रंस देकर, डिपेंडेंसी का ग्राफ़ बना सकते हैं.
नियम से जुड़ी खास विशेषताएं, जैसे कि srcs
या deps
, मैप पास करके तय की जाती हैं
एट्रिब्यूट के नाम से लेकर स्कीमा तक (attr
का इस्तेमाल करके बनाया जाता है
मॉड्यूल) को rule
के attrs
पैरामीटर से बदल दिया जाता है.
सामान्य एट्रिब्यूट, जैसे
name
और visibility
को सभी नियमों में अस्पष्ट रूप से जोड़ा गया है. अतिरिक्त एट्रिब्यूट, खास तौर पर कार्यान्वित किए जा सकने वाले और टेस्ट किए जा सकने वाले नियमों में अपने-आप जुड़ जाते हैं. ऐसे एट्रिब्यूट जो
किसी नियम में निहित रूप से जोड़े नहीं जा सकते उन्हें पास की गई शब्दकोश में शामिल नहीं किया जा सकता
attrs
.
डिपेंडेंसी एट्रिब्यूट
सोर्स कोड को प्रोसेस करने वाले नियम, आम तौर पर इन एट्रिब्यूट को तय करते हैं कई टाइप की डिपेंडेंसी:
srcs
, टारगेट की कार्रवाइयों से प्रोसेस की गई सोर्स फ़ाइलों के बारे में बताता है. अक्सर, एट्रिब्यूट स्कीमा से यह पता चलता है कि नियम, किस तरह की सोर्स फ़ाइल को प्रोसेस करता है और उसके लिए कौनसे फ़ाइल एक्सटेंशन इस्तेमाल किए जा सकते हैं. हेडर फ़ाइलों वाली भाषाओं के लिए नियम, आम तौर पर टारगेट और उसके उपभोक्ताओं से प्रोसेस किए गए हेडर के लिए, अलगhdrs
एट्रिब्यूट तय करते हैं.deps
किसी टारगेट के लिए कोड की डिपेंडेंसी तय करता है. एट्रिब्यूट स्कीमा को तय करें कि उन डिपेंडेंसी को कौनसे provider देने चाहिए. (इसके लिए उदाहरण के लिए,cc_library
सेCcInfo
मिलती है.)data
से पता चलता है कि रनटाइम के दौरान, किसी भी ऐसे प्रोग्राम के लिए कौनसी फ़ाइलें उपलब्ध कराई जाएंगी जो किसी टारगेट पर निर्भर करता है. इससे, अपनी पसंद की फ़ाइलों को तय करने की अनुमति मिलनी चाहिए.
example_library = rule(
implementation = _example_library_impl,
attrs = {
"srcs": attr.label_list(allow_files = [".example"]),
"hdrs": attr.label_list(allow_files = [".header"]),
"deps": attr.label_list(providers = [ExampleInfo]),
"data": attr.label_list(allow_files = True),
...
},
)
ये डिपेंडेंसी एट्रिब्यूट के उदाहरण हैं. कोई भी एट्रिब्यूट, किसी इनपुट लेबल (attr.label_list
,
attr.label
या
attr.label_keyed_string_dict
से तय किए गए) के बारे में बताता है. यह एट्रिब्यूट, किसी टारगेट और उन टारगेट के बीच किसी खास तरह की डिपेंडेंसी के बारे में बताता है जिनके लेबल (या उनसे जुड़े Label
ऑब्जेक्ट) को टारगेट तय करते समय, उस एट्रिब्यूट में शामिल किया गया है. इन लेबल के लिए डेटा स्टोर करने की जगह और पाथ का समाधान कर दिया गया है
तय टारगेट के मुताबिक है.
example_library(
name = "my_target",
deps = [":other_target"],
)
example_library(
name = "other_target",
...
)
इस उदाहरण में, other_target
, my_target
पर निर्भर है. इसलिए, यह इस पर निर्भर करता है कि
other_target
का विश्लेषण पहले किया जाता है. यह एक गड़बड़ी है, अगर
टारगेट का डिपेंडेंसी ग्राफ़.
निजी एट्रिब्यूट और इंप्लिसिट डिपेंडेंसी
डिफ़ॉल्ट वैल्यू वाला डिपेंडेंसी एट्रिब्यूट, अहम जानकारी बनाता है. यह वैल्यू, टारगेट ग्राफ़ का हिस्सा है, जिसे उपयोगकर्ता BUILD
फ़ाइल में नहीं बताता. इसलिए, यह वैल्यू डिफ़ॉल्ट रूप से लागू होती है. किसी नियम और टूल (बिल्ड टाइम डिपेंडेंसी, जैसे कि कंपाइलर) के बीच के संबंध को हार्ड-कोड करने के लिए, इनपुट डिपेंडेंसी काम की होती हैं. ऐसा इसलिए, क्योंकि ज़्यादातर समय में उपयोगकर्ता को यह बताने में दिलचस्पी नहीं होती कि नियम किस टूल का इस्तेमाल करता है. नियम को लागू करने वाले फ़ंक्शन में, इसे अन्य डिपेंडेंसी की तरह ही माना जाता है.
अगर आपको उपयोगकर्ता को अनुमति दिए बिना कोई इंप्लिसिट डिपेंडेंसी उपलब्ध करानी है
अगर इस वैल्यू को बदलना है, तो एट्रिब्यूट को कोई नाम देकर इसे private बनाया जा सकता है
जो अंडरस्कोर (_
) से शुरू होता है. निजी एट्रिब्यूट का डिफ़ॉल्ट मान होना ज़रूरी है
वैल्यू. आम तौर पर, प्राइवेट एट्रिब्यूट का इस्तेमाल सिर्फ़ उन डिपेंडेंसी के लिए किया जाता है जो अपने-आप जुड़ जाती हैं.
example_library = rule(
implementation = _example_library_impl,
attrs = {
...
"_compiler": attr.label(
default = Label("//tools:example_compiler"),
allow_single_file = True,
executable = True,
cfg = "exec",
),
},
)
इस उदाहरण में, example_library
टाइप के हर टारगेट की, कंपाइलर //tools:example_compiler
पर आश्रित होना ज़रूरी है. इससे, example_library
के लागू करने वाले फ़ंक्शन को ऐसी कार्रवाइयां जनरेट करने की अनुमति मिलती है जो कंपाइलर को ट्रिगर करती हैं. भले ही, उपयोगकर्ता ने इनपुट के तौर पर उसका लेबल पास न किया हो. _compiler
एक निजी एट्रिब्यूट है. इसलिए, इस तरह के नियम के सभी टारगेट में ctx.attr._compiler
हमेशा //tools:example_compiler
पर ले जाएगा. इसके अलावा, एट्रिब्यूट का नाम अंडरस्कोर के बिना compiler
रखा जा सकता है और डिफ़ॉल्ट वैल्यू को बनाए रखा जा सकता है. इससे लोग,
अगर ज़रूरी हो, तो अलग-अलग कंपाइलर, लेकिन उसे कंपाइलर के बारे में जानकारी की ज़रूरत नहीं होती है
लेबल.
आम तौर पर, इनपुट के तौर पर इस्तेमाल होने वाले टूल के लिए, लागू किए गए नियम के साथ मौजूद रिपॉज़िटरी का इस्तेमाल किया जाता है. अगर टूल, एक्सीक्यूशन प्लैटफ़ॉर्म या किसी दूसरी रिपॉज़िटरी से आता है, तो नियम को उस टूल को टूलचेन से हासिल करना चाहिए.
आउटपुट एट्रिब्यूट
आउटपुट एट्रिब्यूट, जैसे कि attr.output
और
attr.output_list
, उस आउटपुट फ़ाइल के बारे में बताते हैं जिसे
टारगेट जनरेट करता है. ये, डिपेंडेंसी एट्रिब्यूट से दो तरीकों से अलग होते हैं:
- वे निर्धारित लक्ष्यों को रेफ़र करने के बजाय आउटपुट फ़ाइल लक्ष्य निर्धारित करते हैं कहीं और.
- आउटपुट फ़ाइल टारगेट, इंस्टैंशिएट किए गए नियम टारगेट पर निर्भर करते हैं, न कि इसके उलट.
आम तौर पर, आउटपुट एट्रिब्यूट का इस्तेमाल सिर्फ़ तब किया जाता है, जब किसी नियम को आउटपुट बनाने की ज़रूरत होती है
जिनमें उपयोगकर्ता के तय किए गए नाम हों. ये नाम, टारगेट नाम पर आधारित नहीं हो सकते. अगर किसी नियम में एक आउटपुट एट्रिब्यूट है, तो आम तौर पर उसका नाम out
या outs
होता है.
आउटपुट एट्रिब्यूट, पहले से तय किए गए आउटपुट बनाने का पसंदीदा तरीका है. खास तौर पर, भरोसा किया जा सकता है या कमांड लाइन पर अनुरोध किया गया.
लागू करने का फ़ंक्शन
हर नियम के लिए एक implementation
फ़ंक्शन होना ज़रूरी है. ये फ़ंक्शन विश्लेषण के फ़ेज़ में सख्ती से लागू किए जाते हैं. साथ ही, ये लोडिंग फ़ेज़ में जनरेट किए गए टारगेट के ग्राफ़ को, कार्रवाइयों के ग्राफ़ में बदल देते हैं. ये कार्रवाइयां, लागू करने के फ़ेज़ के दौरान की जाती हैं. इसलिए,
लागू करने वाले फ़ंक्शन, असल में फ़ाइलों को पढ़ या लिख नहीं सकते.
नियम लागू करने वाले फ़ंक्शन आम तौर पर निजी होते हैं. इनका नाम शुरू में अंडरस्कोर होता है. आम तौर पर, इनका नाम उनके नियम के नाम जैसा ही होता है, लेकिन आखिर में _impl
होता है.
लागू करने वाले फ़ंक्शन में सिर्फ़ एक पैरामीटर होता है: नियम का कॉन्टेक्स्ट, जिसे आम तौर पर ctx
कहा जाता है. इससे सेवा देने वाली कंपनियों की सूची मिलती है.
टारगेट
डिपेंडेंसी को विश्लेषण के समय Target
के तौर पर दिखाया जाता है
ऑब्जेक्ट हैं. इन ऑब्जेक्ट में ऐसे providers शामिल होते हैं जो
लक्ष्य का कार्यान्वयन फ़ंक्शन निष्पादित किया गया.
ctx.attr
में हर फ़ील्ड के नाम से मिलते-जुलते फ़ील्ड हैं
डिपेंडेंसी एट्रिब्यूट, जिसमें Target
ऑब्जेक्ट हैं. ये ऑब्जेक्ट हर डायरेक्ट के बारे में बताते हैं
पर निर्भर है. label_list
एट्रिब्यूट के लिए, यह यहां दी गई सूची में मौजूद है:
Targets
. label
एट्रिब्यूट के लिए, यह एक Target
या None
है.
टारगेट के लागू करने वाले फ़ंक्शन से, प्रोवाइडर ऑब्जेक्ट की सूची मिलती है:
return [ExampleInfo(headers = depset(...))]
उन्हें इंडेक्स नोटेशन ([]
) का इस्तेमाल करके ऐक्सेस किया जा सकता है. इसमें, प्रोवाइडर किस तरह का है
एक कुंजी. ये Starlark में बताए गए पसंद के मुताबिक सेवा देने वाली कंपनियां हो सकती हैं या
स्टारलार्क के तौर पर उपलब्ध नेटिव नियमों के लिए सेवा देने वाली कंपनियां
ग्लोबल वैरिएबल.
उदाहरण के लिए, अगर कोई नियम hdrs
एट्रिब्यूट के ज़रिए हेडर फ़ाइलों को लेता है और
इकट्ठा किए गए डेटा को टारगेट और उसके उपभोक्ताओं की कार्रवाइयों से जोड़कर, उन्हें
इस तरह इकट्ठा करें:
def _example_library_impl(ctx):
...
transitive_headers = [hdr[ExampleInfo].headers for hdr in ctx.attr.hdrs]
लेगसी स्टाइल के लिए, जिसमें struct
को
टारगेट सेट करने का फ़ंक्शन:
return struct(example_info = struct(headers = depset(...)))
सेवा देने वाली कंपनियों की जानकारी, Target
ऑब्जेक्ट के संबंधित फ़ील्ड से ली जा सकती है:
transitive_headers = [hdr.example_info.headers for hdr in ctx.attr.hdrs]
इस स्टाइल का इस्तेमाल करने का सुझाव नहीं दिया जाता. साथ ही, नियमों को इससे माइग्रेट कर दिया जाना चाहिए.
फ़ाइलें
फ़ाइलों को File
ऑब्जेक्ट के तौर पर दिखाया जाता है. विश्लेषण के दौरान, Bazel फ़ाइल I/O का इस्तेमाल नहीं करता. इसलिए, इन ऑब्जेक्ट का इस्तेमाल, फ़ाइल के कॉन्टेंट को सीधे पढ़ने या उसमें बदलाव करने के लिए नहीं किया जा सकता. इसके बजाय, इन्हें ऐक्शन ग्राफ़ के हिस्सों को बनाने के लिए, ऐक्शन उत्सर्जित करने वाले फ़ंक्शन (ctx.actions
देखें) को पास किया जाता है.
File
, सोर्स फ़ाइल या जनरेट की गई फ़ाइल हो सकती है. जनरेट की गई हर फ़ाइल
एक ही कार्रवाई का आउटपुट होना चाहिए. स्रोत फ़ाइलें इसका आउटपुट नहीं हो सकतीं
कोई कार्रवाई नहीं कर सकते.
हर डिपेंडेंसी एट्रिब्यूट के लिए,
ctx.files
में सभी के डिफ़ॉल्ट आउटपुट की सूची शामिल है
उस एट्रिब्यूट के ज़रिए डिपेंडेंसी:
def _example_library_impl(ctx):
...
headers = depset(ctx.files.hdrs, transitive=transitive_headers)
srcs = ctx.files.srcs
...
ctx.file
में, डिपेंडेंसी एट्रिब्यूट के लिए एक File
या None
होता है. इन एट्रिब्यूट के स्पेसिफ़िकेशन, allow_single_file=True
को सेट करते हैं.
ctx.executable
, ctx.file
की तरह ही काम करता है. हालांकि, इसमें सिर्फ़ उन डिपेंडेंसी एट्रिब्यूट के लिए फ़ील्ड होते हैं जिनके स्पेसिफ़िकेशन में executable=True
सेट होता है.
आउटपुट का एलान करना
विश्लेषण के चरण के दौरान, नियम लागू करने वाला फ़ंक्शन आउटपुट बना सकता है.
लोडिंग के दौरान सभी लेबल की जानकारी होनी चाहिए. इसलिए, इन अतिरिक्त आउटपुट में कोई लेबल नहीं होता. आउटपुट के लिए File
ऑब्जेक्ट, इनका इस्तेमाल करके बनाए जा सकते हैं
ctx.actions.declare_file
और
ctx.actions.declare_directory
. अक्सर,
आउटपुट के नाम टारगेट के नाम पर आधारित होते हैं,
ctx.label.name
:
def _example_library_impl(ctx):
...
output_file = ctx.actions.declare_file(ctx.label.name + ".output")
...
पहले से तय किए गए आउटपुट के लिए, जैसे कि
आउटपुट एट्रिब्यूट, इसके बजाय File
ऑब्जेक्ट वापस पाए जा सकते हैं
ctx.outputs
के संबंधित फ़ील्ड से.
कार्रवाइयां
किसी कार्रवाई से यह पता चलता है कि इनपुट के किसी सेट से आउटपुट का सेट कैसे जनरेट किया जाए. उदाहरण के लिए, "hello.c पर gcc चलाएं और hello.o पाएं". कोई कार्रवाई बनाने पर, Bazel कमांड को तुरंत नहीं चलाता. यह इसे डिपेंडेंसी के ग्राफ़ में रजिस्टर करता है, क्योंकि कोई कार्रवाई किसी दूसरी कार्रवाई के आउटपुट पर निर्भर हो सकती है. उदाहरण के लिए, C में, कंपाइलर के बाद लिंकर को कॉल किया जाना चाहिए.
कार्रवाइयां बनाने वाले सामान्य फ़ंक्शन, ctx.actions
में तय किए गए हैं:
ctx.actions.run
, ताकि एक्ज़ीक्यूट किया जा सके.ctx.actions.run_shell
, शेल चलाने के लिए आदेश.ctx.actions.write
, किसी फ़ाइल में स्ट्रिंग लिखने के लिए.ctx.actions.expand_template
, से टेंप्लेट से फ़ाइल जनरेट करें.
ctx.actions.args
का इस्तेमाल, कार्रवाइयों के लिए आर्ग्युमेंट को बेहतर तरीके से इकट्ठा करने के लिए किया जा सकता है. इससे बराबर होने से बचा जा सकता है
प्रोग्राम के चलने का समय:
def _example_library_impl(ctx):
...
transitive_headers = [dep[ExampleInfo].headers for dep in ctx.attr.deps]
headers = depset(ctx.files.hdrs, transitive=transitive_headers)
srcs = ctx.files.srcs
inputs = depset(srcs, transitive=[headers])
output_file = ctx.actions.declare_file(ctx.label.name + ".output")
args = ctx.actions.args()
args.add_joined("-h", headers, join_with=",")
args.add_joined("-s", srcs, join_with=",")
args.add("-o", output_file)
ctx.actions.run(
mnemonic = "ExampleCompile",
executable = ctx.executable._compiler,
arguments = [args],
inputs = inputs,
outputs = [output_file],
)
...
कार्रवाइयों के लिए, इनपुट फ़ाइलों की सूची या उन्हें शामिल किया जाता है. इसके बाद, इनकी सूची जनरेट की जाती है (जो खाली नहीं है) आउटपुट फ़ाइलें. विश्लेषण के चरण के दौरान, इनपुट और आउटपुट फ़ाइलों का सेट पता होना चाहिए. यह एट्रिब्यूट की वैल्यू पर निर्भर हो सकता है. इसमें डिपेंडेंसी के लिए उपलब्ध कराए गए प्रोवाइडर भी शामिल हैं. हालांकि, यह एट्रिब्यूट, लागू करने के नतीजे पर निर्भर नहीं हो सकता. उदाहरण के लिए, अगर आपकी कार्रवाई अनज़िप करने वाला कमांड चलाती है, तो यह बताना ज़रूरी है कि किन फ़ाइलों को बढ़ा-चढ़ाकर दिखाया जा सकता है (अनज़िप करने से पहले). ऐसी कार्रवाइयां जो इंटरनल तौर पर अलग-अलग संख्या में फ़ाइलें बनाती हैं उन्हें एक ही फ़ाइल (जैसे, zip, tar या अन्य आर्काइव फ़ॉर्मैट) में लपेटा जा सकता है.
कार्रवाइयों में उनके सभी इनपुट की सूची होनी चाहिए. ऐसे इनपुट की अनुमति है जिनका इस्तेमाल नहीं किया जाता, लेकिन ये काम के नहीं होते.
कार्रवाइयों को अपने सभी आउटपुट बनाने होंगे. वे अन्य फ़ाइलें लिख सकते हैं, लेकिन जो भी आउटपुट में नहीं होगा वह उपभोक्ताओं के लिए उपलब्ध नहीं होगा. एलान किए गए सभी आउटपुट किसी क्रिया के ज़रिए लिखा जाना चाहिए.
ऐक्शन को प्योर फ़ंक्शन के साथ तुलना की जा सकती है: इनमें सिर्फ़ दिए गए इनपुट का इस्तेमाल किया जाना चाहिए. साथ ही, इनमें कंप्यूटर की जानकारी, उपयोगकर्ता नाम, घड़ी, नेटवर्क या I/O डिवाइसों को ऐक्सेस करने से बचना चाहिए. हालांकि, इनपुट पढ़ने और आउटपुट लिखने के लिए ऐसा किया जा सकता है. यह है यह ज़रूरी है, क्योंकि आउटपुट को कैश मेमोरी में सेव करके, फिर से इस्तेमाल किया जाएगा.
डिपेंडेंसी को Bazel हल करता है. यह तय करता है कि कौनसी कार्रवाइयां की जाएंगी. अगर डिपेंडेंसी ग्राफ़ में कोई साइकल है, तो यह गड़बड़ी है. बनाई जा रही है कोई कार्रवाई इस बात की गारंटी नहीं देती कि उसे चलाया जाएगा. यह इस बात पर निर्भर करता है कि बिल्ड के लिए आउटपुट ज़रूरी हैं.
सेवा देने वाली कंपनियां
प्रोवाइडर, जानकारी के ऐसे हिस्से होते हैं जिन्हें कोई नियम, उस पर निर्भर रहने वाले अन्य नियमों के लिए दिखाता है. इस डेटा में आउटपुट फ़ाइलें, लाइब्रेरी, और पास किए जाने वाले पैरामीटर शामिल हो सकते हैं या कुछ भी जो टारगेट के उपभोक्ताओं को पता होना चाहिए. के बारे में.
चूंकि नियम का कार्यान्वयन फ़ंक्शन केवल
इंस्टैंशिएट किए गए टारगेट की तुरंत डिपेंडेंसी के लिए, नियमों को किसी
टारगेट की डिपेंडेंसी से मिलने वाली जानकारी जिसे टारगेट
उपभोक्ताओं को भेजा जा सकता है. आम तौर पर, इस जानकारी को depset
में इकट्ठा किया जाता है.
टारगेट के प्रोवाइडर, लागू करने वाले फ़ंक्शन से मिले Provider
ऑब्जेक्ट की सूची से तय किए जाते हैं.
लागू करने के पुराने फ़ंक्शन, लेगसी स्टाइल में भी लिखे जा सकते हैं. इसमें लागू करने वाला फ़ंक्शन, प्रोवाइडर ऑब्जेक्ट की सूची के बजाय struct
दिखाता है. यह शैली पूरी तरह से प्रोत्साहित नहीं की जाती है और नियमों को
इससे माइग्रेट नहीं हुआ.
डिफ़ॉल्ट आउटपुट
टारगेट के डिफ़ॉल्ट आउटपुट वे आउटपुट होते हैं जिनका अनुरोध डिफ़ॉल्ट रूप से तब किया जाता है, जब कमांड लाइन पर टारगेट के लिए बिल्ड का अनुरोध किया जाता है. उदाहरण के लिए,
java_library
टारगेट //pkg:foo
में डिफ़ॉल्ट आउटपुट के तौर पर foo.jar
है. इसलिए,
कमांड bazel build //pkg:foo
की मदद से बनाया जाएगा.
डिफ़ॉल्ट आउटपुट, DefaultInfo
के files
पैरामीटर से तय किए जाते हैं:
def _example_library_impl(ctx):
...
return [
DefaultInfo(files = depset([output_file]), ...),
...
]
अगर नियम लागू करने या files
लागू करने पर, DefaultInfo
नहीं मिलता है
कोई पैरामीटर नहीं चुना गया है, DefaultInfo.files
डिफ़ॉल्ट रूप से सभी पर सेट है
पहले से तय किए गए आउटपुट (आम तौर पर, जो आउटपुट" से बनाए जाते हैं
एट्रिब्यूट).
कार्रवाइयां करने वाले नियमों में डिफ़ॉल्ट आउटपुट देने चाहिए, भले ही वे आउटपुट सीधे तौर पर इस्तेमाल नहीं किया जाना चाहिए. वे कार्रवाइयां जो अनुरोध किए गए आउटपुट कम कर दिए जाते हैं. अगर किसी आउटपुट का इस्तेमाल सिर्फ़ टारगेट के उपभोक्ता करते हैं, तो टारगेट को अलग से बनाने पर वे कार्रवाइयां नहीं की जाएंगी. यह डीबग करना और मुश्किल बना देता है, क्योंकि सिर्फ़ असफल टारगेट को फिर से बनाने से और उस गड़बड़ी को फिर से देख सकें.
Runfiles
रनफ़ाइलें, फ़ाइलों का एक सेट होता है. इसका इस्तेमाल टारगेट, रनटाइम के दौरान करता है, न कि बिल्डटाइम के दौरान. लागू करने के चरण के दौरान, Basel ने एक डायरेक्ट्री ट्री, जिसमें रनफ़ाइल पर ले जाने वाले सिमलिंक होते हैं. इसमें स्टेज को एनवायरमेंट के तौर पर इस्तेमाल कर सकते हैं, ताकि यह रनटाइम के दौरान रनफ़ाइल को ऐक्सेस कर सके.
नियम बनाने के दौरान रनफ़ाइल मैन्युअल रूप से जोड़ी जा सकती हैं.
runfiles
ऑब्जेक्ट, नियम के संदर्भ ctx.runfiles
पर runfiles
तरीके से बनाए जा सकते हैं और DefaultInfo
पर runfiles
पैरामीटर को पास किए जा सकते हैं. कार्रवाई करने वाले नियमों का, रनफ़ाइलों में अपने-आप जुड़ने वाला आउटपुट.
कुछ नियम, एट्रिब्यूट के बारे में बताते हैं. इन्हें आम तौर पर
data
, जिसके आउटपुट इसमें जोड़े जाते हैं
लक्ष्य का runfiles. रनफ़ाइल को data
से भी मर्ज किया जाना चाहिए. साथ ही,
ऐसे किसी भी एट्रिब्यूट से लिया जाता है जो मॉडल को एक्ज़ीक्यूट करने के लिए कोड दे सकते हैं.
srcs
(जिसमें data
से जुड़े filegroup
टारगेट हो सकते हैं) और
deps
.
def _example_library_impl(ctx):
...
runfiles = ctx.runfiles(files = ctx.files.data)
transitive_runfiles = []
for runfiles_attr in (
ctx.attr.srcs,
ctx.attr.hdrs,
ctx.attr.deps,
ctx.attr.data,
):
for target in runfiles_attr:
transitive_runfiles.append(target[DefaultInfo].default_runfiles)
runfiles = runfiles.merge_all(transitive_runfiles)
return [
DefaultInfo(..., runfiles = runfiles),
...
]
पसंद के मुताबिक सेवा देने वाली कंपनियां
provider
का इस्तेमाल करके, सेवा देने वाली कंपनियों की जानकारी दी जा सकती है
फ़ंक्शन का इस्तेमाल करें:
ExampleInfo = provider(
"Info needed to compile/link Example code.",
fields={
"headers": "depset of header Files from transitive dependencies.",
"files_to_link": "depset of Files from compilation.",
})
इसके बाद, नियम लागू करने वाले फ़ंक्शन, प्रोवाइडर के इंस्टेंस बना सकते हैं और उन्हें दिखा सकते हैं:
def _example_library_impl(ctx):
...
return [
...
ExampleInfo(
headers = headers,
files_to_link = depset(
[output_file],
transitive = [
dep[ExampleInfo].files_to_link for dep in ctx.attr.deps
],
),
)
]
सेवा देने वाली कंपनियों को पसंद के मुताबिक शुरू करना
सेवा देने वाली कंपनी के इंस्टैंशिएट को कस्टम प्री-प्रोसेसिंग और पुष्टि करने वाला लॉजिक. इसका इस्तेमाल यह पक्का करने के लिए किया जा सकता है कि सभी प्रोवाइडर इंस्टेंस, कुछ इनवैरिएंट का पालन करते हों. इसके अलावा, इसका इस्तेमाल उपयोगकर्ताओं को इंस्टेंस पाने के लिए बेहतर एपीआई देने के लिए भी किया जा सकता है.
ऐसा करने के लिए init
कॉलबैक को
provider
फ़ंक्शन. अगर यह कॉलबैक दिया जाता है, तो provider()
का रिटर्न टाइप, दो वैल्यू के ट्यूपल में बदल जाता है: प्रोवाइडर सिंबल, जो init
का इस्तेमाल न करने पर सामान्य रिटर्न वैल्यू होता है और "रॉ कंस्ट्रक्टर".
इस मामले में, जब प्रोवाइडर सिंबल को कॉल किया जाता है, तो वह सीधे तौर पर नया इंस्टेंस दिखाने के बजाय, init
कॉलबैक के साथ आर्ग्युमेंट को फ़ॉरवर्ड करेगा. कॉन्टेंट बनाने
कॉलबैक की रिटर्न वैल्यू, वैल्यू के लिए डिक्शनरी वाले फ़ील्ड के नाम (स्ट्रिंग) होनी चाहिए;
इसका इस्तेमाल नए इंस्टेंस के फ़ील्ड शुरू करने के लिए किया जाता है. ध्यान दें कि कॉलबैक में कोई भी हस्ताक्षर हो सकता है. अगर आर्ग्युमेंट, हस्ताक्षर से मेल नहीं खाते हैं, तो गड़बड़ी की रिपोर्ट तब की जाती है, जब कॉलबैक को सीधे तौर पर लागू किया गया हो.
इसके उलट, रॉ कंस्ट्रक्टर, init
कॉलबैक को बायपास करेगा.
यहां दिए गए उदाहरण में, init
का इस्तेमाल करके, अपने आर्ग्युमेंट को पहले से प्रोसेस किया गया है और उनकी पुष्टि की गई है:
# //pkg:exampleinfo.bzl
_core_headers = [...] # private constant representing standard library files
# It's possible to define an init accepting positional arguments, but
# keyword-only arguments are preferred.
def _exampleinfo_init(*, files_to_link, headers = None, allow_empty_files_to_link = False):
if not files_to_link and not allow_empty_files_to_link:
fail("files_to_link may not be empty")
all_headers = depset(_core_headers, transitive = headers)
return {'files_to_link': files_to_link, 'headers': all_headers}
ExampleInfo, _new_exampleinfo = provider(
...
init = _exampleinfo_init)
export ExampleInfo
इसके बाद, नियम लागू होने पर, सेवा देने वाली कंपनी को इस तरह इंस्टैंशिएट किया जा सकता है:
ExampleInfo(
files_to_link=my_files_to_link, # may not be empty
headers = my_headers, # will automatically include the core headers
)
रॉ कंस्ट्रक्टर का इस्तेमाल, ऐसे अन्य पब्लिक फ़ैक्ट्री फ़ंक्शन तय करने के लिए किया जा सकता है जो init
लॉजिक से नहीं गुज़रते. उदाहरण के लिए, exampleinfo.bzl में हम ये तय कर सकते हैं:
def make_barebones_exampleinfo(headers):
"""Returns an ExampleInfo with no files_to_link and only the specified headers."""
return _new_exampleinfo(files_to_link = depset(), headers = all_headers)
आम तौर पर, रॉ कंस्ट्रक्टर ऐसे वैरिएबल से जुड़ा होता है जिसका नाम किसी वैरिएबल से शुरू होता है
(_new_exampleinfo
ऊपर दिया गया है), ताकि उपयोगकर्ता कोड इसे लोड न कर सके और
प्रोवाइडर के आर्बिट्रेरी इंस्टेंस जनरेट करना.
init
का एक और इस्तेमाल यह है कि उपयोगकर्ता को प्रोवाइडर के चिह्न को कॉल करने से रोका जा सके. इसके बजाय, उसे फ़ैक्ट्री फ़ंक्शन का इस्तेमाल करने के लिए मजबूर किया जा सके:
def _exampleinfo_init_banned(*args, **kwargs):
fail("Do not call ExampleInfo(). Use make_exampleinfo() instead.")
ExampleInfo, _new_exampleinfo = provider(
...
init = _exampleinfo_init_banned)
def make_exampleinfo(...):
...
return _new_exampleinfo(...)
लागू किए जा सकने वाले नियम और जांच के नियम
लागू किए जा सकने वाले नियम, ऐसे टारगेट तय करते हैं जिन्हें bazel run
कमांड से चालू किया जा सकता है.
टेस्ट नियम, एक खास तरह के लागू किए जा सकने वाले नियम होते हैं. इनके टारगेट को bazel test
निर्देश से भी शुरू किया जा सकता है. rule
को कॉल करते समय, executable
या test
आर्ग्युमेंट को True
पर सेट करके, लागू किए जा सकने वाले और जांच के नियम बनाए जाते हैं:
example_binary = rule(
implementation = _example_binary_impl,
executable = True,
...
)
example_test = rule(
implementation = _example_binary_impl,
test = True,
...
)
जांच के नियमों में _test
से खत्म होने वाले नाम होने चाहिए. (टारगेट नामों का भी अक्सर टेस्ट करें
नियम के मुताबिक _test
पर खत्म होता है. हालांकि, ऐसा करना ज़रूरी नहीं है.) नॉन-टेस्ट नियमों को ये काम नहीं करने चाहिए
यह प्रत्यय है.
दोनों तरह के नियमों से एक ऐसी आउटपुट फ़ाइल जनरेट होनी चाहिए जिसे चलाया जा सके. यह फ़ाइल पहले से एलान की गई हो या न हो. इस फ़ाइल को run
या test
निर्देशों से चालू किया जाएगा. बताने के लिए
Basel को किसी नियम के कौनसे आउटपुट को इस एक्ज़ीक्यूटेबल के रूप में इस्तेमाल करना है, उसे
दिए गए DefaultInfo
के लिए executable
आर्ग्युमेंट
कंपनी. उस executable
को नियम के डिफ़ॉल्ट आउटपुट में जोड़ दिया जाता है (इसलिए, ताकि आप
को executable
और files
, दोनों को पास करने की ज़रूरत नहीं होती है). इसका मतलब यह भी है कि
इन्हें runfiles में जोड़ा गया:
def _example_binary_impl(ctx):
executable = ctx.actions.declare_file(ctx.label.name)
...
return [
DefaultInfo(executable = executable, ...),
...
]
इस फ़ाइल को जनरेट करने वाली कार्रवाई के लिए, फ़ाइल पर एक्ज़ीक्यूटेबल बिट सेट करना ज़रूरी है. इसके लिए
ctx.actions.run
या
ctx.actions.run_shell
कार्रवाई, यह की जानी चाहिए
भी शामिल करें. ctx.actions.write
कार्रवाई के लिए, is_executable=True
पास करें.
लेगसी व्यवहार के तौर पर, लागू किए जा सकने वाले नियमों का एक खास ctx.outputs.executable
पहले से तय आउटपुट होता है. अगर DefaultInfo
का इस्तेमाल करके किसी एक फ़ाइल को एक्ज़ीक्यूटेबल के तौर पर नहीं बताया जाता है, तो यह फ़ाइल डिफ़ॉल्ट एक्ज़ीक्यूटेबल के तौर पर काम करती है. इसका इस्तेमाल किसी और फ़ाइल के लिए नहीं किया जाना चाहिए. आउटपुट के लिए इस तरीके का इस्तेमाल नहीं किया जा सकता, क्योंकि विश्लेषण के समय, यह तरीका, रन की जा सकने वाली फ़ाइल के नाम में बदलाव करने की सुविधा नहीं देता.
कार्रवाई करने वाले नियम और जांच करने वाले नियम के उदाहरण देखें.
कार्यान्वित किए जा सकने वाले नियमों और टेस्ट नियमों में, सभी नियमों के लिए जोड़े गए एट्रिब्यूट के अलावा, कुछ और एट्रिब्यूट भी शामिल होते हैं. के डिफ़ॉल्ट सीधे तौर पर जोड़े गए एट्रिब्यूट बदले नहीं जा सकते. हालांकि, इसका इस्तेमाल किया जा सकता है Starlark मैक्रो में एक निजी नियम रैप करें, जो डिफ़ॉल्ट:
def example_test(size="small", **kwargs):
_example_test(size=size, **kwargs)
_example_test = rule(
...
)
Runfiles की जगह
जब किसी एक्ज़ीक्यूटेबल टारगेट को bazel run
(या test
) के साथ चलाया जाता है, तो
रनफ़ाइल डायरेक्ट्री, एक्ज़ीक्यूटेबल के बगल में मौजूद होती है. पाथ इस तरह से जुड़े होते हैं:
# Given launcher_path and runfile_file:
runfiles_root = launcher_path.path + ".runfiles"
workspace_name = ctx.workspace_name
runfile_path = runfile_file.short_path
execution_root_relative_path = "%s/%s/%s" % (
runfiles_root, workspace_name, runfile_path)
रनफ़ाइल डायरेक्ट्री के तहत File
का पाथ इससे जुड़ा है
File.short_path
.
bazel
से सीधे तौर पर चलाया गया बाइनरी, runfiles
डायरेक्ट्री के रूट के बगल में होता है. हालांकि, रनफ़ाइल से नाम की बाइनरी नहीं बना सकतीं
नहीं कर रहे हैं. इस समस्या को कम करने के लिए, हर बाइनरी को एक तरीका देना चाहिए, ताकि वह किसी एनवायरमेंट या कमांड-लाइन आर्ग्युमेंट/फ़्लैग का इस्तेमाल करके, अपने runfiles रूट को पैरामीटर के तौर पर स्वीकार कर सके. इससे बाइनरी को सही कैननिकल रनफ़ाइल रूट पास करने की अनुमति मिलती है
उसे बाइनरी पर ले जाते हैं. अगर यह सेट नहीं है, तो बाइनरी यह अनुमान लगा सकती है कि इसे सबसे पहले कॉल किया गया था और वह आस-पास मौजूद runfiles डायरेक्ट्री खोज सकती है.
उन्नत विषय
आउटपुट फ़ाइलों का अनुरोध किया जा रहा है
एक टारगेट में कई आउटपुट फ़ाइलें हो सकती हैं. जब bazel build
निर्देश यह होता है
चलाएं, तो कमांड को दिए गए टारगेट के कुछ आउटपुट के रूप में
अनुरोध किया जाएगा. Bazel सिर्फ़ उन फ़ाइलों और उन फ़ाइलों को बनाता है जिन पर ये फ़ाइलें सीधे या (ऐक्शन ग्राफ़ के हिसाब से, सिर्फ़ Basel का
उन कार्रवाइयों को एक्ज़ीक्यूट करता है जिन्हें ऐक्सेस किया जा सकता है. ये
फ़ाइलों का अनुरोध किया है.)
डिफ़ॉल्ट आउटपुट के अलावा, कोई भी पहले से तय किया गया आउटपुट
कमांड लाइन पर साफ़ तौर पर अनुरोध किया जा सकता है. नियमों में, आउटपुट एट्रिब्यूट की मदद से, पहले से तय किए गए आउटपुट की जानकारी दी जा सकती है. ऐसी स्थिति में, उपयोगकर्ता
आउटपुट के लिए लेबल को साफ़ तौर पर चुनता है, जब वे नियम को इंस्टैंशिएट करते हैं. आउटपुट एट्रिब्यूट के लिए
File
ऑब्जेक्ट पाने के लिए, ctx.outputs
के उसी एट्रिब्यूट का इस्तेमाल करें. नियम, टारगेट के नाम के आधार पर भी पहले से तय किए गए आउटपुट को चुपचाप तय कर सकते हैं. हालांकि, इस सुविधा का इस्तेमाल नहीं किया जा सकता.
डिफ़ॉल्ट आउटपुट के अलावा, आउटपुट ग्रुप भी होते हैं. ये आउटपुट फ़ाइलों के कलेक्शन होते हैं. इनके लिए एक साथ अनुरोध किया जा सकता है. इनके साथ अनुरोध किया जा सकता है:
--output_groups
. इसके लिए
उदाहरण के लिए, अगर टारगेट //pkg:mytarget
किसी ऐसे नियम टाइप में है जिसमें debug_files
आउटपुट ग्रुप में, ये फ़ाइलें bazel build //pkg:mytarget
--output_groups=debug_files
चलाकर बनाई जा सकती हैं. पहले से एलान न किए गए आउटपुट में लेबल नहीं होते. इसलिए, इनका अनुरोध सिर्फ़ डिफ़ॉल्ट आउटपुट या आउटपुट ग्रुप में दिखने के लिए किया जा सकता है.
आउटपुट ग्रुप की जानकारी, OutputGroupInfo
प्रोवाइडर के साथ दी जा सकती है. ध्यान दें कि कई डिफ़ॉल्ट प्रोवाइडर के उलट, OutputGroupInfo
में अपने हिसाब से नाम वाले पैरामीटर इस्तेमाल किए जा सकते हैं, ताकि उस नाम से आउटपुट ग्रुप तय किए जा सकें:
def _example_library_impl(ctx):
...
debug_file = ctx.actions.declare_file(name + ".pdb")
...
return [
DefaultInfo(files = depset([output_file]), ...),
OutputGroupInfo(
debug_files = depset([debug_file]),
all_files = depset([output_file, debug_file]),
),
...
]
इसके अलावा, सेवा देने वाली ज़्यादातर कंपनियों के उलट, OutputGroupInfo
को
aspec और वह नियम लक्ष्य जिस पर वह पहलू लागू किया जाता है, जैसा
जब तक वे एक ही आउटपुट ग्रुप को परिभाषित न करें. ऐसे में, एक जैसे नाम वाले प्रॉवाइडर को मर्ज कर दिया जाता है.
ध्यान दें कि आम तौर पर, OutputGroupInfo
का इस्तेमाल खास तरह के क्रम के बारे में बताने के लिए नहीं किया जाना चाहिए
टारगेट की गई फ़ाइलों का विश्लेषण करती है. इसके बजाय, नियम के हिसाब से उपलब्ध कराने वाली कंपनियों की जानकारी दें.
कॉन्फ़िगरेशन
मान लें कि आपको किसी अलग आर्किटेक्चर के लिए, C++ बाइनरी बनाना है. कॉन्टेंट बनाने बनाना जटिल हो सकता है और उसमें कई चरण शामिल हो सकते हैं. कुछ इंटरमीडिएट बाइनरी, जैसे कि कंपाइलर और कोड जनरेटर को एक्सीक्यूशन प्लैटफ़ॉर्म पर चलाना पड़ता है. यह प्लैटफ़ॉर्म आपका होस्ट या रिमोट एक्सीक्यूटर हो सकता है. फ़ाइनल आउटपुट जैसी कुछ बाइनरी टारगेट आर्किटेक्चर.
इस वजह से, Babel के पास "कॉन्फ़िगरेशन" का एक सिद्धांत होता है और ट्रांज़िशन शामिल हैं. कॉन्टेंट बनाने शीर्ष लक्ष्य (कमांड लाइन पर अनुरोध किए गए) "target" कॉन्फ़िगरेशन, जबकि ऐसे टूल जो एक्ज़ीक्यूशन प्लैटफ़ॉर्म पर चलने चाहिए एक "exec" में बनाए जाते हैं कॉन्फ़िगरेशन. नियम, कॉन्फ़िगरेशन के आधार पर अलग-अलग कार्रवाइयां जनरेट कर सकते हैं. उदाहरण के लिए, कंपाइलर को पास किए गए सीपीयू आर्किटेक्चर को बदलने के लिए. कुछ मामलों में, अलग-अलग कॉन्फ़िगरेशन. ऐसा होने पर, इसका विश्लेषण किया जाएगा और इसे कई बार बनाया जा सकता है.
डिफ़ॉल्ट रूप से, Bazel किसी टारगेट की डिपेंडेंसी को उसी कॉन्फ़िगरेशन में बनाता है जिसमें टारगेट बना है. दूसरे शब्दों में, ट्रांज़िशन के बिना. जब डिपेंडेंसी जिसकी ज़रूरत टारगेट बनाने में होती है, संबंधित एट्रिब्यूट को exec कॉन्फ़िगरेशन में ट्रांज़िशन तय करें. इससे, टूल और उसकी सभी डिपेंडेंसी, लागू करने वाले प्लैटफ़ॉर्म के लिए बन जाती हैं.
हर डिपेंडेंसी एट्रिब्यूट के लिए, cfg
का इस्तेमाल करके यह तय किया जा सकता है कि डिपेंडेंसी है या नहीं
को उसी कॉन्फ़िगरेशन में बनाना चाहिए या किसी exec कॉन्फ़िगरेशन में ट्रांज़िशन करना चाहिए.
अगर किसी डिपेंडेंसी एट्रिब्यूट में फ़्लैग executable=True
है, तो cfg
को साफ़ तौर पर सेट किया जाना चाहिए. ऐसा इसलिए किया जाता है, ताकि गलती से गलत कॉन्फ़िगरेशन के लिए टूल न बनाया जाए.
उदाहरण देखें
सामान्य तौर पर, सोर्स, डिपेंडेंट लाइब्रेरी, और एक्ज़ीक्यूटेबल की ज़रूरत होती है रनटाइम इसी कॉन्फ़िगरेशन का इस्तेमाल कर सकता है.
ऐसे टूल जिन्हें बिल्ड के हिस्से के तौर पर चलाया जाता है, जैसे कि कंपाइलर या कोड जनरेटर, इन्हें एक्ज़ीक्यूट कॉन्फ़िगरेशन के लिए बनाया जाना चाहिए. इस मामले में, एट्रिब्यूट में cfg="exec"
की वैल्यू सबमिट करें.
नहीं तो, रनटाइम पर इस्तेमाल किए जाने वाले एक्ज़ीक्यूटेबल (जैसे कि टेस्ट के हिस्से) के लिए
को टारगेट कॉन्फ़िगरेशन के लिए बनाया जाना चाहिए. इस मामले में, एट्रिब्यूट में cfg="target"
की वैल्यू सबमिट करें.
cfg="target"
असल में कुछ नहीं करता: यह सिर्फ़ एक सुविधा है, ताकि नियम बनाने वाले अपने मकसद के बारे में साफ़ तौर पर बता सकें. जब executable=False
,
इसका मतलब है कि cfg
का इस्तेमाल करना ज़रूरी नहीं है. इसे सिर्फ़ तब सेट करें, जब यह पढ़ने में आसान हो.
cfg=my_transition
का इस्तेमाल करके,
उपयोगकर्ता के तय किए गए ट्रांज़िशन. इसकी मदद से,
नियम लिखने वालों को कॉन्फ़िगरेशन बदलने में बहुत ज़्यादा सुविधा मिलती है,
इसकी कमी
बिल्ड ग्राफ़ को बड़ा और कम समझ में आने लायक बनाना.
ध्यान दें: पहले, Bazel में एक्ज़ीक्यूशन प्लैटफ़ॉर्म का कॉन्सेप्ट नहीं था. इसके बजाय, सभी बिल्ड ऐक्शन को होस्ट मशीन पर चलाया जाता था. Bazel के 6.0 से पहले के वर्शन में, इसे दिखाने के लिए एक अलग "होस्ट" कॉन्फ़िगरेशन बनाया गया था. अगर आपको कोड या पुराने दस्तावेज़ में "होस्ट" का रेफ़रंस दिखता है, तो इसका मतलब यही है. इस अतिरिक्त कॉन्सेप्ट से बचने के लिए, हमारा सुझाव है कि आप Basel 6.0 या उसके बाद के वर्शन का इस्तेमाल करें ओवरहेड.
कॉन्फ़िगरेशन फ़्रैगमेंट
नियम, cpp
, java
, और jvm
जैसे कॉन्फ़िगरेशन फ़्रैगमेंट ऐक्सेस कर सकते हैं. हालांकि, ऐक्सेस से जुड़ी गड़बड़ियों से बचने के लिए, सभी ज़रूरी फ़्रेगमेंट का एलान करना ज़रूरी है:
def _impl(ctx):
# Using ctx.fragments.cpp leads to an error since it was not declared.
x = ctx.fragments.java
...
my_rule = rule(
implementation = _impl,
fragments = ["java"], # Required fragments of the target configuration
host_fragments = ["java"], # Required fragments of the host configuration
...
)
रनफ़ाइल सिमलिंक
आम तौर पर, रनफ़ाइल ट्री में किसी फ़ाइल का रिलेटिव पाथ
सोर्स ट्री या जनरेट किए गए आउटपुट ट्री में उस फ़ाइल का रिलेटिव पाथ. अगर ये
किसी वजह से अलग होने चाहिए, तो आप यह बता सकते हैं root_symlinks
या
symlinks
आर्ग्युमेंट. root_symlinks
, शब्दकोश का मैप पाथ है, जो
फ़ाइलें जिनमें पाथ, रनफ़ाइल डायरेक्ट्री के रूट से जुड़े होते हैं. symlinks
डिक्शनरी एक ही है, लेकिन पाथ में मुख्य वर्कस्पेस का नाम पहले से जुड़ा होता है. यह नाम, मौजूदा टारगेट वाले रिपॉज़िटरी का नाम नहीं होता.
...
runfiles = ctx.runfiles(
root_symlinks = {"some/path/here.foo": ctx.file.some_data_file2}
symlinks = {"some/path/here.bar": ctx.file.some_data_file3}
)
# Creates something like:
# sometarget.runfiles/
# some/
# path/
# here.foo -> some_data_file2
# <workspace_name>/
# some/
# path/
# here.bar -> some_data_file3
अगर symlinks
या root_symlinks
का इस्तेमाल किया गया है, तो दो अलग-अलग जगहों को मैप न करें
रनफ़ाइल ट्री में उसी पाथ पर रखता है. इससे, विरोध की जानकारी देने वाली गड़बड़ी के साथ, बिल्ड पूरा नहीं हो पाएगा. ठीक करने के लिए, आपको अपने
टक्कर हटाने के लिए ctx.runfiles
आर्ग्युमेंट. यह जांच इसके लिए की जाएगी
आपके नियम का इस्तेमाल करने वाले टारगेट और उन पर निर्भर किसी भी तरह के टारगेट
टारगेट के लिए. खास तौर पर, ऐसा करना तब जोखिम भरा होता है, जब आपके टूल का इस्तेमाल अस्थायी तौर पर किया जा सकता हो
किसी अन्य टूल से; सिमलिंक के नाम किसी टूल की रनफ़ाइल में यूनीक होने चाहिए. साथ ही,
उससे जुड़ी सभी डिपेंडेंसी.
कोड कवरेज
coverage
कमांड चलाने पर, बिल्ड को कुछ टारगेट के लिए कवरेज इंस्ट्रूमेंटेशन जोड़ना पड़ सकता है. कॉन्टेंट बनाने
बिल्ड, इंस्ट्रुमेंट की गई सोर्स फ़ाइलों की सूची भी इकट्ठा करता है. इसका सबसेट
जिन टारगेट को फ़्लैग किया जाता है उन्हें
--instrumentation_filter
.
टेस्ट टारगेट को बाहर रखा जाता है, बशर्ते --instrument_test_targets
को तय न किया गया हो.
अगर लागू होने वाले किसी नियम की वजह से बिल्ड टाइम में कवरेज इंस्ट्रुमेंटेशन जुड़ जाता है, तो उसके लिए ज़रूरी है उसका ध्यान रखना चाहिए. ctx.coverage_instrumented पर सही वैल्यू मिलती है कवरेज मोड, अगर किसी टारगेट के सोर्स को इंस्ट्रुमेंट किया जाना चाहिए:
# Are this rule's sources instrumented?
if ctx.coverage_instrumented():
# Do something to turn on coverage for this compile action
कवरेज मोड में हमेशा चालू रहने वाले लॉजिक को ctx.configuration.coverage_enabled पर आधारित किया जा सकता है. भले ही, किसी टारगेट के सोर्स को खास तौर पर इंस्ट्रूमेंट किया गया हो या नहीं.
अगर नियम, कंपाइलेशन से पहले सीधे अपनी डिपेंडेंसी से सोर्स शामिल करता है (जैसे हेडर फ़ाइलें), तो इसे कंपाइल-टाइम इंस्ट्रुमेंटेशन भी चालू करना पड़ सकता है, अगर डिपेंडेंसी' स्रोतों में इंस्ट्रुमेंट इंस्ट्रुमेंट होने चाहिए:
# Are this rule's sources or any of the sources for its direct dependencies
# in deps instrumented?
if (ctx.configuration.coverage_enabled and
(ctx.coverage_instrumented() or
any([ctx.coverage_instrumented(dep) for dep in ctx.attr.deps]))):
# Do something to turn on coverage for this compile action
नियमों में यह जानकारी भी होनी चाहिए कि किन एट्रिब्यूट के लिए काम के हैं
InstrumentedFilesInfo
की सेवा देने वाली कंपनी के साथ कवरेज करता है. इसे
coverage_common.instrumented_files_info
.
instrumented_files_info
के dependency_attributes
पैरामीटर में, रनटाइम डिपेंडेंसी वाले सभी एट्रिब्यूट की सूची होनी चाहिए. इनमें deps
जैसी कोड डिपेंडेंसी और data
जैसी डेटा डिपेंडेंसी शामिल हैं. अगर कवरेज इंस्ट्रूमेंटेशन जोड़ा जा सकता है, तो source_attributes
पैरामीटर में नियम की सोर्स फ़ाइलों के एट्रिब्यूट की सूची होनी चाहिए:
def _example_library_impl(ctx):
...
return [
...
coverage_common.instrumented_files_info(
ctx,
dependency_attributes = ["deps", "data"],
# Omitted if coverage is not supported for this rule:
source_attributes = ["srcs", "hdrs"],
)
...
]
अगर InstrumentedFilesInfo
नहीं दिखाया जाता है, तो dependency_attributes
में हर ऐसे डिपेंडेंसी एट्रिब्यूट के लिए डिफ़ॉल्ट वैल्यू बनाई जाती है जो टूल नहीं है और एट्रिब्यूट स्कीमा में cfg
को "host"
या "exec"
पर सेट नहीं करता. (यह सही तरीका नहीं है, क्योंकि यह srcs
जैसे एट्रिब्यूट को source_attributes
के बजाय dependency_attributes
में डालता है. हालांकि, इससे डिपेंडेंसी चेन में सभी नियमों के लिए, कवरेज कॉन्फ़िगरेशन की ज़रूरत नहीं होती.)
पुष्टि करने से जुड़ी कार्रवाइयां
कभी-कभी आपको बिल्ड के बारे में कुछ की पुष्टि करनी पड़ती है. पुष्टि करने के लिए ज़रूरी जानकारी, सिर्फ़ आर्टफ़ैक्ट (सोर्स फ़ाइलें या जनरेट की गई फ़ाइलें) में उपलब्ध होती है. यह जानकारी आर्टफ़ैक्ट में है, इसलिए नियम, विश्लेषण के समय यह पुष्टि नहीं कर सकते, क्योंकि नियमों को पढ़ा नहीं जा सकता फ़ाइलें. इसके बजाय, कार्रवाइयों को लागू करने के समय इसकी पुष्टि करनी चाहिए. पुष्टि न होने पर, कार्रवाई पूरी नहीं होगी और इसलिए बिल्ड भी पूरा नहीं होगा.
पुष्टि करने के लिए, स्टैटिक विश्लेषण, लिंटिंग, डिपेंडेंसी और कंसिस्टेंसी की जांच, और स्टाइल की जांच जैसी प्रोसेस इस्तेमाल की जा सकती हैं.
पुष्टि करने वाली कार्रवाइयों से, आर्टफ़ैक्ट बनाने के लिए ज़रूरी नहीं होने वाली कार्रवाइयों के हिस्सों को अलग-अलग कार्रवाइयों में ले जाकर, बिल्ड की परफ़ॉर्मेंस को बेहतर बनाने में भी मदद मिल सकती है. उदाहरण के लिए, अगर किसी एक ऐक्शन में कोड को कंपाइल और लिंट करने की सुविधा को, कंपाइल करने की सुविधा और लिंट करने की सुविधा में अलग-अलग किया जा सकता है, तो लिंट करने की सुविधा को पुष्टि करने की सुविधा के तौर पर चलाया जा सकता है. साथ ही, इसे अन्य ऐक्शन के साथ चलाया जा सकता है.
ये "पुष्टि करने वाली कार्रवाइयां" अक्सर ऐसा कोई नतीजा नहीं देतीं जिसका इस्तेमाल, बिल्ड में कहीं और किया जा सके. इसकी वजह यह है कि उन्हें सिर्फ़ अपने इनपुट के बारे में बताना होता है. यह हालांकि, एक समस्या आती है: अगर पुष्टि करने की कार्रवाई से ऐसा कुछ नहीं होता है इसका इस्तेमाल बिल्ड में कहीं और किया जाता है. नियम को कार्रवाई करने के लिए कैसे कहा जाता है? पहले, पुष्टि करने वाली कार्रवाई से खाली फ़ाइल का आउटपुट मिलता था. साथ ही, उस आउटपुट को बिल्ड में किसी अन्य अहम कार्रवाई के इनपुट में जोड़ दिया जाता था:
यह इसलिए काम करता है, क्योंकि कंपाइलेशन के समय बेज़ल पुष्टि करने की कार्रवाई हमेशा चलाएगा कार्रवाई की गई, लेकिन इसकी कुछ बड़ी कमियां हैं:
पुष्टि करने की कार्रवाई, बिल्ड के अहम पाथ में होती है. Bazel को लगता है कि कंपाइल ऐक्शन को चलाने के लिए खाली आउटपुट ज़रूरी है. इसलिए, यह पहले पुष्टि करने की कार्रवाई चलाएगा. भले ही, कंपाइल ऐक्शन इनपुट को अनदेखा कर देगा. यह पैरलिज़्म को कम करता है और बिल्ड को धीमा करता है.
अगर बिल्ड में मौजूद दूसरी कार्रवाइयां कार्रवाई को कंपाइल करें, फिर पुष्टि करने की कार्रवाइयों के खाली आउटपुट जोड़ने होंगे वे कार्रवाइयाँ भी होंगी (उदाहरण के लिए,
java_library
का सोर्स जार आउटपुट). यह है यह भी एक समस्या है कि अगर कंपाइल ऐक्शन के बजाय नई कार्रवाइयाँ चल सकती हैं बाद में जोड़ा जाता है और पुष्टि करने वाला खाली आउटपुट गलती से छूट जाता है.
इन समस्याओं को हल करने के लिए, पुष्टि करने वाले आउटपुट ग्रुप का इस्तेमाल करें.
पुष्टि करने वाला आउटपुट ग्रुप
वैलिडेशन आउटपुट ग्रुप एक आउटपुट ग्रुप है, जिसे पुष्टि करने की कार्रवाइयों के इस्तेमाल नहीं किए गए आउटपुट, ताकि उन्हें आर्टिफ़िशियल तरीके से बनाने की ज़रूरत न हो अन्य कार्रवाइयों के इनपुट में जोड़ी गई.
यह ग्रुप खास है, क्योंकि इसके आउटपुट के लिए हमेशा अनुरोध किया जाता है, भले ही
--output_groups
फ़्लैग की वैल्यू दी गई हो. भले ही, टारगेट वैल्यू कोई भी हो
निर्भर करता है (उदाहरण के लिए, कमांड लाइन पर, डिपेंडेंसी के तौर पर या
टारगेट के इंप्लिसिट आउटपुट). ध्यान दें कि सामान्य कैश मेमोरी और इंक्रीमेंटलिटी अब भी लागू होती है: अगर पुष्टि करने की कार्रवाई के इनपुट में बदलाव नहीं हुआ है और पुष्टि करने की कार्रवाई पहले पूरी हो चुकी है, तो पुष्टि करने की कार्रवाई नहीं की जाएगी.
इस आउटपुट ग्रुप का इस्तेमाल करने के लिए, अब भी पुष्टि करने वाली कार्रवाइयों से कोई फ़ाइल आउटपुट होनी चाहिए. भले ही, वह फ़ाइल खाली हो. इसके लिए कुछ ऐसे टूल को रैप करना पड़ सकता है जो आम तौर पर काम नहीं करते आउटपुट जनरेट करता है, ताकि एक फ़ाइल बनाई जा सके.
टारगेट की पुष्टि करने वाली कार्रवाइयां, इन तीन मामलों में नहीं चलाई जातीं:
- जब टारगेट को टूल के तौर पर इस्तेमाल किया जाता है
- जब टारगेट, इंप्लिसिट डिपेंडेंसी के तौर पर निर्भर होता है (उदाहरण के लिए, एट्रिब्यूट जो "_" से शुरू होता है
- जब टारगेट को होस्ट या exec कॉन्फ़िगरेशन में बनाया गया हो.
यह माना जाता है कि इन टारगेट के पास अपने अलग-अलग बिल्ड और टेस्ट होते हैं, जिनसे पुष्टि करने में हुई किसी भी गड़बड़ी का पता चलता है.
पुष्टि करने के लिए आउटपुट ग्रुप का इस्तेमाल करना
इस टूल की पुष्टि करने वाले आउटपुट ग्रुप को _validation
नाम दिया गया है. इसे किसी भी दूसरे कोड की तरह इस्तेमाल किया जाता है
आउटपुट ग्रुप:
def _rule_with_validation_impl(ctx):
ctx.actions.write(ctx.outputs.main, "main output\n")
ctx.actions.write(ctx.outputs.implicit, "implicit output\n")
validation_output = ctx.actions.declare_file(ctx.attr.name + ".validation")
ctx.actions.run(
outputs = [validation_output],
executable = ctx.executable._validation_tool,
arguments = [validation_output.path])
return [
DefaultInfo(files = depset([ctx.outputs.main])),
OutputGroupInfo(_validation = depset([validation_output])),
]
rule_with_validation = rule(
implementation = _rule_with_validation_impl,
outputs = {
"main": "%{name}.main",
"implicit": "%{name}.implicit",
},
attrs = {
"_validation_tool": attr.label(
default = Label("//validation_actions:validation_tool"),
executable = True,
cfg = "exec"),
}
)
ध्यान दें कि पुष्टि करने वाले आउटपुट फ़ाइल को DefaultInfo
या
इनपुट का इस्तेमाल करें. इस नियम के टाइप के टारगेट के लिए, पुष्टि करने की कार्रवाई
तब भी चलेगा, जब टारगेट लेबल या किसी टारगेट के
इंप्लिसिट आउटपुट, सीधे तौर पर या किसी अन्य तरीके से इन पर निर्भर होते हैं.
आम तौर पर, यह ज़रूरी होता है कि पुष्टि करने से जुड़ी कार्रवाइयों के आउटपुट सिर्फ़ उसे पुष्टि करने वाले आउटपुट ग्रुप में शामिल किया जाता है और उसे दूसरी कार्रवाइयों के इनपुट में नहीं जोड़ा जाता है, जैसे कि इससे, साथ-साथ काम करने की क्षमता हासिल नहीं की जा सकती. हालांकि, ध्यान दें कि फ़िलहाल, Bazel में इस शर्त को लागू करने के लिए कोई खास जांच नहीं की जाती. इसलिए, आपको यह जांच करनी चाहिए कि पुष्टि करने वाली कार्रवाई के आउटपुट, Starlark नियमों के लिए किए गए टेस्ट में किसी भी कार्रवाई के इनपुट में नहीं जोड़े गए हैं. उदाहरण के लिए:
load("@bazel_skylib//lib:unittest.bzl", "analysistest")
def _validation_outputs_test_impl(ctx):
env = analysistest.begin(ctx)
actions = analysistest.target_actions(env)
target = analysistest.target_under_test(env)
validation_outputs = target.output_groups._validation.to_list()
for action in actions:
for validation_output in validation_outputs:
if validation_output in action.inputs.to_list():
analysistest.fail(env,
"%s is a validation action output, but is an input to action %s" % (
validation_output, action))
return analysistest.end(env)
validation_outputs_test = analysistest.make(_validation_outputs_test_impl)
पुष्टि करने की कार्रवाइयों का फ़्लैग
पुष्टि करने वाली कार्रवाइयों को --run_validations
कमांड लाइन के फ़्लैग से कंट्रोल किया जाता है. यह डिफ़ॉल्ट रूप से 'सही' पर सेट होता है.
बंद की गई सुविधाएं
ऐसे आउटपुट जो पहले से तय नहीं किए गए हैं
पहले से तय किए गए आउटपुट को इस्तेमाल करने के दो तरीके हैं, जो अब काम नहीं करते:
rule
काoutputs
पैरामीटर तय करता है जनरेट करने के लिए, आउटपुट एट्रिब्यूट के नाम और स्ट्रिंग टेंप्लेट के बीच की मैपिंग पहले से तय आउटपुट लेबल. पहले से एलान न किए गए आउटपुट का इस्तेमाल करें औरDefaultInfo.files
में आउटपुट को साफ़ तौर पर जोड़ें. पहले से तय किए गए आउटपुट के लेबल के बजाय, आउटपुट का इस्तेमाल करने वाले नियमों के लिए, नियम के टारगेट के लेबल का इस्तेमाल इनपुट के तौर पर करें.लागू किए जा सकने वाले नियमों के लिए,
ctx.outputs.executable
इसका इस्तेमाल करता है पहले से तय किए गए एक्ज़ीक्यूटेबल आउटपुट के लिए, नियम के टारगेट के नाम से मेल खाना चाहिए. आउटपुट के बारे में साफ़ तौर पर जानकारी दें, उदाहरण के लिएctx.actions.declare_file(ctx.label.name)
और पक्का करें कि कमांड एक्ज़ीक्यूटेबल को जनरेट करने पर, उसकी अनुमतियां सेट करके, एक्ज़ीक्यूट करने की अनुमति दी जाती है. एक्ज़ीक्यूटेबल आउटपुट कोDefaultInfo
केexecutable
पैरामीटर में साफ़ तौर पर पास करें.
Runfiles की ऐसी सुविधाएं जिनसे बचना चाहिए
ctx.runfiles
और runfiles
टाइप में सुविधाओं का एक जटिल सेट होता है. इनमें से कई सुविधाएं लेगसी वजहों से रखी जाती हैं.
ये सुझाव, जटिलता को कम करने में मदद करते हैं:
इसके
collect_data
औरcollect_default
मोड का इस्तेमाल करने से बचेंctx.runfiles
. ये मोड, अनजाने में डेटा इकट्ठा करते हैं रनफ़ाइल को कुछ हार्डकोड डिपेंडेंसी किनारों पर भ्रम की स्थिति में डाल दिया जाता है. इसके बजाय,ctx.runfiles
केfiles
याtransitive_files
पैरामीटर का इस्तेमाल करके फ़ाइलें जोड़ें याrunfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)
के साथ डिपेंडेंसी से रनफ़ाइलों को मर्ज करके जोड़ें.DefaultInfo
कन्स्ट्रक्टर केdata_runfiles
औरdefault_runfiles
का इस्तेमाल न करें. इसके बजाय,DefaultInfo(runfiles = ...)
डालें. "डिफ़ॉल्ट" के बीच फ़र्क़ और "data" रनफ़ाइल का रखरखाव किया जाता है शामिल हैं. उदाहरण के लिए, कुछ नियम अपने डिफ़ॉल्ट आउटपुट कोdata_runfiles
में डालते हैं, लेकिनdefault_runfiles
में नहीं.data_runfiles
का इस्तेमाल करने के बजाय, नियमों में डिफ़ॉल्ट आउटपुट और रनफ़ाइलें देने वाले एट्रिब्यूट से मिलेdefault_runfiles
को दोनों शामिल करना चाहिए. आम तौर पर,data
से रनफ़ाइलें मिलती हैं.DefaultInfo
सेrunfiles
को वापस लाने के लिए,DefaultInfo.data_runfiles
के बजायDefaultInfo.default_runfiles
का इस्तेमाल करें. आम तौर पर, ऐसा सिर्फ़ मौजूदा नियम और उसकी डिपेंडेंसी के बीच रनफ़ाइलों को मर्ज करने के लिए किया जाता है.
लेगसी प्रोवाइडर से माइग्रेट करना
अब तक, 'बेज़ल' प्रोवाइडर, Target
ऑब्जेक्ट पर सामान्य फ़ील्ड हुआ करते थे. इन्हें बिंदु ऑपरेटर का इस्तेमाल करके ऐक्सेस किया गया था. साथ ही, इन्हें नियम लागू करने वाले फ़ंक्शन से मिले स्ट्रक्चर में फ़ील्ड डालकर बनाया गया था.
इस स्टाइल का इस्तेमाल बंद कर दिया गया है और इसे नए कोड में इस्तेमाल नहीं किया जाना चाहिए; माइग्रेट करने में मदद पाने के लिए, नीचे दी गई जानकारी देखें. प्रोवाइडर के नए तरीके से, नामों के मेल खाने से बचा जा सकता है. यह डेटा छिपाने की सुविधा भी देता है. इसके लिए, किसी भी कोड को प्रोवाइडर इंस्टेंस को ऐक्सेस करने के लिए, प्रोवाइडर सिंबल का इस्तेमाल करके उसे वापस लाना होगा.
कुछ समय के लिए, लेगसी प्रोवाइडर अब भी काम कर सकते हैं. कोई नियम, लेगसी और आधुनिक, दोनों तरह के प्रोवाइडर को इस तरह दिखा सकता है:
def _old_rule_impl(ctx):
...
legacy_data = struct(x="foo", ...)
modern_data = MyInfo(y="bar", ...)
# When any legacy providers are returned, the top-level returned value is a
# struct.
return struct(
# One key = value entry for each legacy provider.
legacy_info = legacy_data,
...
# Additional modern providers:
providers = [modern_data, ...])
अगर इस नियम के एक इंस्टेंस के लिए, dep
मिलने वाला Target
ऑब्जेक्ट है, तो
सेवा देने वाली कंपनियों और उनके कॉन्टेंट को dep.legacy_info.x
के तौर पर वापस लाया जा सकता है.
dep[MyInfo].y
.
providers
के अलावा, लौटाए गए निर्देश में कई अन्य निर्देश भी लग सकते हैं
ऐसे फ़ील्ड जिनका खास मतलब होता है (और इसलिए उनसे जुड़ी लेगसी नहीं बनाते
सेवा देने वाली कंपनी):
files
,runfiles
,data_runfiles
,default_runfiles
, औरexecutable
फ़ील्ड,DefaultInfo
के एक जैसे नाम वाले फ़ील्ड से मेल खाते हैं. इनमें से किसी को भी बताने की अनुमति नहीं है ये फ़ील्ड,DefaultInfo
सेवा देने वाली कंपनी को दिखाते समय भी शामिल होंगे.output_groups
फ़ील्ड में एक स्ट्रक्चर वैल्यू होती है और यहOutputGroupInfo
.
नियमों के provides
एलान और डिपेंडेंसी एट्रिब्यूट के providers
एलान में, लेगसी प्रोवाइडर को स्ट्रिंग के तौर पर पास किया जाता है और आधुनिक प्रोवाइडर को उनके *Info
सिंबल के तौर पर पास किया जाता है. स्ट्रिंग से सिंबल को ज़रूर बदलें
माइग्रेट करते समय "सेट अप" के विकल्प चुनें. जटिल या बड़े नियम सेट के लिए, सभी नियमों को एक साथ अपडेट करना मुश्किल हो सकता है. ऐसे में, नीचे दिए गए चरणों का पालन करके, नियमों को आसानी से अपडेट किया जा सकता है:
ऊपर दिए गए सिंटैक्स का इस्तेमाल करके, लेगसी और आधुनिक, दोनों तरह के प्रोवाइडर दिखाने के लिए, लेगसी प्रोवाइडर दिखाने वाले नियमों में बदलाव करें. ऐसे नियमों के लिए जो यह घोषणा करते हैं कि साथ ही, पुराने वर्शन को पहले जैसा करने की प्रोसेस से जुड़े सेवा देने वाली नई कंपनियां हैं.
उन नियमों में बदलाव करें जो मॉडर्न प्रोवाइडर. अगर किसी एट्रिब्यूट के एलान के लिए, लेगसी प्रोवाइडर की ज़रूरत है, तो उसे अपडेट करके, आधुनिक प्रोवाइडर की ज़रूरत भी बताएं. इसके अलावा, इस काम को पहले चरण के साथ इंटरवेल किया जा सकता है. इसके लिए, उपभोक्ताओं को किसी एक सेवा देने वाली कंपनी को स्वीकार करने/उसकी ज़रूरत पड़ने की शर्त रखें:
hasattr(target, 'foo')
का इस्तेमाल करके, लेगसी सेवा देने वाली कंपनी की मौजूदगी की जांच करें याFooInfo in target
का इस्तेमाल करके, नई सेवा देने वाली कंपनी की मौजूदगी की जांच करें.सभी नियमों से लेगसी प्रोवाइडर को पूरी तरह हटाएं.