मैक्रो

इस पेज पर, मैक्रो इस्तेमाल करने की बुनियादी जानकारी दी गई है. इसमें, मैक्रो इस्तेमाल करने के सामान्य उदाहरण, डीबग करने की जानकारी, और इस्तेमाल से जुड़े नियम शामिल हैं.

मैक्रो, BUILD फ़ाइल से कॉल किया जाने वाला एक फ़ंक्शन है. इसकी मदद से, नियमों को इंस्टैंशिएट किया जा सकता है. मैक्रो का इस्तेमाल मुख्य रूप से, मौजूदा नियमों और अन्य मैक्रो को एनकैप्सुलेट करने और कोड को फिर से इस्तेमाल करने के लिए किया जाता है.

मैक्रो दो तरह के होते हैं: सिंबॉलिक मैक्रो, जिनके बारे में इस पेज पर बताया गया है, और लेगसी मैक्रो. हमारा सुझाव है कि कोड को साफ़ तौर पर दिखाने के लिए, सिंबॉलिक मैक्रो का इस्तेमाल करें.

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

सिंबॉलिक मैक्रो का कोई ऐसा उदाहरण जिसे चलाया जा सके, उदाहरणों के रिपॉज़िटरी में देखा जा सकता है.

इस्तेमाल

मैक्रो को .bzl फ़ाइलों में macro() फ़ंक्शन को दो ज़रूरी पैरामीटर के साथ कॉल करके तय किया जाता है: attrs और implementation.

एट्रिब्यूट

attrs एट्रिब्यूट के टाइप के हिसाब से एट्रिब्यूट के नाम की डिक्शनरी स्वीकार करता है. यह डिक्शनरी, मैक्रो के आर्ग्युमेंट को दिखाती है. दो सामान्य एट्रिब्यूट – name और visibility – सभी मैक्रो में अपने-आप जुड़ जाते हैं. इन्हें attrs को पास की गई डिक्शनरी में शामिल नहीं किया जाता.

# macro/macro.bzl
my_macro = macro(
    attrs = {
        "deps": attr.label_list(mandatory = True, doc = "The dependencies passed to the inner cc_binary and cc_test targets"),
        "create_test": attr.bool(default = False, configurable = False, doc = "If true, creates a test target"),
    },
    implementation = _my_macro_impl,
)

एट्रिब्यूट के टाइप के एलान में, पैरामीटर, mandatory, default, और doc स्वीकार किए जाते हैं. ज़्यादातर एट्रिब्यूट टाइप, configurable पैरामीटर भी स्वीकार करते हैं. इससे यह तय होता है कि एट्रिब्यूट, select को स्वीकार करता है या नहीं. अगर कोई एट्रिब्यूट configurable है, तो वह गैर-select वैल्यू को अनकॉन्फ़िगर किए गए select के तौर पर पार्स करेगा – "foo" बन जाएगा select({"//conditions:default": "foo"}). selects के बारे में ज़्यादा जानें.

एट्रिब्यूट इनहेरिटेंस

मैक्रो का इस्तेमाल अक्सर किसी नियम (या किसी अन्य मैक्रो) को रैप करने के लिए किया जाता है. साथ ही, मैक्रो का लेखक अक्सर रैप किए गए सिंबल के ज़्यादातर एट्रिब्यूट को, **kwargs का इस्तेमाल करके, मैक्रो के मुख्य टारगेट (या मुख्य इनर मैक्रो) को बिना किसी बदलाव के फ़ॉरवर्ड करना चाहता है.

इस पैटर्न के लिए, कोई मैक्रो, नियम या किसी अन्य मैक्रो से एट्रिब्यूट इनहेरिट कर सकता है. इसके लिए, नियम या मैक्रो सिंबल को macro()'s inherit_attrs आर्ग्युमेंट में पास किया जाता है. (Starlark के सभी बिल्ड नियमों के लिए तय किए गए सामान्य एट्रिब्यूट को इनहेरिट करने के लिए, नियम या मैक्रो सिंबल के बजाय, खास स्ट्रिंग "common" `"common"` का भी इस्तेमाल किया जा सकता है.) सिर्फ़ सार्वजनिक एट्रिब्यूट इनहेरिट किए जाते हैं. साथ ही, मैक्रो की अपनी attrs डिक्शनरी में मौजूद एट्रिब्यूट, एक ही नाम वाले इनहेरिट किए गए एट्रिब्यूट को ओवरराइड करते हैं. attrs डिक्शनरी में, None को वैल्यू के तौर पर इस्तेमाल करके, इनहेरिट किए गए एट्रिब्यूट को हटाया भी जा सकता है:

# macro/macro.bzl
my_macro = macro(
    inherit_attrs = native.cc_library,
    attrs = {
        # override native.cc_library's `local_defines` attribute
        "local_defines": attr.string_list(default = ["FOO"]),
        # do not inherit native.cc_library's `defines` attribute
        "defines": None,
    },
    ...
)

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

# macro/macro.bzl
_my_macro_implementation(name, visibility, tags, **kwargs):
    # Append a tag; tags attr is an inherited non-mandatory attribute, and
    # therefore is None unless explicitly set by the caller of our macro.
    my_tags = (tags or []) + ["another_tag"]
    native.cc_library(
        ...
        tags = my_tags,
        **kwargs,
    )
    ...

लागू करना

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

नियम लागू करने वाले फ़ंक्शन के उलट, मैक्रो लागू करने वाले फ़ंक्शन, हर आर्ग्युमेंट के लिए एक पैरामीटर स्वीकार करते हैं. नियम लागू करने वाले फ़ंक्शन, सिर्फ़ एक आर्ग्युमेंट (ctx) स्वीकार करते हैं. इसमें एट्रिब्यूट का रेफ़रंस होता है.

# macro/macro.bzl
def _my_macro_impl(name, visibility, deps, create_test):
    cc_library(
        name = name + "_cc_lib",
        deps = deps,
    )

    if create_test:
        cc_test(
            name = name + "_test",
            srcs = ["my_test.cc"],
            deps = deps,
        )

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

एलान

मैक्रो का एलान, BUILD फ़ाइल में उसकी परिभाषा लोड करके और कॉल करके किया जाता है. ```starlark

pkg/BUILD

my_macro( name = "macro_instance", deps = ["src.cc"] + select( { "//config_setting:special": ["special_source.cc"], "//conditions:default": [], }, ), create_tests = True, ) ```

इससे //pkg:macro_instance_cc_lib और//pkg:macro_instance_test टारगेट बनेंगे.

नियमों को कॉल करने की तरह, अगर किसी मैक्रो कॉल में किसी एट्रिब्यूट की वैल्यू None पर सेट की जाती है, तो उस एट्रिब्यूट को ऐसा माना जाता है जैसे कि उसे मैक्रो के कॉलर ने छोड़ दिया हो. उदाहरण के लिए, ये दो मैक्रो कॉल एक जैसे हैं:

# pkg/BUILD
my_macro(name = "abc", srcs = ["src.cc"], deps = None)
my_macro(name = "abc", srcs = ["src.cc"])

यह आम तौर पर BUILD फ़ाइलों में काम का नहीं होता. हालांकि, प्रोग्राम के ज़रिए किसी मैक्रो को किसी दूसरे मैक्रो में रैप करते समय यह काम का होता है.

विवरण

बनाए गए टारगेट के लिए नाम रखने के नियम

सिंबॉलिक मैक्रो से बनाए गए किसी भी टारगेट या सबमैक्रो के नाम, मैक्रो के name पैरामीटर से मेल खाने चाहिए. इसके अलावा, उनके नाम की शुरुआत में name के बाद _ (सुझाया गया), . या - होना चाहिए. उदाहरण के लिए, my_macro(name = "foo") से सिर्फ़ foo नाम की फ़ाइलें या टारगेट बनाए जा सकते हैं. इसके अलावा, इनके नाम की शुरुआत में foo_, foo- या foo. होना चाहिए. जैसे, foo_bar.

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

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

पाबंदियां

लेगसी मैक्रो की तुलना में, सिंबॉलिक मैक्रो पर कुछ अतिरिक्त पाबंदियां होती हैं.

सिंबॉलिक मैक्रो

  • में name आर्ग्युमेंट और visibility आर्ग्युमेंट होना ज़रूरी है
  • में implementation फ़ंक्शन होना ज़रूरी है
  • वैल्यू नहीं लौटा सकते
  • अपने आर्ग्युमेंट में बदलाव नहीं कर सकते
  • native.existing_rules() को कॉल नहीं कर सकते. हालांकि, खास finalizer मैक्रो ऐसा कर सकते हैं
  • native.package() को कॉल नहीं कर सकते
  • glob() को कॉल नहीं कर सकते
  • native.environment_group() को कॉल नहीं कर सकते
  • ऐसे टारगेट बनाने होंगे जिनके नाम, नाम रखने के नियम के मुताबिक हों
  • इनपुट फ़ाइलों का रेफ़रंस नहीं ले सकते. ये फ़ाइलें, आर्ग्युमेंट के तौर पर पास नहीं की गई हैं या जिनका एलान नहीं किया गया है
  • अपने कॉलर के निजी टारगेट का रेफ़रंस नहीं ले सकते. ज़्यादा जानकारी के लिए, विज़िबिलिटी और मैक्रो देखें.

विज़िबिलिटी और मैक्रो

विज़िबिलिटी सिस्टम, (सिंबॉलिक) मैक्रो और उनके कॉलर, दोनों की लागू करने से जुड़ी जानकारी को सुरक्षित रखने में मदद करता है.

डिफ़ॉल्ट रूप से, सिंबॉलिक मैक्रो में बनाए गए टारगेट, मैक्रो में ही दिखते हैं. हालांकि, यह ज़रूरी नहीं है कि वे मैक्रो के कॉलर को भी दिखें. मैक्रो, किसी टारगेट को सार्वजनिक एपीआई के तौर पर "एक्सपोर्ट" कर सकता है. इसके लिए, वह अपने visibilityएट्रिब्यूट की वैल्यू को फ़ॉरवर्ड करता है. जैसे, some_rule(..., visibility = visibility).

मैक्रो की विज़िबिलिटी से जुड़े मुख्य आइडिया यहां दिए गए हैं:

  1. विज़िबिलिटी की जांच, इस आधार पर की जाती है कि टारगेट का एलान किस मैक्रो ने किया है. इस आधार पर नहीं कि मैक्रो को किस पैकेज ने कॉल किया है.

    • दूसरे शब्दों में, एक ही पैकेज में होने से, एक टारगेट दूसरे को नहीं दिखता. इससे मैक्रो के इंटरनल टारगेट, पैकेज में मौजूद अन्य मैक्रो या टॉप-लेवल टारगेट की डिपेंडेंसी नहीं बनते.
  2. नियमों और मैक्रो, दोनों पर मौजूद सभी visibility एट्रिब्यूट में, उस जगह की जानकारी अपने-आप शामिल हो जाती है जहां नियम या मैक्रो को कॉल किया गया था.

    • इसलिए, कोई टारगेट, उसी मैक्रो (या BUILD फ़ाइल, अगर वह मैक्रो में नहीं है) में एलान किए गए अन्य टारगेट को बिना किसी शर्त के दिखता है.

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

# tool/BUILD
...
some_rule(
    name = "some_tool",
    visibility = ["//macro:__pkg__"],
)
# macro/macro.bzl

def _impl(name, visibility):
    cc_library(
        name = name + "_helper",
        ...
        # No visibility passed in. Same as passing `visibility = None` or
        # `visibility = ["//visibility:private"]`. Visible to the //macro
        # package only.
    )
    cc_binary(
        name = name + "_exported",
        deps = [
            # Allowed because we're also in //macro. (Targets in any other
            # instance of this macro, or any other macro in //macro, can see it
            # too.)
            name + "_helper",
            # Allowed by some_tool's visibility, regardless of what BUILD file
            # we're called from.
            "//tool:some_tool",
        ],
        ...
        visibility = visibility,
    )

my_macro = macro(implementation = _impl, ...)
# pkg/BUILD
load("//macro:macro.bzl", "my_macro")
...

my_macro(
    name = "foo",
    ...
)

some_rule(
    ...
    deps = [
        # Allowed, its visibility is ["//pkg:__pkg__", "//macro:__pkg__"].
        ":foo_exported",
        # Disallowed, its visibility is ["//macro:__pkg__"] and
        # we are not in //macro.
        ":foo_helper",
    ]
)

अगर my_macro को visibility = ["//other_pkg:__pkg__"] के साथ कॉल किया जाता है या अगर //pkg पैकेज ने अपनी default_visibility को उस वैल्यू पर सेट किया है, तो //pkg:foo_exported का इस्तेमाल //other_pkg/BUILD में या //other_pkg:defs.bzl में तय किए गए किसी मैक्रो में भी किया जा सकता है. हालांकि, //pkg:foo_helper सुरक्षित रहेगा.

कोई मैक्रो, एलान कर सकता है कि कोई टारगेट, फ़्रेंड पैकेज को दिखे. इसके लिए, वह visibility = ["//some_friend:__pkg__"] (इंटरनल टारगेट के लिए) या visibility = visibility + ["//some_friend:__pkg__"] (एक्सपोर्ट किए गए टारगेट के लिए) पास कर सकता है. ध्यान दें कि किसी मैक्रो के लिए, सार्वजनिक विज़िबिलिटी (visibility = ["//visibility:public"]) के साथ किसी टारगेट का एलान करना, एक एंटीपैटर्न है. ऐसा इसलिए, क्योंकि इससे टारगेट, हर पैकेज को बिना किसी शर्त के दिखता है. भले ही, कॉलर ने ज़्यादा सीमित विज़िबिलिटी तय की हो.

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

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

फ़ाइनलाइज़र और विज़िबिलिटी

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

इसका मतलब है कि अगर native.existing_rules() पर आधारित किसी लेगसी मैक्रो को फ़ाइनलाइज़र में माइग्रेट किया जाता है, तो फ़ाइनलाइज़र से एलान किए गए टारगेट, अपनी पुरानी डिपेंडेंसी को अब भी देख पाएंगे.

हालांकि, ध्यान दें कि सिंबॉलिक मैक्रो में किसी टारगेट का एलान इस तरह से किया जा सकता है कि फ़ाइनलाइज़र के टारगेट, विज़िबिलिटी सिस्टम के तहत उसे न देख पाएं. भले ही, फ़ाइनलाइज़र, native.existing_rules() का इस्तेमाल करके, उसके एट्रिब्यूट को इंट्रोस्पेक्ट कर सकता है.

Selects

अगर कोई एट्रिब्यूट configurable है (डिफ़ॉल्ट रूप से) और उसकी वैल्यू None नहीं है, तो मैक्रो लागू करने वाला फ़ंक्शन, एट्रिब्यूट की वैल्यू को एक सामान्य select में रैप करके देखेगा. इससे मैक्रो के लेखक को उन गड़बड़ियों को पकड़ने में आसानी होती है जहां उन्हें यह उम्मीद नहीं थी कि एट्रिब्यूट की वैल्यू select हो सकती है.

उदाहरण के लिए, इस मैक्रो पर ध्यान दें:

my_macro = macro(
    attrs = {"deps": attr.label_list()},  # configurable unless specified otherwise
    implementation = _my_macro_impl,
)

अगर my_macro को deps = ["//a"] के साथ कॉल किया जाता है, तो _my_macro_impl को उसके deps पैरामीटर को select({"//conditions:default": ["//a"]}) पर सेट करके कॉल किया जाएगा. अगर इससे लागू करने वाला फ़ंक्शन काम नहीं करता है (उदाहरण के लिए, क्योंकि कोड ने वैल्यू को deps[0] के तौर पर इंडेक्स करने की कोशिश की, जिसकी अनुमति select के लिए नहीं है), तो मैक्रो का लेखक इनमें से कोई एक विकल्प चुन सकता है: या तो वह अपने मैक्रो को फिर से लिखकर, सिर्फ़ select के साथ काम करने वाले ऑपरेशन का इस्तेमाल कर सकता है या वह एट्रिब्यूट को नॉन-कॉन्फ़िगर करने लायक मार्क कर सकता है (attr.label_list(configurable = False)). दूसरे विकल्प से यह पक्का होता है कि उपयोगकर्ताओं को select वैल्यू पास करने की अनुमति नहीं है.

नियम टारगेट, इस बदलाव को उलट देते हैं. साथ ही, सामान्य select को अपनी बिना शर्त वाली वैल्यू के तौर पर सेव करते हैं. ऊपर दिए गए उदाहरण में, अगर _my_macro_impl नियम टारगेट my_rule(..., deps = deps) का एलान करता है, तो उस नियम टारगेट के deps को ["//a"] के तौर पर सेव किया जाएगा. इससे यह पक्का होता है कि select-रैपिंग की वजह से, मैक्रो से इंस्टैंशिएट किए गए सभी टारगेट में, सामान्य select वैल्यू सेव नहीं होती हैं.

अगर कॉन्फ़िगर करने लायक एट्रिब्यूट की वैल्यू None है, तो उसे select में रैप नहीं किया जाता. इससे यह पक्का होता है कि my_attr == None जैसे टेस्ट अब भी काम करते हैं. साथ ही, जब एट्रिब्यूट को कंप्यूट की गई डिफ़ॉल्ट वैल्यू वाले किसी नियम में फ़ॉरवर्ड किया जाता है, तो नियम सही तरीके से काम करता है. इसका मतलब है कि ऐसा माना जाता है कि एट्रिब्यूट को पास नहीं किया गया है. यह ज़रूरी नहीं है कि किसी एट्रिब्यूट की वैल्यू हमेशा None हो. हालांकि, attr.label() टाइप और इनहेरिट किए गए किसी भी ऐसे एट्रिब्यूट के लिए ऐसा हो सकता है जो ज़रूरी नहीं है.

फ़ाइनलाइज़र

नियम फ़ाइनलाइज़र, एक खास सिंबॉलिक मैक्रो होता है. इसे BUILD फ़ाइल में इसकी जगह के हिसाब से नहीं, बल्कि पैकेज लोड होने के आखिरी चरण में, सभी नॉन-फ़ाइनलाइज़र टारगेट तय होने के बाद, इवैल्युएट किया जाता है. सामान्य सिंबॉलिक मैक्रो के उलट, फ़ाइनलाइज़र, native.existing_rules() को कॉल कर सकता है. इसमें यह लेगसी मैक्रो की तुलना में थोड़ा अलग तरीके से काम करता है: यह सिर्फ़ नॉन-फ़ाइनलाइज़र नियम टारगेट का सेट लौटाता है. फ़ाइनलाइज़र, उस सेट की स्थिति पर दावा कर सकता है या नए टारगेट तय कर सकता है.

फ़ाइनलाइज़र का एलान करने के लिए, macro() को finalizer = True के साथ कॉल करें:

def _my_finalizer_impl(name, visibility, tags_filter):
    for r in native.existing_rules().values():
        for tag in r.get("tags", []):
            if tag in tags_filter:
                my_test(
                    name = name + "_" + r["name"] + "_finalizer_test",
                    deps = [r["name"]],
                    data = r["srcs"],
                    ...
                )
                continue

my_finalizer = macro(
    attrs = {"tags_filter": attr.string_list(configurable = False)},
    implementation = _impl,
    finalizer = True,
)

Laziness

अहम जानकारी: हम लेज़ी मैक्रो एक्सपैंशन और इवैल्युएशन को लागू करने की प्रोसेस में हैं. फ़िलहाल, आपके लिए यह सुविधा उपलब्ध नहीं है.

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

माइग्रेशन से जुड़ी समस्या हल करना

यहां माइग्रेशन से जुड़ी कुछ सामान्य समस्याएं और उन्हें ठीक करने का तरीका बताया गया है.

  • लेगसी मैक्रो कॉल glob()

glob() कॉल को अपनी BUILD फ़ाइल में ले जाएं. इसके अलावा, इसे BUILD फ़ाइल से कॉल किए गए किसी लेगसी मैक्रो में ले जाएं. साथ ही, लेबल-लिस्ट एट्रिब्यूट का इस्तेमाल करके, glob() वैल्यू को सिंबॉलिक मैक्रो में पास करें:

# BUILD file
my_macro(
    ...,
    deps = glob(...),
)
  • लेगसी मैक्रो में एक ऐसा पैरामीटर है जो मान्य starlark attr टाइप नहीं है.

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

  • लेगसी मैक्रो, किसी ऐसे नियम को कॉल करता है जिससे ऐसा टारगेट बनता है जो नाम रखने के नियम का उल्लंघन करता है

कोई बात नहीं, बस "समस्या वाले" टारगेट पर निर्भर न रहें. नाम की जांच को चुपचाप अनदेखा कर दिया जाएगा.