BazelCon 2022, 16 नवंबर से 17 नवंबर तक न्यूयॉर्क में और ऑनलाइन उपलब्ध है.
आज ही रजिस्टर करें!

मैक्रो

संग्रह की मदद से व्यवस्थित रहें अपनी प्राथमिकताओं के आधार पर, कॉन्टेंट को सेव करें और कैटगरी में बांटें.

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

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

इस्तेमाल का तरीका

आम तौर पर, किसी नियम को दोबारा इस्तेमाल करने के लिए मैक्रो का इस्तेमाल किया जाता है.

उदाहरण के लिए, BUILD फ़ाइल में genrule, //:generator का इस्तेमाल करके फ़ाइल जनरेट करता है, जिसमें निर्देश में some_arg आर्ग्युमेंट हार्डकोड होते हैं:

genrule(
    name = "file",
    outs = ["file.txt"],
    cmd = "$(location //:generator) some_arg > $@",
    tools = ["//:generator"],
)

अगर आप अलग-अलग तर्कों के साथ ज़्यादा फ़ाइलें जनरेट करना चाहते हैं, तो आप इस कोड को मैक्रो फ़ंक्शन से निकालना चाहें. मान लें कि # और मैक्रो file_generator है, जिसमें name और arg पैरामीटर हैं. जनरेट करें को निम्न से बदलें:

load("//path:generator.bzl", "file_generator")

file_generator(
    name = "file",
    arg = "some_arg",
)

file_generator(
    name = "file-two",
    arg = "some_arg_two",
)

file_generator(
    name = "file-three",
    arg = "some_arg_three",
)

यहां, आप //path पैकेज में मौजूद .bzl फ़ाइल से file_generator सिंबल लोड करते हैं. मैक्रो फ़ंक्शन की परिभाषाओं को एक अलग .bzl फ़ाइल में रखने पर, आपकी BUILD फ़ाइलें साफ़ और एलान की जा सकती हैं. फ़ाइल फ़ोल्डर में, .bzl फ़ाइल को किसी भी पैकेज से लोड किया जा सकता है.

आखिर में, path/generator.bzl में मूल genrule की परिभाषा को कैप्चर और पैरामीटर करने के लिए मैक्रो की परिभाषा लिखें.

def file_generator(name, arg, visibility=None):
  native.genrule(
    name = name,
    outs = [name + ".txt"],
    cmd = "$(location //:generator) %s > $@" % arg,
    tools = ["//:generator"],
    visibility = visibility,
  )

आप कई नियमों को एक साथ लागू करने के लिए भी मैक्रो का इस्तेमाल कर सकते हैं. यह उदाहरण, चेन किए गए जनरल रूल दिखाता है. यहां एक जेनरूल, पिछले जेनरूल के आउटपुट का इस्तेमाल इनपुट के तौर पर करता है:

def chained_genrules(name, visibility=None):
  native.genrule(
    name = name + "-one",
    outs = [name + ".one"],
    cmd = "$(location :tool-one) $@",
    tools = [":tool-one"],
    visibility = ["//visibility:private"],
  )

  native.genrule(
    name = name + "-two",
    srcs = [name + ".one"],
    outs = [name + ".two"],
    cmd = "$(location :tool-two) $< $@",
    tools = [":tool-two"],
    visibility = visibility,
  )

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

मैक्रोज़ को बड़ा करना

जब आप जांच करना चाहते हैं कि मैक्रो क्या करता है, तो बड़ा किया गया फ़ॉर्म देखने के लिए --output=build के साथ query निर्देश का इस्तेमाल करें:

$ bazel query --output=build :file
# /absolute/path/test/ext.bzl:42:3
genrule(
  name = "file",
  tools = ["//:generator"],
  outs = ["//test:file.txt"],
  cmd = "$(location //:generator) some_arg > $@",
)

नेटिव नियमों को लागू करना

नेटिव नियमों (ऐसे नियम जिन्हें load() स्टेटमेंट की ज़रूरत नहीं होती) को नेटिव मॉड्यूल से इंस्टैंशिएट किया जा सकता है:

def my_macro(name, visibility=None):
  native.cc_library(
    name = name,
    srcs = ["main.cc"],
    visibility = visibility,
  )

अगर आपको पैकेज का नाम जानना है (उदाहरण के लिए, BUILD फ़ाइल, मैक्रो को कॉल कर रही है या नहीं), तो फ़ंक्शन नेटिव.package_name() का इस्तेमाल करें. ध्यान दें कि native का इस्तेमाल सिर्फ़ .bzl फ़ाइलों में किया जा सकता है, WORKSPACE या BUILD फ़ाइलों में नहीं.

मैक्रो में लेबल का रिज़ॉल्यूशन

मैक्रो का आकलन लोड होने के चरण के बाद किया जाता है. इसलिए, मैक्रो में होने वाली "//foo:bar" जैसी लेबल स्ट्रिंग को BUILD फ़ाइल के हिसाब से समझा जाता है. इसमें, .bzl फ़ाइल के मुकाबले मैक्रो का इस्तेमाल किया जाता है, जिसमें इसे तय किया जाता है. आम तौर पर, ये व्यवहार उन मैक्रो के लिए अनचाहे होते हैं जिन्हें दूसरे रिपॉज़िटरी (डेटा स्टोर की जगह) में इस्तेमाल किया जाता है. उदाहरण के लिए, वे पब्लिश किए गए Starlark नियम का हिस्सा होते हैं.

Starlark के नियमों की तरह ही काम करने के लिए, लेबल स्ट्रिंग को Label कंस्ट्रक्टर से रैप करें:

# @my_ruleset//rules:defs.bzl
def my_cc_wrapper(name, deps = [], **kwargs):
  native.cc_library(
    name = name,
    deps = deps + select({
      # Due to the use of Label, this label is resolved within @my_ruleset,
      # regardless of its site of use.
      Label("//config:needs_foo"): [
        # Due to the use of Label, this label will resolve to the correct target
        # even if the canonical name of @dep_of_my_ruleset should be different
        # in the main workspace, such as due to repo mappings.
        Label("@dep_of_my_ruleset//tools:foo"),
      ],
      "//conditions:default": [],
    }),
    **kwargs,
  )

डीबग करना

  • bazel query --output=build //my/path:all आपको दिखाएगा कि BUILD फ़ाइल, इवैलुएशन के बाद कैसी दिखती है. सभी मैक्रो, ग्लोब, लूप को बढ़ाया जाता है. जानी-पहचानी सीमा: फ़िलहाल, select एक्सप्रेशन आउटपुट में नहीं दिखाए जाते हैं.

  • आउटपुट को generator_function (जो फ़ंक्शन नियम जनरेट करते हैं) या generator_name (मैक्रो का नाम एट्रिब्यूट) के हिसाब से फ़िल्टर किया जा सकता है: bash $ bazel query --output=build 'attr(generator_function, my_macro, //my/path:all)'

  • यह पता लगाने के लिए कि foo नियम, BUILD फ़ाइल में कहां जनरेट होता है, आप यह तरीका आज़मा सकते हैं. BUILD फ़ाइल के ऊपरी हिस्से के पास यह लाइन डालें: cc_library(name = "foo"). Bazel चलाएं. foo नियम बनाने के बाद, आपको नाम से जुड़ी गड़बड़ी की वजह से अपवाद का पता चलेगा. इससे, आपको पूरा स्टैक ट्रेस दिखेगा.

  • आप डीबग करने के लिए प्रिंट का भी इस्तेमाल कर सकते हैं. यह मैसेज, लोड होने के दौरान DEBUG लॉग लाइन के तौर पर दिखाता है. बहुत कम मामलों में, print कॉल हटाएं या डिपो में कोड सबमिट करने से पहले, debugging पैरामीटर में कंडीशनल बनाएं.

गड़बड़ियां

अगर आपको कोई गड़बड़ी करनी है, तो फ़ेल फ़ंक्शन का इस्तेमाल करें. उपयोगकर्ता को साफ़ तौर पर बताएं कि उन्हें क्या गड़बड़ी मिली. साथ ही, उनकी BUILD फ़ाइल को ठीक करने का तरीका भी बताएं. गड़बड़ी का पता नहीं लगाया जा सकता.

def my_macro(name, deps, visibility=None):
  if len(deps) < 2:
    fail("Expected at least two values in deps")
  # ...

सम्मेलन

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

  • सार्वजनिक फ़ंक्शन को Python कन्वेंशन के बाद आने वाली डॉकस्ट्रिंग का इस्तेमाल करना चाहिए.

  • BUILD फ़ाइलों में, मैक्रो का name आर्ग्युमेंट एक कीवर्ड आर्ग्युमेंट होना चाहिए (कोई पोज़िशनल आर्ग्युमेंट नहीं).

  • मैक्रो से जनरेट किए गए नियमों के name एट्रिब्यूट में, नाम का नाम प्रीफ़िक्स के तौर पर शामिल होना चाहिए. उदाहरण के लिए, macro(name = "foo") एक cc_library foo और सामान्य नियम foo_gen जनरेट कर सकता है.

  • ज़्यादातर मामलों में, वैकल्पिक पैरामीटर की डिफ़ॉल्ट वैल्यू None होनी चाहिए. None को सीधे नेटिव नियमों पर पास किया जा सकता है. इसे ऐसे ही लागू किया जा सकता है जैसे आप किसी आर्ग्युमेंट में पास नहीं हुए हैं. इसलिए, इसे बदलने के लिए इसे 0, False या [] से बदलने की ज़रूरत नहीं है. इसके बजाय, मैक्रो को बनाए गए नियमों का पालन करना चाहिए, क्योंकि उनके डिफ़ॉल्ट मुश्किल हो सकते हैं या समय के साथ बदल सकते हैं. इसके अलावा, जब पैरामीटर डिफ़ॉल्ट रूप से अपनी डिफ़ॉल्ट वैल्यू पर सेट होता है, तो वह क्वेरी लैंग्वेज या बिल्ड-सिस्टम के अंदरूनी ऐक्सेस से ऐक्सेस किए जाने पर पहले से सेट (या None पर सेट) किए गए पैरामीटर से अलग दिखता है.

  • मैक्रो में एक वैकल्पिक visibility तर्क होना चाहिए.