नियम

नियम, actions की एक ऐसी सीरीज़ के बारे में बताता है जिसे बेज़ल, आउटपुट पर सेट बनाने के लिए इनपुट पर करते हैं. इन आउटपुट का संदर्भ यहां दिया गया है सेवा देने वाली कंपनियों ने नियम लागू करने का फ़ंक्शन लौटाया. उदाहरण के लिए, C++बाइनरी नियम:

  1. .cpp सोर्स फ़ाइलों (इनपुट) का सेट चुनें.
  2. स्रोत फ़ाइलों (कार्रवाई) पर g++ चलाएं.
  3. रनटाइम पर उपलब्ध कराने के लिए, DefaultInfo कंपनी को एक्ज़ीक्यूटेबल आउटपुट और अन्य फ़ाइल के साथ लौटाएं.
  4. टारगेट और इसकी डिपेंडेंसी से इकट्ठा की गई C++-खास जानकारी के साथ CcInfo सेवा देने वाली कंपनी को लौटाएं.

बैजल के नज़रिए से, g++ और स्टैंडर्ड C++ लाइब्रेरी भी इस नियम के लिए इनपुट देती हैं. नियम लेखक के रूप में, आपको न सिर्फ़ नियम को उपयोगकर्ता के दिए हुए इनपुट पर विचार करना चाहिए, बल्कि कार्रवाइयां करने के लिए ज़रूरी सभी टूल और लाइब्रेरी पर भी विचार करना चाहिए.

किसी नियम को बनाने या उसमें बदलाव करने से पहले, पक्का करें कि आप Bazel की बिल्डिंग की प्रोसेस के बारे में जानते हैं. बिल्ड के तीन चरणों (लोड करना, विश्लेषण, और काम करना) को समझना ज़रूरी है. इससे नियमों और मैक्रो के बीच का अंतर समझने के लिए, मैक्रो के बारे में भी जानना उपयोगी होता है. शुरू करने के लिए, पहले नियम ट्यूटोरियल की समीक्षा करें. इसके बाद, इस पेज का इस्तेमाल पहचान फ़ाइल के तौर पर करें.

कुछ नियम, बैजल में ही बनाए गए हैं. ये नेटिव नियम, जैसे कि cc_library और java_binary कुछ भाषाओं के लिए मुख्य मदद देते हैं. अपने नियम तय करके, आप उन भाषाओं और टूल के लिए मिलती-जुलती सहायता जोड़ सकते हैं जिनकी भाषा में मूल रूप से सहायता नहीं होती है.

बैजल 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 मैक्रो कहा जाता है. Starlark मैक्रो को आखिर में BUILD फ़ाइलों से कॉल किया जाना चाहिए. इन्हें सिर्फ़ लोड होने के चरण के दौरान कॉल किया जा सकता है. ऐसा तब होता है, जब BUILD फ़ाइलों का आकलन, टारगेट को तुरंत पूरा करने के लिए किया जाता है.

विशेषताएं

एट्रिब्यूट नियम का तर्क है. एट्रिब्यूट किसी टारगेट को लागू करने के लिए खास मान दे सकते हैं या वे दूसरे टारगेट का संदर्भ दे सकते हैं, जो डिपेंडेंसी का ग्राफ़ बना सकते हैं.

नियम से जुड़ी खास विशेषताएं, जैसे किsrcs याdeps, एट्रिब्यूट के नामों से स्कीमा तक का मैप पास करके तय किया जाता है (इसका इस्तेमाल करके बनाया गयाattr module)attrs का पैरामीटरrule चुनें. सामान्य विशेषताएं, जैसे कि name और visibility सीधे तौर पर सभी नियमों में जोड़ी जाती हैं. कुछ अन्य एट्रिब्यूट, खास तौर पर लागू किए जा सकने वाले और टेस्ट के नियमों में जोड़े जाते हैं. किसी नियम को सीधे तौर पर किसी नियम में जोड़ा जाने वाला एट्रिब्यूट, attrs में भेजे गए शब्दकोश में शामिल नहीं किया जा सकता.

निर्भरता की विशेषताएं

आम तौर पर, सोर्स कोड को प्रोसेस करने वाले नियम, नीचे दी गई विशेषताएं तय करते हैं, ताकि अलग-अलग तरह की डिपेंडेंसी का ध्यान रखा जा सके:

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

निजी विशेषताएं और सीधे तौर पर मौजूद डिपेंडेंसी

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

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

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 ऑब्जेक्ट के तौर पर दिखाया जाता है. इन ऑब्जेक्ट में सेवा देने वाली कंपनियां शामिल होती हैं, जो टारगेट लागू करने के काम करने के दौरान जनरेट की जाती हैं.

ctx.attr में, हर निर्भरता एट्रिब्यूट के नाम से जुड़े फ़ील्ड हैं. इसमें हर ऑब्जेक्ट पर निर्भरता वाले Target ऑब्जेक्ट होते हैं. label_list एट्रिब्यूट के लिए, यह Targets की सूची है. label एट्रिब्यूट के लिए, यह एक Target या None है.

कंपनी के ऑब्जेक्ट की सूची, टारगेट लागू करने के फ़ंक्शन से मिलती है:

return [ExampleInfo(headers = depset(...))]

उन्हें इंडेक्स नोटेशन ([]) का इस्तेमाल करके, सेवा देने वाली कंपनी के प्रकार की कुंजी के ज़रिए ऐक्सेस किया जा सकता है. ये Starlark में तय की गई कस्टम सेवा देने वाली कंपनियां या ऐसे स्थानीय नियम दे सकते हैं जो Starlark ग्लोबल वैरिएबल के तौर पर उपलब्ध हैं.

उदाहरण के लिए, अगर कोई नियम hdrs विशेषता के ज़रिए हेडर फ़ाइलें लेता है और उन्हें टारगेट और उसके उपभोक्ताओं की कंपाइलेशन कार्रवाइयों से जोड़ता है, तो वह उन्हें इस तरह इकट्ठा कर सकता है:

def _example_library_impl(ctx):
    ...
    transitive_headers = [dep[ExampleInfo].headers for dep in ctx.attr.deps]

उस विरासती स्टाइल के लिए जिसमें प्रोवाइडर ऑब्जेक्ट की सूची के बजाय टारगेट लागू करने के फ़ंक्शन से struct लौटाया जाता है:

return struct(example_info = struct(headers = depset(...)))

Target ऑब्जेक्ट से जुड़े फ़ील्ड से, सेवा देने वाली कंपनियों की जानकारी हासिल की जा सकती है:

transitive_headers = [dep.example_info.headers for dep in ctx.attr.deps]

इस तरीके का इस्तेमाल करने की सलाह नहीं दी जाती है. साथ ही, नियमों को इससे दूर माइग्रेट कर दिया जाना चाहिए.

फ़ाइलें

फ़ाइलों को File ऑब्जेक्ट से दिखाया जाता है. विश्लेषण के दौरान, बेज़ेल फ़ाइल 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 चुनें.

कार्रवाइयां

इस बारे में जानकारी दी गई है कि इनपुट के सेट से आउटपुट का सेट कैसे जनरेट किया जाता है.उदाहरण के लिए, "हैलो ccc को चलाएं और हैलो.ओ पाएं." जब कोई कार्रवाई बनाई जाती है, तो बैजल तुरंत निर्देश नहीं भेजता है. यह डिपेंडेंसी के ग्राफ़ में इसे रजिस्टर करता है, क्योंकि कोई कार्रवाई किसी दूसरी कार्रवाई के आउटपुट पर निर्भर कर सकती है. उदाहरण के लिए, 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],
    )
    ...

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

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

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

कार्रवाइयां, ठीक तरह से काम करने वाले फ़ंक्शन के बराबर होती हैं: उन्हें सिर्फ़ दिए गए इनपुट पर निर्भर करना चाहिए. साथ ही, उन्हें कंप्यूटर की जानकारी, उपयोगकर्ता नाम, घड़ी, नेटवर्क या I/O डिवाइस (इनपुट पढ़ने और आउटपुट लिखने को छोड़कर) को ऐक्सेस करने से बचना चाहिए. यह इसलिए ज़रूरी है, क्योंकि आउटपुट को कैश मेमोरी में सेव किया जाएगा और फिर से इस्तेमाल किया जाएगा.

निर्भरता का फ़ैसला बज़ेल करता है, इससे यह तय होगा कि कौनसी कार्रवाइयां लागू होंगी. डिपेंडेंसी ग्राफ़ में कोई साइकल होने पर, यह गड़बड़ी होती है. किसी कार्रवाई को बनाने से इस बात की गारंटी नहीं मिलती कि उसे लागू किया जाएगा या नहीं, यह इस बात पर निर्भर करता है कि बिल्ड के लिए उसके आउटपुट की ज़रूरत है या नहीं.

सेवा देने वाली कंपनियां

सेवा देने वाली कंपनियां उस जानकारी के एक हिस्से होते हैं जो किसी नियम से जुड़ी दूसरी बातों के मुताबिक होती हैं. इस डेटा में आउटपुट फ़ाइलें, लाइब्रेरी, टूल की कमांड लाइन पर पास किए जाने वाले पैरामीटर या ऐसी कोई भी जानकारी शामिल हो सकती है जिसके बारे में टारगेट के उपभोक्ताओं को पता होना चाहिए.

किसी नियम को लागू करने वाला फ़ंक्शन, सिर्फ़ सेवा देने वाली कंपनियों को ही इंस्टैंट टारगेट की गई डिपेंडेंसी से पढ़ सकता है. इसलिए, नियमों को किसी भी ऐसी शर्त से तय किया जाता है जो टारगेट किए जाने वाले उपभोक्ताओं की ज़रूरत के मुताबिक हो एक 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]), ...),
        ...
    ]

अगरDefaultInfo किसी नियम को लागू करके याfiles पैरामीटर मौजूद नहीं है, DefaultInfo.files सभी के लिए डिफ़ॉल्ट पहले से तय आउटपुट (आम तौर पर, जो क्रिएटर्सआउटपुट विशेषता ).

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

रनफ़ाइल

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

नियम बनाने के दौरान रनफ़ाइलें मैन्युअल रूप से जोड़ी जा सकती हैं. runfilesऑब्जेक्टrunfiles नियम के संदर्भ मेंctx.runfiles और उन्हें runfiles पैरामीटर चालू हैDefaultInfo चुनें. लागू होने वाले नियमों का एक्ज़ीक्यूटेबल आउटपुट, रनफ़ाइल में साफ़ तौर पर जोड़ा जाता है.

कुछ नियमों में, आम तौर पर data नाम वाली विशेषताएं दी जाती हैं. इन आउटपुट के टारगेट में फ़ाइल की रनफ़ाइल जोड़ी जाती है. रनटाइम फ़ाइलों को भी यहां से मर्ज किया जाना चाहिएdata साथ ही, ऐसे किसी भी एट्रिब्यूट से जो आम तौर पर, एक्ज़ीक्यूशन के लिए कोड दे सकता है, आम तौर पर srcs (जिसमें यह हो सकता हैfilegroup इससे जुड़े टारगेटdata ) और 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
              ],
          ),
      )
  ]
सेवा देने वाली कंपनियों को अपनी पसंद के मुताबिक शुरू करना

कस्टम प्री-प्रोसेसिंग और सत्यापन लॉजिक के साथ सेवा देने वाली कंपनी को झटपट चालू करना संभव है. इसका इस्तेमाल यह पक्का करने के लिए किया जा सकता है कि सेवा देने वाली सभी कंपनियों के इंस्टेंस कुछ अलग-अलग वर्शन का पालन करते हैं या उपयोगकर्ताओं को इंस्टेंस बनाने के लिए एक बेहतर एपीआई देते हैं.

ऐसा provider फ़ंक्शन में init कॉलबैक पास करके किया जाता है. अगर यह कॉलबैक दिया गया है, तो 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
    )

RAW कंस्ट्रक्टर का इस्तेमाल वैकल्पिक सार्वजनिक फ़ैक्ट्री फ़ंक्शन को तय करने के लिए किया जा सकता है जो 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)

आम तौर पर, RAW कंस्ट्रक्टर एक ऐसे वैरिएबल से जुड़ा होता है जिसका नाम अंडरस्कोर (_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 या test इसका तर्कTrue कॉल मेंrule:

example_binary = rule(
   implementation = _example_binary_impl,
   executable = True,
   ...
)

example_test = rule(
   implementation = _example_binary_impl,
   test = True,
   ...
)

जांच के नियमों में ऐसे नाम होने चाहिए जो _test से खत्म हों. (टारगेट नामों का परीक्षण अक्सर पारंपरिक तौर पर _test में भी होता है, लेकिन इसकी ज़रूरत नहीं है.) बिना जांच वाले नियमों में यह सफ़िक्स नहीं होना चाहिए.

दोनों तरह के नियमों को एक ऐसी आउटपुट फ़ाइल बनानी चाहिए जिसे एलान किया जा सकता हो या नहीं किया जा सके. ऐसा run या test निर्देशों की मदद से किया जाएगा. बैजेल को यह बताने के लिए कि किसी नियम के आउटपुट का इस्तेमाल, इस एक्ज़ीक्यूटेबल के तौर पर कैसे किया जाए, इसे लौटाए गए DefaultInfo सेवा देने वाले के executable तर्क के तौर पर पास करें. उस executable को नियम के डिफ़ॉल्ट आउटपुट में जोड़ दिया जाता है (इसलिए आपको इसे executable और files दोनों को भेजने की ज़रूरत नहीं है). इसे साफ़ तौर पर रनफ़ाइल में भी जोड़ा जाता है:

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 executable_file and runfile_file:
runfiles_root = executable_file.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 निर्देश चलाया जाता है, तो दिए गए टारगेट के कुछ आउटपुट को अनुरोध किया जाता है. बैजल सिर्फ़ उन अनुरोध की गई फ़ाइलों को तैयार करती हैं जिन्हें वे सीधे तौर पर या किसी दूसरे तरीके से तय करते हैं. (कार्रवाई ग्राफ़ के मामले में, बेज़ेल सिर्फ़ उन कार्रवाइयों को लागू करता है जिनके लिए अनुरोध की गई फ़ाइलों का ट्रांज़िट निर्भरता होता है.)

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

ध्यान दें कि आम तौर पर OutputGroupInfo का इस्तेमाल, टारगेट से लेकर खास तरह की फ़ाइलों के बारे में बताने के लिए नहीं किया जाना चाहिए. इसके बजाय, इसके लिए खास तौर पर नियम की सेवा देने वाली कंपनियां तय करें.

कॉन्फ़िगरेशन

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

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

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

हर डिपेंडेंसी एट्रिब्यूट के लिए, आप cfg का इस्तेमाल करके यह तय कर सकते हैं कि डिपेंडेंसी एक ही कॉन्फ़िगरेशन में होनी चाहिए या एक एक्सकेशन कॉन्फ़िगरेशन में ट्रांज़िशन होना चाहिए. अगर डिपेंडेंसी एट्रिब्यूट में फ़्लैग executable=True है, तो cfg को साफ़ तौर पर सेट करना चाहिए. यह गलत कॉन्फ़िगरेशन के लिए, गलती से टूल बनाने से बचने के लिए है. उदाहरण देखें

आम तौर पर, रनटाइम के लिए ज़रूरी स्रोत, निर्भर लाइब्रेरी, और एक्ज़ीक्यूटेबल एक ही कॉन्फ़िगरेशन का इस्तेमाल कर सकते हैं.

बिल्ड के हिस्से के तौर पर इस्तेमाल किए जाने वाले टूल (जैसे कंपाइलर या कोड जनरेटर) एक कसरत कॉन्फ़िगरेशन के लिए बनाए जाने चाहिए. इस मामले में, एट्रिब्यूट में cfg="exec" की जानकारी दें.

नहीं तो, रनटाइम पर इस्तेमाल की जाने वाली एक्ज़ीक्यूटेबल (जैसे कि जांच के हिस्से के तौर पर) टारगेट कॉन्फ़िगरेशन के लिए बनाई जानी चाहिए. इस मामले में, एट्रिब्यूट में cfg="target" की जानकारी दें.

असल में cfg="target" कुछ नहीं करता है: यह नियम डिज़ाइनर की इच्छा के बारे में साफ़ तौर पर जानकारी देने में मदद करने के लिए पूरी तरह से एक सुविधा मान है. जब executable=False, इसका मतलब है कि cfg ज़रूरी नहीं है, तो इसे सिर्फ़ तब सेट करें, जब वाकई इसे पढ़ने में मदद मिले.

आप cfg=my_transition का इस्तेमाल करके, उपयोगकर्ता के तय किए गए ट्रांज़िशन का इस्तेमाल भी कर सकते हैं. इसकी मदद से, नियम बनाने वाले लोग कॉन्फ़िगरेशन को बदलने की प्रक्रिया में आसानी से बदलाव कर सकते हैं. इसके लिए, वे {101 ड्रॉबैक} कर सकते हैं }बिल्ड ग्राफ़ को बड़ा और कम समझ में आने वाला बनाना.

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

"होस्ट" और "exec" कॉन्फ़िगरेशन के बीच कई अंतर हैं:

  • "होस्ट" टर्मिनल है, "exec" नहीं है: एक बार डिपेंडेंसी, "host" कॉन्फ़िगरेशन में होने पर, किसी और ट्रांज़िशन की अनुमति नहीं है. "exec" कॉन्फ़िगरेशन में आने पर आप आगे से कॉन्फ़िगरेशन ट्रांज़िशन करना जारी रख सकते हैं.
  • "होस्ट" मोनोलिथिक है, "exec" नहीं है: सिर्फ़ एक "होस्ट" कॉन्फ़िगरेशन है, लेकिन हर एक परफ़ॉर्मेंस प्लैटफ़ॉर्म के लिए अलग-अलग "exec" कॉन्फ़िगरेशन हो सकता है.
  • "host" में यह माना जाता है कि आप उसी मशीन पर Bazzel की तरह के टूल या बहुत हद तक मिलती-जुलती मशीन चलाते हैं. यह अब सही नहीं है: आप अपनी स्थानीय मशीन या बिल्ड एक्ज़ीक्यूटर पर बिल्ड कार्रवाइयां चला सकते हैं और इस बात की कोई गारंटी नहीं है कि रिमोट एक्ज़ीक्यूटर आपके सीपीयू मशीन और ओएस जैसा ही है.

"exec" और "host" कॉन्फ़िगरेशन, दोनों एक ही विकल्प के बदलाव लागू करते हैं (उदाहरण के लिए, --host_compilation_mode से --compilation_mode सेट करें, --host_cpu से --cpu सेट करें, वगैरह) चुनें. अंतर यह है कि "होस्ट" कॉन्फ़िगरेशन दूसरे सभी फ़्लैग के डिफ़ॉल्ट मानों से शुरू होता है, जबकि "exec" कॉन्फ़िगरेशन मौजूदा मानों से शुरू होता है फ़्लैग के हिसाब से.

कॉन्फ़िगरेशन फ़्रैगमेंट

नियम कॉन्फ़िगरेशन फ़्रैगमेंट को ऐक्सेस कर सकते हैं, जैसे कि 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
    ...
)

ctx.fragments सिर्फ़ टारगेट कॉन्फ़िगरेशन के लिए कॉन्फ़िगरेशन फ़्रैगमेंट उपलब्ध कराता है. अगर आप होस्ट कॉन्फ़िगरेशन के फ़्रैगमेंट ऐक्सेस करना चाहते हैं, तो ctx.host_fragments का इस्तेमाल करें.

आम तौर पर, रनफ़ाइल ट्री में किसी फ़ाइल का मिलते-जुलते पाथ, स्रोत ट्री या जनरेट किए गए आउटपुट ट्री में उस फ़ाइल के मिलते-जुलते पाथ जैसा ही होता है. अगर किसी वजह से ये अलग-अलग हैं, तो आप 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_deviced अगर टारगेट के स्रोतों को इंस्ट्रुमेंट किया जाना चाहिए, तो कवरेज मोड में 'सही' दिखाता है:

# Are this rule's sources instrumented?
if ctx.coverage_instrumented():
  # Do something to turn on coverage for this compile action

लॉजिक जिसे हमेशा कवरेज मोड में चालू होना ज़रूरी है (खास तौर पर टारगेट के स्रोतों को खास तौर पर इस्तेमाल किया जाता है या नहीं) उन पर भी कार्रवाई की जा सकती है ctx.config.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 से"host" या"exec" एट्रिब्यूट स्कीमा में)dependency_attributes चुनें. (यह आदर्श व्यवहार नहीं है, क्योंकि इसमें विशेषताओं को पसंद किया जाता हैsrcs इंचdependency_attributes के बजायsource_attributes, लेकिन यह निर्भरता की शृंखला में मौजूद सभी नियमों के लिए कवरेज कवरेज कॉन्फ़िगरेशन की ज़रूरत से बचाता है.)

पुष्टि करने की कार्रवाइयां

कभी-कभी आपको बिल्ड के बारे में कुछ पुष्टि करनी पड़ती है और उस पुष्टि को करने के लिए ज़रूरी जानकारी सिर्फ़ आर्टफ़ैक्ट में उपलब्ध है (स्रोत फ़ाइलें या जनरेट की गई फ़ाइलें). यह जानकारी आर्टफ़ैक्ट में है, इसलिए विश्लेषण के समय नियम इसकी पुष्टि नहीं कर सकते, क्योंकि नियम फ़ाइलें नहीं पढ़ सकते. इसके बजाय, कार्रवाइयां पूरी करते समय यह पुष्टि करनी होगी. जब पुष्टि नहीं हो पाती है, तो यह कार्रवाई नहीं की जा सकेगी और इसलिए इसे बनाया जाएगा.

पुष्टि करने के लिए चलाए जाने वाले पुष्टि के उदाहरणों में स्थिर विश्लेषण, लिंटिंग, निर्भरता, और एक जैसा जांच, और शैली की जांच शामिल है.

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

इन "पुष्टि करने की कार्रवाइयों" में अक्सर ऐसा कुछ नहीं मिलता है, जिसका इस्तेमाल बिल्ड में कहीं और किया गया हो, क्योंकि उन्हें सिर्फ़ अपने इनपुट के बारे में जानकारी देनी होती है. हालांकि, इसमें समस्या के बारे में बताया गया है: अगर पुष्टि के लिए कोई ऐसी कार्रवाई नहीं की जाती है जिसका इस्तेमाल बिल्ड में कहीं और किया गया है, तो नियम कैसे काम करता है? पहले, यह तरीका था कि पुष्टि के लिए की जाने वाली कार्रवाई का आउटपुट एक खाली फ़ाइल हो. साथ ही, उस आउटपुट को आर्टिफ़िशियल तरीके से बिल्ड में कुछ दूसरी ज़रूरी कार्रवाई के इनपुट में जोड़ा जाए:

यह काम करता है, क्योंकि बज़ल कंपाइलेशन चलाने पर हमेशा पुष्टि की कार्रवाई करता है, लेकिन इसमें कमियां हैं:

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

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

इससे बचने के लिए, Files में मौजूद सुविधाएं चलाएं

ctx.runfiles और runfiles टाइप में कई सुविधाओं का एक कॉम्प्लेक्स होता है. इनमें से कई को विरासती वजहों से रखा जाता है. इन सुझावों से मुश्किल को कम करने में मदद मिलती है:

  • ctx.runfiles के collect_data और collect_default मोड का इस्तेमाल करने से बचें. ये मोड साफ़ तौर पर कुछ हार्डकोडेड डिपेंडेंसी किनारों से रनरन फ़ाइल इकट्ठा करते हैं. इसके बजाय, ctx.runfiles के files या transitive_files पैरामीटर का इस्तेमाल करके या runfiles = runfiles.merge(dep[DefaultInfo].default_runfiles) पर निर्भरता से रनफ़ाइल मर्ज करके फ़ाइलें जोड़ें.

  • DefaultInfo कंस्ट्रक्टर का data_runfiles और default_runfiles इस्तेमाल करने से बचें. इसके बजाय, DefaultInfo(runfiles = ...) की जानकारी दें. "डिफ़ॉल्ट" और "डेटा" रनफ़ाइल के बीच अंतर को विरासती वजहों से बनाए रखा जाता है. जैसे, कुछ नियमों के मुताबिक डिफ़ॉल्ट आउटपुट data_runfiles में होते हैं, लेकिन default_runfiles में नहीं. Google Ads data_runfiles, नियम को यह करना चाहिएदोनों डिफ़ॉल्ट आउटपुट शामिल करें और उन्हें मर्ज करें default_runfiles रनफ़ाइल देने वाली विशेषताओं से (अक्सर data ).

  • वापस लाते समयrunfiles मैसेज भेजने वाले लोगDefaultInfo आम तौर पर सिर्फ़ मौजूदा नियम और इसकी डिपेंडेंसी के बीच रनरनिंग फ़ाइलों को मर्ज करने के लिए), DefaultInfo.default_runfiles, नहीं DefaultInfo.data_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 प्रतीक से पास किया जाता है. माइग्रेट करते समय स्ट्रिंग से प्रतीक में आना न भूलें. ऐसे जटिल या बड़े नियम सेट के लिए जिनमें सभी नियम नियम के अनुसार अपडेट करना मुश्किल होता है, वहां पर आप यह तरीका अपनाकर देख सकते हैं:

  1. ऊपर दिए गए सिंटैक्स का इस्तेमाल करके, पुराने और पुराने, दोनों वर्शन बनाने वाले नियमों में बदलाव करें. ऐसे नियम जो यह बताते हैं कि वे पुराने वर्शन की सेवा देने वाली कंपनी के तौर पर वापस आते हैं, उसके लिए वह एलान अपडेट करें जिसमें पुरानी और आधुनिक, दोनों सेवाएं देने वाली कंपनियां शामिल हों.

  2. इसके बजाय, आधुनिक सेवा देने वाले के पुराने वर्शन का इस्तेमाल करने वाले नियमों में बदलाव करें. अगर किसी एट्रिब्यूट के एलान के लिए पुराने वर्शन की सेवा देने वाली कंपनी का होना ज़रूरी है, तो कृपया मौजूदा वर्शन को भी अपडेट करें. इसके अलावा, आप पहले चरण के साथ इस काम को बीच में छोड़ सकते हैं. इसके लिए, आपको उपभोक्ताओं में से किसी एक को स्वीकार करना होगा/इसके लिए ज़रूरी है: hasattr(target, 'foo') याFooInfo in target चुनें.

  3. लेगसी सेवा देने वाली कंपनी को सभी नियमों से पूरी तरह हटाएं.