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