लेगसी मैक्रो, 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
फ़ाइल को वर्कस्पेस के किसी भी पैकेज से लोड किया जा सकता है.
आखिर में, 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,
)
इस उदाहरण में, सिर्फ़ दूसरे जनरेटिव नियम के लिए, दिखने की वैल्यू असाइन की गई है. इससे मैक्रो बनाने वाले, इंटरमीडिएट नियमों के आउटपुट को छिपा सकते हैं, ताकि 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
आर्ग्युमेंट होना चाहिए. हालांकि, यह ज़रूरी नहीं है.