एक नियम ऐसी कार्रवाइयों की सीरीज़ के बारे में बताता है जिन पर बेज़ल परफ़ॉर्म करते हैं आउटपुट का एक सेट बनाने के लिए इनपुट, जिनका संदर्भ नियम के मुताबिक लौटाए गए providers लागू करने का फ़ंक्शन. उदाहरण के लिए, C++ बाइनरी नियम यह कर सकता है:
.cpp
सोर्स फ़ाइलों (इनपुट) का सेट लें.- सोर्स फ़ाइलों पर
g++
चलाएं (कार्रवाई). - एक्ज़ीक्यूटेबल आउटपुट और अन्य फ़ाइलों के साथ,
DefaultInfo
प्रोवाइडर को वापस करें रनटाइम पर उपलब्ध कराने के लिए. - इस एपीआई से, C++ की खास जानकारी इकट्ठा करके,
CcInfo
प्रोवाइडर को वापस भेजें टारगेट और उसकी डिपेंडेंसी.
बेज़ल के हिसाब से, g++
और स्टैंडर्ड C++ लाइब्रेरी भी इनपुट हैं
इस नियम का पालन करें. नियम लिखने वाले के तौर पर, आपको न सिर्फ़ उपयोगकर्ता के लिए उपलब्ध कराए गए
इनपुट के साथ-साथ उन सभी टूल और लाइब्रेरी को भी शामिल कर सकते हैं जो इन्हें लागू करने के लिए ज़रूरी हैं
कार्रवाइयां.
किसी भी नियम को बनाने या उसमें बदलाव करने से पहले, पक्का करें कि आपको Basel की फ़ेज़ बनाना. तीन तरीकों को समझना ज़रूरी है. बिल्ड के चरण (लोडिंग, विश्लेषण, और एक्ज़ीक्यूशन). इसके लिए भी उपयोगी है मैक्रो और नियमों के बीच के अंतर को समझने के लिए मैक्रो. शुरू करने के लिए, पहले नियमों का ट्यूटोरियल देखें. इसके बाद, इस पेज को रेफ़रंस के तौर पर इस्तेमाल करें.
Basel में भी कुछ नियम बनाए गए हैं. ये निजी नियम, जैसे
genrule
और filegroup
, हमारी थोड़ी-बहुत मदद करते हैं.
अपने नियम तय करके, उन भाषाओं और टूल के लिए सहायता जोड़ी जा सकती है
का इस्तेमाल करें.
Basel ने नियमों को लिखने के लिए, एक्सटेंशन को अलग-अलग
Starlark भाषा. ये नियम .bzl
फ़ाइलों में लिखे गए हैं, जो
इन्हें सीधे BUILD
फ़ाइलों से लोड किया जा सकता है.
अपना नियम तय करते समय, आपको यह तय करना होगा कि किन एट्रिब्यूट के साथ काम करना है और वह अपने आउटपुट कैसे जनरेट करती है.
नियम का implementation
फ़ंक्शन,
विश्लेषण का चरण. यह कोई भी फ़ंक्शन नहीं चलता है
बाहरी आदेश शामिल होते हैं. इसके बजाय, यह इस्तेमाल की जाने वाली कार्रवाइयों को रजिस्टर करता है
बाद में, नियम के आउटपुट बनाने के लिए किया जाता है. हालांकि, ऐसा तब होता है, जब वे
की ज़रूरत नहीं है.
नियम बनाना
.bzl
फ़ाइल में, नया नियम तय करने के लिए नियम फ़ंक्शन का इस्तेमाल करें
नियम बनाएं और नतीजे को ग्लोबल वैरिएबल में स्टोर करें. 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 मैक्रो कहा जाता है.
स्टारलार्क मैक्रो को आखिर में 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
नाम दिया जाता है. वे इन चीज़ों की सूची दिखाते हैं
providers हैं.
टारगेट
डिपेंडेंसी को विश्लेषण के समय 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]
इसमें लेगसी स्ट्रक्चर स्टाइल है. इसे इस्तेमाल करने की सलाह बिलकुल नहीं दी जाती. साथ ही, नियमों को इससे माइग्रेट नहीं हुआ.
फ़ाइलें
फ़ाइलों को File
ऑब्जेक्ट के तौर पर दिखाया जाता है. ऐसा इसलिए, क्योंकि Ba ज़रिए
विश्लेषण चरण के दौरान फ़ाइल 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 पाएं". कोई कार्रवाई बनाए जाने पर, Basel आदेश को तुरंत नहीं चलाता है. यह इसे डिपेंडेंसी के ग्राफ़ में रजिस्टर करता है, क्योंकि एक कार्रवाई, दूसरी कार्रवाई के नतीजे पर निर्भर कर सकती है. उदाहरण के लिए, 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 डिवाइस (इनपुट पढ़ने और आउटपुट लिखने को छोड़कर). यह है यह ज़रूरी है, क्योंकि आउटपुट को कैश मेमोरी में सेव करके, फिर से इस्तेमाल किया जाएगा.
डिपेंडेंसी का समाधान बेज़ल करता है, जो तय करता है कि किन कार्रवाइयों को लागू करना. अगर डिपेंडेंसी ग्राफ़ में कोई साइकल मौजूद है, तो यह एक गड़बड़ी है. बनाई जा रही है कोई कार्रवाई इस बात की गारंटी नहीं देती कि उसे चलाया जाएगा. यह इस बात पर निर्भर करता है कि बिल्ड के लिए आउटपुट ज़रूरी हैं.
सेवा देने वाली कंपनियां
सेवा देने वाली कंपनियां वे जानकारी होती हैं जिन्हें कोई नियम, दूसरे नियमों के दायरे में रखता है निर्भर है. इस डेटा में आउटपुट फ़ाइलें, लाइब्रेरी, और पास किए जाने वाले पैरामीटर शामिल हो सकते हैं या कुछ भी जो टारगेट के उपभोक्ताओं को पता होना चाहिए. के बारे में.
चूंकि नियम का कार्यान्वयन फ़ंक्शन केवल
इंस्टैंशिएट किए गए टारगेट की तुरंत डिपेंडेंसी के लिए, नियमों को किसी
टारगेट की डिपेंडेंसी से मिलने वाली जानकारी जिसे टारगेट
उपभोक्ताओं को भेजा जा सकता है. आम तौर पर, इस जानकारी को depset
में इकट्ठा किया जाता है.
टारगेट की सेवा देने वाली कंपनियों को, प्रोवाइडर ऑब्जेक्ट की सूची से तय किया जाता है. ये ऑब्जेक्ट, लागू करने का फ़ंक्शन.
लागू करने के पुराने फ़ंक्शन, लेगसी स्टाइल में भी लिखे जा सकते हैं जहां
लागू करने वाला फ़ंक्शन, यूआरएल की सूची के बजाय struct
दिखाता है
प्रोवाइडर ऑब्जेक्ट के लिए. यह शैली पूरी तरह से प्रोत्साहित नहीं की जाती है और नियमों को
इससे माइग्रेट नहीं हुआ.
डिफ़ॉल्ट आउटपुट
किसी टारगेट के डिफ़ॉल्ट आउटपुट ऐसे आउटपुट होते हैं जिनका अनुरोध डिफ़ॉल्ट रूप से तब किया जाता है, जब
कमांड लाइन पर बनाने के लिए टारगेट का अनुरोध किया जाता है. उदाहरण के लिए,
java_library
टारगेट //pkg:foo
में डिफ़ॉल्ट आउटपुट के तौर पर foo.jar
है. इसलिए,
कमांड bazel build //pkg:foo
की मदद से बनाया जाएगा.
डिफ़ॉल्ट आउटपुट, इसके files
पैरामीटर से तय किए जाते हैं
DefaultInfo
:
def _example_library_impl(ctx):
...
return [
DefaultInfo(files = depset([output_file]), ...),
...
]
अगर नियम लागू करने या files
लागू करने पर, DefaultInfo
नहीं मिलता है
कोई पैरामीटर नहीं चुना गया है, DefaultInfo.files
डिफ़ॉल्ट रूप से सभी पर सेट है
पहले से तय किए गए आउटपुट (आम तौर पर, जो आउटपुट" से बनाए जाते हैं
एट्रिब्यूट).
कार्रवाइयां करने वाले नियमों में डिफ़ॉल्ट आउटपुट मिलने चाहिए, भले ही वे आउटपुट सीधे तौर पर इस्तेमाल नहीं किया जाना चाहिए. वे कार्रवाइयां जो अनुरोध किए गए आउटपुट कम कर दिए जाते हैं. अगर किसी आउटपुट का इस्तेमाल सिर्फ़ टारगेट के उपभोक्ता करते हैं, तो अगर टारगेट को अलग से बनाया गया है, तो ये कार्रवाइयां नहीं की जा सकेंगी. यह डीबग करना और मुश्किल बना देता है, क्योंकि सिर्फ़ असफल टारगेट को फिर से बनाने से और उस गड़बड़ी को फिर से देख सकें.
रनफ़ाइल
रनफ़ाइलें उन फ़ाइलों का सेट होती हैं जिन्हें कोई टारगेट रनटाइम के दौरान इस्तेमाल करता है. ये फ़ाइलें, बनाने से ठीक नहीं होती हैं समय). लागू करने के चरण के दौरान, Basel ने एक डायरेक्ट्री ट्री, जिसमें रनफ़ाइल पर ले जाने वाले सिमलिंक होते हैं. इसमें स्टेज को एनवायरमेंट के तौर पर इस्तेमाल कर सकते हैं, ताकि यह रनटाइम के दौरान रनफ़ाइल को ऐक्सेस कर सके.
नियम बनाने के दौरान रनफ़ाइल मैन्युअल रूप से जोड़ी जा सकती हैं.
runfiles
ऑब्जेक्ट, runfiles
तरीके से बनाए जा सकते हैं
नियम के संदर्भ ctx.runfiles
से मेल खाना चाहिए और
DefaultInfo
पर runfiles
पैरामीटर. इसका एक्ज़ीक्यूटेबल आउटपुट
लागू किए जा सकने वाले नियम, सीधे तौर पर रनफ़ाइल में जोड़े जाते हैं.
कुछ नियम, एट्रिब्यूट के बारे में बताते हैं. इन्हें आम तौर पर
data
, जिसके आउटपुट इसमें जोड़े जाते हैं
लक्ष्य का रन करने वाली फ़ाइलें शामिल हैं. रनफ़ाइल को 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
# 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(
fields = ["files_to_link", "headers"],
init = _exampleinfo_init,
)
इसके बाद, नियम लागू होने पर, सेवा देने वाली कंपनी को इस तरह इंस्टैंशिएट किया जा सकता है:
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
निर्देश से शुरू किया गया. लागू किए जा सकने वाले और जांच के नियमों को इन्होंने बनाया है
executable
को सेट करें या
rule
को किए गए कॉल में True
के लिए test
तर्क:
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(
...
)
रनफ़ाइल की जगह
जब किसी एक्ज़ीक्यूटेबल टारगेट को 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
डायरेक्ट्री. हालांकि, रनफ़ाइल से नाम की बाइनरी नहीं बना सकतीं
नहीं कर रहे हैं. इसे कम करने के लिए, हर बाइनरी को
किसी एनवायरमेंट या कमांड लाइन का इस्तेमाल करके, रनफ़ाइल रूट को पैरामीटर के तौर पर स्वीकार करता है
तर्क या फ़्लैग जोड़ें. इससे बाइनरी को सही कैननिकल रनफ़ाइल रूट पास करने की अनुमति मिलती है
उसे बाइनरी पर ले जाते हैं. अगर यह सेट नहीं है, तो बाइनरी से अनुमान लगाया जा सकता है कि यह
पहली बाइनरी को कॉल किया जाता है और उसके बगल में बनी किसी रनफ़ाइल डायरेक्ट्री को खोजा जाता है.
उन्नत विषय
आउटपुट फ़ाइलों का अनुरोध किया जा रहा है
एक टारगेट में कई आउटपुट फ़ाइलें हो सकती हैं. जब bazel build
निर्देश यह होता है
चलाएं, तो कमांड को दिए गए टारगेट के कुछ आउटपुट के रूप में
अनुरोध किया जाएगा. Baज़र, सिर्फ़ उन फ़ाइलों और फ़ाइलों को बनाता है जिनका अनुरोध किया गया है
सीधे तौर पर या किसी अन्य तरीके से. (ऐक्शन ग्राफ़ के हिसाब से, सिर्फ़ 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 के पास "कॉन्फ़िगरेशन" का एक सिद्धांत होता है और ट्रांज़िशन शामिल हैं. कॉन्टेंट बनाने सबसे लोकप्रिय टारगेट (जिनके लिए कमांड लाइन पर अनुरोध किया गया है) में पहले से ही "टारगेट" कॉन्फ़िगरेशन, जबकि ऐसे टूल जो एक्ज़ीक्यूशन प्लैटफ़ॉर्म पर चलने चाहिए पहले से मौजूद "exec" हों कॉन्फ़िगरेशन. नियम के आधार पर, अलग-अलग कार्रवाइयां जनरेट की जा सकती हैं कॉन्फ़िगरेशन पर, उदाहरण के लिए, पास किए गए सीपीयू आर्किटेक्चर को बदलने के लिए कंपाइलर को भेजा जा सकता है. कुछ मामलों में, अलग-अलग क्वेरी के लिए एक ही लाइब्रेरी की ज़रूरत कॉन्फ़िगरेशन. अगर ऐसा होता है, तो इसका विश्लेषण किया जाएगा और संभावित तौर पर इसे बनाया जाएगा कई बार इस्तेमाल किया जा सकता है.
डिफ़ॉल्ट रूप से, Baze टारगेट की डिपेंडेंसी उसी कॉन्फ़िगरेशन में बनाता है जो दूसरे शब्दों में कहें, तो टारगेट में कोई बदलाव नहीं होगा. जब डिपेंडेंसी जिसकी ज़रूरत टारगेट बनाने में होती है, संबंधित एट्रिब्यूट को किसी exec कॉन्फ़िगरेशन में ट्रांज़िशन दर्ज करें. यह टूल और उसके सभी डिपेंडेंसी जो एक्ज़ीक्यूशन प्लैटफ़ॉर्म के लिए बनाई जा सकती हैं.
हर डिपेंडेंसी एट्रिब्यूट के लिए, cfg
का इस्तेमाल करके यह तय किया जा सकता है कि डिपेंडेंसी है या नहीं
को उसी कॉन्फ़िगरेशन में बनाना चाहिए या किसी exec कॉन्फ़िगरेशन में ट्रांज़िशन करना चाहिए.
अगर किसी डिपेंडेंसी एट्रिब्यूट में executable = True
फ़्लैग है, तो cfg
को सेट करना ज़रूरी है
साफ़ तौर पर बताया गया है. यह गलत जानकारी के लिए गलती से टूल बनाने से बचने के लिए है
कॉन्फ़िगरेशन.
उदाहरण देखें
सामान्य तौर पर, सोर्स, डिपेंडेंट लाइब्रेरी, और एक्ज़ीक्यूटेबल की ज़रूरत होती है रनटाइम इसी कॉन्फ़िगरेशन का इस्तेमाल कर सकता है.
बिल्ड के हिस्से के तौर पर इस्तेमाल किए जाने वाले टूल, जैसे कि कंपाइलर या कोड जनरेटर
एक exec कॉन्फ़िगरेशन के लिए बनाया जाना चाहिए. इस मामले में, cfg = "exec"
को
एट्रिब्यूट की वैल्यू सबमिट करें.
नहीं तो, रनटाइम के दौरान इस्तेमाल किए जाने वाले एक्ज़ीक्यूटेबल (जैसे कि टेस्ट के हिस्से) के लिए
को टारगेट कॉन्फ़िगरेशन के लिए बनाया जाना चाहिए. इस मामले में, cfg = "target"
को
एट्रिब्यूट की वैल्यू सबमिट करें.
cfg = "target"
असल में कुछ नहीं करता: यह पूरी तरह से आपके लिए
ताकि वे नियम बनाने वाले लोगों को अपने इरादों के बारे में साफ़ तौर पर बता सकें. जब executable = False
,
इसका मतलब है कि cfg
का इस्तेमाल करना ज़रूरी नहीं है. इसे सिर्फ़ तब सेट करें, जब यह पढ़ने में आसान हो.
cfg = my_transition
का इस्तेमाल करके,
उपयोगकर्ता के तय किए गए ट्रांज़िशन. इसकी मदद से,
नियम लिखने वालों को कॉन्फ़िगरेशन बदलने में बहुत ज़्यादा सुविधा मिलती है,
इसकी कमी
बिल्ड ग्राफ़ को बड़ा और कम समझ में आने लायक बनाना.
ध्यान दें: पहले, Basel के पास प्रोग्राम चलाने के प्लैटफ़ॉर्म का कॉन्सेप्ट नहीं था, और इसके बजाय, सभी बिल्ड ऐक्शन को होस्ट मशीन पर चलाया जाता था. बेज़ल वर्शन 6.0 से पहले वाले वर्शन में एक अलग "होस्ट" बन जाता था कॉन्फ़िगरेशन का इस्तेमाल करें. अगर आपको "होस्ट" के रेफ़रंस दिखते हैं, तो या पुराने दस्तावेज़ में, यही का संदर्भ है. इस अतिरिक्त कॉन्सेप्ट से बचने के लिए, हमारा सुझाव है कि आप Basel 6.0 या उसके बाद के वर्शन का इस्तेमाल करें है.
कॉन्फ़िगरेशन फ़्रैगमेंट
नियम ऐक्सेस कर सकते हैं
कॉन्फ़िगरेशन फ़्रैगमेंट, जैसे कि
cpp
और java
. हालांकि, सभी ज़रूरी फ़्रैगमेंट का एलान
ऐक्सेस करने में आने वाली गड़बड़ियों से बचने के लिए:
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
...
)
रनफ़ाइल सिमलिंक
आम तौर पर, रनफ़ाइल ट्री में किसी फ़ाइल का रिलेटिव पाथ
सोर्स ट्री या जनरेट किए गए आउटपुट ट्री में उस फ़ाइल का रिलेटिव पाथ. अगर ये
किसी वजह से अलग होने चाहिए, तो आप यह बता सकते हैं 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 पर लौटाया गया सामान
True
कवरेज मोड में, अगर टारगेट के स्रोतों को इंस्ट्रुमेंट किया जाना चाहिए:
# 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
नहीं लौटाया जाता है, तो हर एक के साथ एक डिफ़ॉल्ट डोमेन बन जाएगा
नॉन-टूल डिपेंडेंसी एट्रिब्यूट, जो सेट नहीं होता है
एट्रिब्यूट स्कीमा में cfg
से "exec"
तक. इंच
dependency_attributes
. (यह सही व्यवहार नहीं है, क्योंकि इसमें एट्रिब्यूट
जैसे, source_attributes
के बजाय dependency_attributes
में srcs
, लेकिन यह
में सभी नियमों के लिए स्पष्ट कवरेज कॉन्फ़िगरेशन की आवश्यकता से बचाता है
डिपेंडेंसी चेन.)
पुष्टि करने की कार्रवाइयां
कभी-कभी आपको बिल्ड से जुड़ी किसी चीज़ की पुष्टि करनी पड़ती है और पुष्टि करने के लिए ज़रूरी जानकारी सिर्फ़ आर्टफ़ैक्ट में उपलब्ध है (सोर्स फ़ाइलें या जनरेट की गई फ़ाइलें). यह जानकारी आर्टफ़ैक्ट में है, इसलिए नियम, विश्लेषण के समय पुष्टि नहीं कर सकते, क्योंकि नियम नहीं पढ़े जा सकते फ़ाइलें शामिल हैं. इसके बजाय, कार्रवाइयों को निष्पादन के समय यह सत्यापन करना चाहिए. टास्क कब शुरू होगा सत्यापन विफल रहता है, कार्रवाई विफल हो जाएगी और इसलिए बिल्ड भी होगा.
स्टैटिक विश्लेषण, लिंटिंग, और अन्य पुष्टि करने के तरीकों के उदाहरण डिपेंडेंसी और कंसिस्टेंसी चेकिंग के साथ-साथ स्टाइल की जांच भी की जाती है.
पुष्टि करने की कार्रवाइयों से भी परफ़ॉर्मेंस को बेहतर बनाने में मदद मिल सकती है. इसके लिए, अलग-अलग पार्ट को मूव करें ऐसी कार्रवाइयां जिन्हें अलग-अलग कार्रवाइयों में आर्टफ़ैक्ट बनाने के लिए ज़रूरी नहीं है. उदाहरण के लिए, अगर कंपाइलेशन और लिंटिंग करने वाली एक कार्रवाई उन्हें एक कंपाइलेशन ऐक्शन और लिंटिंग ऐक्शन में अलग किया गया, फिर लिंटिंग कार्रवाई को पुष्टि करने की कार्रवाई के तौर पर चलाया जा सकता है. साथ ही, इसे दूसरी कार्रवाइयों के साथ भी चलाया जा सकता है.
"पुष्टि करने की ये कार्रवाइयां" वे अक्सर ऐसा कुछ नहीं बनाते जिसका इस्तेमाल कहीं और किया जाता है क्योंकि उन्हें सिर्फ़ अपने इनपुट के बारे में दावा करना होता है. यह हालांकि, एक समस्या आती है: अगर पुष्टि करने की कार्रवाई से ऐसा कुछ नहीं होता इसका इस्तेमाल बिल्ड में कहीं और किया जाता है. नियम को कार्रवाई करने के लिए कैसे कहा जाता है? पहले, यह तरीका था कि पुष्टि करने वाली कार्रवाई का आउटपुट खाली था फ़ाइल हो सकती है, और उस आउटपुट को किसी अन्य महत्वपूर्ण बिल्ड में क्या-क्या मौजूद है:
यह इसलिए काम करता है, क्योंकि कंपाइलेशन के समय बेज़ल पुष्टि करने की कार्रवाई हमेशा चलाएगा कार्रवाई की गई, लेकिन इसकी कुछ बड़ी कमियां हैं:
पुष्टि करने की कार्रवाई, बिल्ड के अहम पाथ में होती है. क्योंकि बेज़ल को लगता है कि कंपाइल ऐक्शन चलाने के लिए खाली आउटपुट ज़रूरी है, तो यह पुष्टि करने की कार्रवाई पहले करें, भले ही कंपाइल करने की कार्रवाई इनपुट को अनदेखा करेगी. यह पैरलिज़्म को कम करता है और बिल्ड को धीमा करता है.
अगर इसके बजाय बिल्ड में अन्य कार्रवाइयां चल सकती हैं कार्रवाई को कंपाइल करें, फिर पुष्टि करने की कार्रवाइयों के खाली आउटपुट जोड़ने होंगे वे कार्रवाइयाँ भी होंगी (उदाहरण के लिए,
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
या
इनपुट का इस्तेमाल करें. इस नियम के टाइप के टारगेट के लिए, पुष्टि करने की कार्रवाई
तब भी चलेगा, जब टारगेट लेबल या किसी टारगेट के
इंप्लिसिट आउटपुट, सीधे तौर पर या किसी अन्य तरीके से इन पर निर्भर होते हैं.
आम तौर पर, यह ज़रूरी होता है कि पुष्टि करने से जुड़ी कार्रवाइयों के आउटपुट सिर्फ़ उसे पुष्टि करने वाले आउटपुट ग्रुप में शामिल किया जाता है और उसे दूसरी कार्रवाइयों के इनपुट में नहीं जोड़ा जाता है, जैसे कि इससे, साथ-साथ काम करने की क्षमता हासिल नहीं की जा सकती. हालांकि, ध्यान दें कि बेज़ल अपने हाथ में को लागू करने के लिए कोई विशेष जांच है. इसलिए, आपको कि पुष्टि करने वाली कार्रवाई के आउटपुट को, 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
पैरामीटर में पास करें.
ऐसी सुविधाएं रन करें जिन्हें रोकना
ctx.runfiles
और runfiles
टाइप में सुविधाओं का एक जटिल सेट होता है. इनमें से कई सुविधाएं लेगसी वजहों से रखी जाती हैं.
ये सुझाव, जटिलता को कम करने में मदद करते हैं:
इसके
collect_data
औरcollect_default
मोड का इस्तेमाल करने से बचेंctx.runfiles
. ये मोड, अनजाने में डेटा इकट्ठा करते हैं रनफ़ाइल को कुछ हार्डकोड डिपेंडेंसी किनारों पर भ्रम की स्थिति में डाल दिया जाता है. इसके बजाय, इसकेfiles
याtransitive_files
पैरामीटर का इस्तेमाल करके फ़ाइलें जोड़ेंctx.runfiles
से याrunfiles = runfiles.merge(dep[DefaultInfo].default_runfiles)
.data_runfiles
औरdefault_runfiles
का इस्तेमाल करने से बचेंDefaultInfo
कंस्ट्रक्टर. इसके बजाय,DefaultInfo(runfiles = ...)
के बारे में बताएं. "डिफ़ॉल्ट" के बीच फ़र्क़ और "data" रनफ़ाइल का रखरखाव किया जाता है शामिल हैं. उदाहरण के लिए, कुछ नियम अपने डिफ़ॉल्ट आउटपुट कोdata_runfiles
, लेकिनdefault_runfiles
नहीं. का उपयोग करने के बजायdata_runfiles
, नियमों में डिफ़ॉल्ट आउटपुट और मर्ज इन दोनों होने चाहिए रनफ़ाइल उपलब्ध कराने वाले एट्रिब्यूट सेdefault_runfiles
(अक्सरdata
).DefaultInfo
सेrunfiles
की जानकारी हासिल करने पर (आम तौर पर, ऐसा सिर्फ़ मर्ज करने के लिए होता है) मौजूदा नियम और उसकी निर्भरता के बीच रनफ़ाइल), इसका इस्तेमाल करेंDefaultInfo.default_runfiles
, नDefaultInfo.data_runfiles
.
लेगसी प्रोवाइडर से माइग्रेट करना
अब तक, 'बेज़ल' प्रोवाइडर, Target
ऑब्जेक्ट पर सामान्य फ़ील्ड हुआ करते थे. वे
डॉट ऑपरेटर का इस्तेमाल करके ऐक्सेस किया गया था और उन्हें फ़ील्ड
struct
में, नियम के
लागू फ़ंक्शन का इस्तेमाल करें:
return struct(example_info = struct(headers = depset(...)))
ऐसी कंपनियों की जानकारी, Target
ऑब्जेक्ट से जुड़े फ़ील्ड से वापस पाई जा सकती है:
transitive_headers = [hdr.example_info.headers for hdr in ctx.attr.hdrs]
यह शैली रोक दी गई है और नए कोड में इसका इस्तेमाल नहीं किया जाना चाहिए; यहां देखें: माइग्रेट करने में मदद कर सकती है. सेवा देने वाली नई कंपनी के नाम से बचा जाता है झड़पें. यह डेटा को छिपाने में भी मदद करता है. ऐसा करने के लिए, प्रोवाइडर इंस्टेंस का इस्तेमाल करके, इसे वापस पाया जा सकता है.
कुछ समय के लिए, लेगसी प्रोवाइडर अब भी काम कर सकते हैं. एक नियम दोनों नतीजे दे सकता है सेवा देने वाली नई और पुरानी कंपनियों की सेवाओं के बारे में नीचे बताया गया है:
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
चिह्न से पास किया जाता है. स्ट्रिंग से सिंबल को ज़रूर बदलें
माइग्रेट करते समय "सेट अप" के विकल्प चुनें. जटिल या बड़े नियम सेट के लिए जहां अपडेट करना मुश्किल होता है
सभी नियम स्वचालित रूप से, यदि आप
चरण:
उन नियमों में बदलाव करें जो लेगसी प्रोवाइडर को बनाने के लिए, लेगसी वर्शन बनाते हैं और मॉडर्न कंपनियां, ऊपर दिए गए सिंटैक्स का इस्तेमाल करती हों. ऐसे नियमों के लिए जो यह घोषणा करते हैं कि साथ ही, पुराने वर्शन को पहले जैसा करने की प्रोसेस से जुड़े सेवा देने वाली नई कंपनियां हैं.
उन नियमों में बदलाव करें जो मॉडर्न प्रोवाइडर. अगर किसी एट्रिब्यूट की घोषणा के लिए, लेगसी प्रोवाइडर की ज़रूरत होती है, साथ ही, उन्हें अपडेट करने के बजाय, मॉडर्न प्रोवाइडर की ज़रूरत के हिसाब से अपडेट करें. इसके अलावा, आपके पास पहले चरण में यह काम पूरा करें. इसके लिए, उपभोक्ताओं को provider: इसका इस्तेमाल करके, लेगसी प्रोवाइडर की मौजूदगी का पता लगाने के लिए जांच करना
hasattr(target, 'foo')
, याFooInfo in target
का इस्तेमाल करने वाली नई कंपनी.लेगसी प्रोवाइडर को सभी नियमों से पूरी तरह हटाएं.