लेगसी मैक्रो, बिना स्ट्रक्चर वाले फ़ंक्शन होते हैं. इन्हें BUILD
फ़ाइलों से कॉल किया जाता है. ये टारगेट बना सकते हैं. लोडिंग फ़ेज़ के खत्म होने तक, लेगसी मैक्रो मौजूद नहीं होते हैं. साथ ही, Bazel को सिर्फ़ इंस्टैंटिएट किए गए नियमों का सेट दिखता है.
विरासत में मिले मैक्रो का इस्तेमाल क्यों नहीं करना चाहिए और इसके बजाय सिंबॉलिक मैक्रो का इस्तेमाल क्यों करना चाहिए
जहां हो सके वहां सिंबॉलिक मैक्रो का इस्तेमाल करें.
सिम्बॉलिक मैक्रो
- दूर से कार्रवाई करने से रोकना
- विस्तृत जानकारी को छिपाने की सुविधा उपलब्ध कराता है
- टाइप किए गए एट्रिब्यूट का इस्तेमाल करें. इसका मतलब है कि लेबल अपने-आप लग जाएंगे और कन्वर्ज़न अपने-आप चुना जाएगा.
- उन्हें आसानी से पढ़ा जा सकता है
- इसमें जल्द ही लेज़ी इवैलुएशन की सुविधा उपलब्ध होगी
इस्तेमाल
मैक्रो का इस्तेमाल आम तौर पर तब किया जाता है, जब आपको किसी नियम का दोबारा इस्तेमाल करना हो.
उदाहरण के लिए, BUILD
फ़ाइल में मौजूद genrule, //:generator
का इस्तेमाल करके एक फ़ाइल जनरेट करता है. इसमें some_arg
आर्ग्युमेंट को कमांड में हार्डकोड किया जाता है:
genrule(
name = "file",
outs = ["file.txt"],
cmd = "$(location //:generator) some_arg > $@",
tools = ["//:generator"],
)
अगर आपको अलग-अलग आर्ग्युमेंट के साथ ज़्यादा फ़ाइलें जनरेट करनी हैं, तो इस कोड को मैक्रो फ़ंक्शन में एक्सट्रैक्ट करें. name
और arg
पैरामीटर वाले file_generator
नाम का मैक्रो बनाने के लिए, हम genrule को इससे बदल सकते हैं:
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",
)
यहां, file_generator
सिंबल को //path
पैकेज में मौजूद .bzl
फ़ाइल से लोड किया जाता है. मैक्रो फ़ंक्शन की परिभाषाओं को अलग .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,
)
नियमों को एक साथ जोड़ने के लिए, मैक्रो का भी इस्तेमाल किया जा सकता है. इस उदाहरण में चेन की गई genrule दिखाई गई हैं. इनमें एक genrule, पिछली genrule के आउटपुट को इनपुट के तौर पर इस्तेमाल करती है:
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,
)
इस उदाहरण में, सिर्फ़ दूसरे जनरूल को विज़िबिलिटी वैल्यू असाइन की गई है. इससे मैक्रो लिखने वाले लोग, इंटरमीडिएट नियमों के आउटपुट को छिपा सकते हैं, ताकि Workspace में मौजूद अन्य टारगेट उन पर निर्भर न रहें.
बड़ी होने वाली मैक्रो
अगर आपको यह जानना है कि कोई मैक्रो क्या करता है, तो query
कमांड के साथ --output=build
का इस्तेमाल करके, मैक्रो का पूरा कोड देखें:
$ 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
फ़ाइल मैक्रो को कॉल कर रही है), तो native.package_name() फ़ंक्शन का इस्तेमाल करें. ध्यान दें कि native
का इस्तेमाल सिर्फ़ .bzl
फ़ाइलों में किया जा सकता है, 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 repo, 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)'
BUILD
फ़ाइल मेंfoo
नियम कहां जनरेट होता है, यह जानने के लिए यह तरीका आज़माएं. इस लाइन कोBUILD
फ़ाइल में सबसे ऊपर डालें:cc_library(name = "foo")
. Bazel चलाएं. नियमfoo
बनाते समय, नाम के टकराव की वजह से आपको एक अपवाद मिलेगा. इससे आपको पूरा स्टैक ट्रेस दिखेगा.डीबग करने के लिए, print का भी इस्तेमाल किया जा सकता है. यह लोडिंग के दौरान, मैसेज को
DEBUG
लॉग लाइन के तौर पर दिखाता है. कुछ मामलों को छोड़कर,print
कॉल हटाएं या उन्हेंdebugging
पैरामीटर के तहत शर्त के साथ लागू करें. यह पैरामीटर, डिफ़ॉल्ट रूप सेFalse
पर सेट होता है. इसके बाद, कोड को डिपो में सबमिट करें.
गड़बड़ियां
अगर आपको कोई गड़बड़ी दिखानी है, तो fail फ़ंक्शन का इस्तेमाल करें. उपयोगकर्ता को साफ़ तौर पर बताएं कि क्या गड़बड़ी हुई है और 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
और genrulefoo_gen
जनरेट कर सकता है.ज़्यादातर मामलों में, जो पैरामीटर ज़रूरी नहीं हैं उनकी डिफ़ॉल्ट वैल्यू
None
होनी चाहिए.None
को सीधे तौर पर नेटिव नियमों में पास किया जा सकता है. इससे नेटिव नियमों को यह पता चलता है कि आपने कोई तर्क पास नहीं किया है. इसलिए, इस मकसद के लिए इसे0
,False
या[]
से बदलने की ज़रूरत नहीं है. इसके बजाय, मैक्रो को उन नियमों को लागू करना चाहिए जिन्हें वह बनाता है, क्योंकि उनके डिफ़ॉल्ट जटिल हो सकते हैं या समय के साथ बदल सकते हैं. इसके अलावा, क्वेरी लैंग्वेज या बिल्ड-सिस्टम इंटरनल के ज़रिए ऐक्सेस किए जाने पर, डिफ़ॉल्ट वैल्यू पर सेट किया गया पैरामीटर, कभी सेट न किए गए पैरामीटर (याNone
पर सेट किए गए पैरामीटर) से अलग दिखता है.मैक्रो में एक वैकल्पिक
visibility
आर्ग्युमेंट होना चाहिए.