मैक्रो

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

मैक्रो, 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
def _my_macro_impl(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 फ़ाइल में उसकी परिभाषा लोड करके और कॉल करके किया जाता है.


# 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() को कॉल कर सकता है. हालांकि, यह लेगसी मैक्रो की तुलना में थोड़ा अलग तरीके से काम करता है. यह सिर्फ़ फ़ाइनलाइज़र के अलावा अन्य नियमों के टारगेट का सेट दिखाता है. फ़ाइनलाइज़र, उस सेट की स्थिति की पुष्टि कर सकता है या नए टारगेट तय कर सकता है.

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

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 टाइप नहीं है.

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

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

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