इस पेज में मैक्रो इस्तेमाल करने की बुनियादी बातें बताई गई हैं. साथ ही, इसमें इस्तेमाल के सामान्य उदाहरण, डीबग करना, और कन्वेंशन शामिल हैं.
मैक्रो, BUILD
फ़ाइल से कॉल किया जाने वाला एक फ़ंक्शन है, जो नियमों को इंस्टैंशिएट करता है.
मैक्रो का इस्तेमाल मुख्य रूप से मौजूदा नियमों और अन्य मैक्रो को एनकैप्सुलेशन करने और कोड का दोबारा इस्तेमाल करने के लिए किया जाता है. लोडिंग फ़ेज़ खत्म होने तक, मैक्रो का इस्तेमाल नहीं किया जा सकता.
और बेज़ल को इंस्टैंशिएट किए गए नियमों के सिर्फ़ कंक्रीट सेट दिखते हैं.
इस्तेमाल का तरीका
आम तौर पर, मैक्रो का इस्तेमाल तब होता है, जब आपको किसी नियम का दोबारा इस्तेमाल करना हो.
उदाहरण के लिए, BUILD
फ़ाइल में genरूल, //: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
फ़ाइल
मैक्रो को कॉल कर रही है), तो Native.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
पैरामीटर में शर्तों के मुताबिक बनाएं. यह पैरामीटर डिपो में कोड सबमिट करने से पहलेFalse
तक आता है.
गड़बड़ियां
अगर आपको कोई गड़बड़ी करनी है, तो fall फ़ंक्शन का इस्तेमाल करें.
उपयोगकर्ता को साफ़ तौर पर बताएं कि क्या गड़बड़ी हुई है और उसकी BUILD
फ़ाइल को कैसे ठीक करें.
किसी गड़बड़ी का पता नहीं लगाया जा सकता.
def my_macro(name, deps, visibility=None):
if len(deps) < 2:
fail("Expected at least two values in deps")
# ...
सम्मेलन
नियमों को लागू करने वाले सभी सार्वजनिक फ़ंक्शन (अंडरस्कोर से शुरू नहीं होने वाले फ़ंक्शन) में
name
आर्ग्युमेंट होना ज़रूरी है. यह आर्ग्युमेंट वैकल्पिक नहीं होना चाहिए (कोई डिफ़ॉल्ट वैल्यू न दें).सार्वजनिक फ़ंक्शन को Python की कन्वेंशन का पालन करते हुए docstring का इस्तेमाल करना चाहिए.
BUILD
फ़ाइलों में, मैक्रो काname
आर्ग्युमेंट एक कीवर्ड आर्ग्युमेंट होना चाहिए (पोज़िशनल आर्ग्युमेंट नहीं).मैक्रो से जनरेट किए गए नियमों के
name
एट्रिब्यूट में, नाम का इस्तेमाल प्रीफ़िक्स के तौर पर किया जाना चाहिए. उदाहरण के लिए,macro(name = "foo")
एकcc_library
foo
और एक संग नियमfoo_gen
जनरेट कर सकता है.ज़्यादातर मामलों में, वैकल्पिक पैरामीटर की डिफ़ॉल्ट वैल्यू
None
होनी चाहिए.None
को सीधे नेटिव नियमों पर भेजा जा सकता है. ये ऐसे ही होंगे जैसे आपने किसी आर्ग्युमेंट में पास नहीं किए हैं. इसलिए, इसे बदलने के लिए आपको0
,False
या[]
को बदलने की ज़रूरत नहीं है. इसके बजाय, मैक्रो को उसके बनाए गए नियमों का पालन करना चाहिए, क्योंकि उनके डिफ़ॉल्ट जटिल हो सकते हैं या समय के साथ बदल सकते हैं. इसके अलावा, किसी पैरामीटर को खास तौर पर उसकी डिफ़ॉल्ट वैल्यू पर सेट करने पर, वह क्वेरी लैंग्वेज या बिल्ड-सिस्टम के अंदरूनी डेटा को ऐक्सेस करने पर सेट नहीं किए गए पैरामीटर से अलग दिखता है (याNone
पर सेट होता है).मैक्रो में एक वैकल्पिक
visibility
आर्ग्युमेंट होना चाहिए.