इस पेज पर लक्ष्यों के इस्तेमाल की बुनियादी बातों और फ़ायदों के बारे में बताया गया है. साथ ही, इसमें आसान और बेहतर उदाहरण भी दिए गए हैं.
आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) वाले ग्राफ़ की मदद से, ज़्यादा जानकारी और कार्रवाइयों के साथ-साथ, डिपेंडेंसी ग्राफ़ को बेहतर बनाया जा सकता है. कुछ सामान्य परिस्थितियां, जब पहलू काम के हो सकते हैं:
- Bazel को इंटिग्रेट करने वाले आईडीई, प्रोजेक्ट के बारे में जानकारी इकट्ठा करने के लिए पहलुओं का इस्तेमाल कर सकते हैं.
- कोड जनरेट करने वाले टूल, अपने इनपुट पर काम करने के लिए अलग-अलग पहलुओं का इस्तेमाल
टारगेट-ऐग्नोस्टिक तरीके से कर सकते हैं. उदाहरण के तौर पर,
BUILD
फ़ाइलें प्रोटोबफ़ लाइब्रेरी की परिभाषाओं की हैरारकी तय कर सकती हैं. किसी खास भाषा के नियम, किसी खास भाषा के लिए प्रोटोबफ़ सहायता कोड जनरेट करने वाली कार्रवाइयों को अटैच करने के लिए, खास पहलुओं का इस्तेमाल कर सकते हैं.
आसपेक्ट से जुड़ी बुनियादी बातें
BUILD
फ़ाइलें, प्रोजेक्ट के सोर्स कोड की जानकारी देती हैं: कौनसी सोर्स फ़ाइलें प्रोजेक्ट का हिस्सा हैं, उन फ़ाइलों से कौनसे आर्टफ़ैक्ट (टारगेट) बनाए जाने चाहिए, उन फ़ाइलों के बीच क्या-क्या निर्भरता है वगैरह. Bazel, टारगेट के बीच डिपेंडेंसी ग्राफ़ बनाकर और उन कार्रवाइयों को इकट्ठा करने के लिए इस ग्राफ़ पर जाकर ऐसा करता है.
यह BUILD
फ़ाइल देखें:
java_library(name = 'W', ...)
java_library(name = 'Y', deps = [':W'], ...)
java_library(name = 'Z', deps = [':W'], ...)
java_library(name = 'Q', ...)
java_library(name = 'T', deps = [':Q'], ...)
java_library(name = 'X', deps = [':Y',':Z'], runtime_deps = [':T'], ...)
यह BUILD
फ़ाइल, डिपेंडेंसी ग्राफ़ के बारे में जानकारी देती है. यह ग्राफ़ इस इमेज में दिखाया गया है:
पहला डायग्राम. BUILD
फ़ाइल डिपेंडेंसी ग्राफ़.
Bazel, ऊपर दिए गए उदाहरण में दिए गए हर टारगेट के लिए,
इस डिपेंडेंसी ग्राफ़ का विश्लेषण करता है. इसके लिए, वह
इससे जुड़े नियम (इस मामले में, "java_library") के लागू करने वाले फ़ंक्शन को कॉल करता है. नियम लागू करने वाले फ़ंक्शन, ऐसी कार्रवाइयां जनरेट करते हैं जो .jar
फ़ाइलों जैसे आर्टफ़ैक्ट बनाते हैं और उन आर्टफ़ैक्ट की जगह की जानकारी और नाम जैसी जानकारी को सेवा देने वाली कंपनियों में उन टारगेट की रिवर्स डिपेंडेंसी के साथ जनरेट करते हैं.
पहलू उन नियमों से मिलते-जुलते हैं जिनमें उनका लागू करने वाला फ़ंक्शन होता है जो कार्रवाइयां करने और लौटाने की सुविधा देने वालों को जनरेट करता है. हालांकि, उनकी ताकत इस बात पर निर्भर करती है कि उनके लिए डिपेंडेंसी ग्राफ़ कैसे बनाया जाता है. एक पहलू को लागू किया जाता है और उसके साथ लागू होने वाले सभी एट्रिब्यूट की सूची होती है. पहलू A पर विचार करें जो "deps" नाम वाली एट्रिब्यूट के साथ आगे बढ़ता है. इस पहलू को टारगेट X पर लागू किया जा सकता है, जिससे आसपेक्ट ऐप्लिकेशन नोड A(X) मिलता है. इस्तेमाल करने के दौरान, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) A उन सभी टारगेट पर बार-बार लागू किया जाता है जिनके बारे में X इसके "deps" एट्रिब्यूट (A की प्रॉपेगेशन सूची में सभी एट्रिब्यूट) में बताया गया है.
इसलिए, टारगेट X पर एक बार में ही आसपेक्ट A लागू करने पर, नीचे दिए गए डायग्राम में दिखाए गए टारगेट के ओरिजनल डिपेंडेंसी ग्राफ़ का "शैडो ग्राफ़" बनता है:
दूसरा डायग्राम. पहलुओं के साथ ग्राफ़ बनाएं.
सिर्फ़ उन किनारे को शैडो किया जाता है जो प्रोपेगेशन सेट में एट्रिब्यूट के साथ होते हैं. इसलिए, इस उदाहरण में runtime_deps
किनारे को शैडो नहीं किया गया है. इसके बाद, शैडो ग्राफ़ के सभी नोड पर आसपेक्ट इंप्लीमेंटेशन फ़ंक्शन लागू किया जाता है. यह ठीक वैसे ही होता है जैसे ओरिजनल ग्राफ़ के नोड पर नियम लागू करने की प्रोसेस शुरू की जाती है.
आसान उदाहरण
इस उदाहरण में बताया गया है कि किसी नियम और उसकी उन सभी डिपेंडेंसी के लिए, सोर्स फ़ाइलों को बार-बार कैसे प्रिंट किया जाए जिनमें deps
एट्रिब्यूट है. इसमें पहलू को लागू करने से जुड़ी जानकारी, आसपेक्ट की परिभाषा, और Bazel कमांड लाइन से आसपेक्ट को शुरू करने का तरीका बताया गया है.
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
आइए, उदाहरण को इसके हिस्सों में बांटते हैं और हर एक की अलग-अलग जांच करते हैं.
आसपेक्ट की परिभाषा
print_aspect = aspect(
implementation = _print_aspect_impl,
attr_aspects = ['deps'],
)
आसपेक्ट डेफ़िनिशन, नियम की परिभाषाओं से मिलती-जुलती हैं और उन्हें
aspect
फ़ंक्शन का इस्तेमाल करके तय किया जाता है.
नियम की तरह ही, पहलू लागू करने का फ़ंक्शन होता है, जो इस मामले में _print_aspect_impl
है.
attr_aspects
, नियम एट्रिब्यूट की सूची है जिसके साथ ही आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) लागू होता है.
इस मामले में, यह पहलू उन नियमों के deps
एट्रिब्यूट के साथ लागू होगा जिन पर इसे लागू किया गया है.
attr_aspects
के लिए एक और आम तर्क ['*']
है. यह
नियम के सभी एट्रिब्यूट के आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) को लागू करेगा.
आसपेक्ट लागू करना
def _print_aspect_impl(target, ctx):
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the files that make up the sources and
# print their paths.
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
print(f.path)
return []
आसपेक्ट लागू करने के फ़ंक्शन, नियम लागू करने वाले फ़ंक्शन जैसे होते हैं. वे providers दिखाते हैं, कार्रवाइयां जनरेट कर सकते हैं, और दो तर्क ले सकते हैं:
target
: वह टारगेट जिस पर आसपेक्ट को लागू किया जा रहा है.ctx
:ctx
ऑब्जेक्ट का इस्तेमाल, एट्रिब्यूट को ऐक्सेस करने, आउटपुट और कार्रवाइयों को जनरेट करने के लिए किया जा सकता है.
लागू करने वाला फ़ंक्शन, ctx.rule.attr
के ज़रिए टारगेट नियम के एट्रिब्यूट को ऐक्सेस कर सकता है. यह target
आर्ग्युमेंट की मदद से, उन कंपनियों की जांच कर सकता है जो उस टारगेट से मिली हैं जिस पर उसे लागू किया गया है.
सेवा देने वालों की सूची दिखाने के लिए, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) की जानकारी देना ज़रूरी है. इस उदाहरण में, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) कुछ नहीं मिलता है, इसलिए यह एक खाली सूची दिखाता है.
कमांड लाइन का इस्तेमाल करके पहलू शुरू करना
किसी पहलू को लागू करने का सबसे आसान तरीका, --aspects
आर्ग्युमेंट का इस्तेमाल करके, कमांड लाइन से है. यह मानते हुए कि ऊपर दिया गया पहलू print.bzl
नाम की फ़ाइल में बताया गया था
इसे:
bazel build //MyExample:example --aspects print.bzl%print_aspect
टारगेट example
पर print_aspect
और टारगेट के उन सभी नियमों को लागू करेगा जिन्हें deps
एट्रिब्यूट की मदद से बार-बार ऐक्सेस किया जा सकता है.
--aspects
फ़्लैग एक तर्क लेता है, जो कि <extension file label>%<aspect top-level name>
फ़ॉर्मैट के पहलू की जानकारी है.
बेहतर सेटिंग का उदाहरण
नीचे दिए गए उदाहरण में टारगेट नियम में मौजूद उस पहलू का इस्तेमाल करने के बारे में बताया गया है जो टारगेट में मौजूद फ़ाइलों की गिनती करता है और शायद उन्हें एक्सटेंशन के हिसाब से फ़िल्टर करता है. इसमें दिखाया गया है कि वैल्यू को लौटाने के लिए प्रोवाइडर का इस्तेमाल कैसे किया जाए, किसी पहलू को लागू करने के तरीके में आर्ग्युमेंट को पास करने के लिए पैरामीटर का इस्तेमाल कैसे किया जाए, और किसी नियम से पहलू को कैसे शुरू किया जाए.
file_count.bzl
फ़ाइल:
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
BUILD.bazel
फ़ाइल:
load('//:file_count.bzl', 'file_count_rule')
cc_library(
name = 'lib',
srcs = [
'lib.h',
'lib.cc',
],
)
cc_binary(
name = 'app',
srcs = [
'app.h',
'app.cc',
'main.cc',
],
deps = ['lib'],
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
आसपेक्ट की परिभाषा
file_count_aspect = aspect(
implementation = _file_count_aspect_impl,
attr_aspects = ['deps'],
attrs = {
'extension' : attr.string(values = ['*', 'h', 'cc']),
}
)
इस उदाहरण में दिखाया गया है कि deps
एट्रिब्यूट के ज़रिए, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) किस तरह लागू होते हैं.
attrs
, किसी पहलू के लिए एट्रिब्यूट के सेट के बारे में बताता है. सार्वजनिक पहलू वाले एट्रिब्यूट,
पैरामीटर के बारे में बताते हैं. ये सिर्फ़ bool
, int
या string
टाइप के हो सकते हैं.
नियम लागू करने वाले पहलुओं के लिए, int
और string
पैरामीटर में
values
बताया जाना चाहिए. इस उदाहरण में extension
नाम का एक पैरामीटर है, जिसमें वैल्यू के तौर पर '*
', 'h
' या 'cc
' हो सकते हैं.
नियम प्रसार करने वाले पहलुओं के लिए, पैरामीटर वैल्यू, पहलू का अनुरोध करने वाले नियम से ली जाती है. इसके लिए, समान नाम और प्रकार वाले नियम के एट्रिब्यूट का इस्तेमाल किया जाता है.
(file_count_rule
की परिभाषा देखें).
कमांड-लाइन पहलुओं के लिए, पैरामीटर वैल्यू को
--aspects_parameters
फ़्लैग का इस्तेमाल करके पास किया जा सकता है. int
और string
पैरामीटर की values
पाबंदी हटाई जा सकती है.
पहलुओं में label
या
label_list
टाइप के निजी एट्रिब्यूट भी शामिल किए जा सकते हैं. निजी लेबल एट्रिब्यूट का इस्तेमाल, अलग-अलग टूल या लाइब्रेरी के हिसाब से तय करने के लिए किया जा सकता है. ये वे टूल या लाइब्रेरी होती हैं जो अलग-अलग पहलुओं के हिसाब से जनरेट होने वाली कार्रवाइयों के लिए ज़रूरी होती हैं. इस उदाहरण में कोई निजी विशेषता नहीं है, लेकिन नीचे दिया गया कोड स्निपेट बताता है कि टूल को किसी पहलू में कैसे पास किया जा सकता है:
...
attrs = {
'_protoc' : attr.label(
default = Label('//tools:protoc'),
executable = True,
cfg = "exec"
)
}
...
आसपेक्ट लागू करना
FileCountInfo = provider(
fields = {
'count' : 'number of files'
}
)
def _file_count_aspect_impl(target, ctx):
count = 0
# Make sure the rule has a srcs attribute.
if hasattr(ctx.rule.attr, 'srcs'):
# Iterate through the sources counting files
for src in ctx.rule.attr.srcs:
for f in src.files.to_list():
if ctx.attr.extension == '*' or ctx.attr.extension == f.extension:
count = count + 1
# Get the counts from our dependencies.
for dep in ctx.rule.attr.deps:
count = count + dep[FileCountInfo].count
return [FileCountInfo(count = count)]
नियम लागू करने वाले फ़ंक्शन की तरह ही, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) लागू करने वाला फ़ंक्शन, प्रोवाइडर का स्ट्रक्चर दिखाता है जिन्हें इसकी डिपेंडेंसी से ऐक्सेस किया जा सकता है.
इस उदाहरण में, FileCountInfo
को सेवा देने वाली ऐसी कंपनी के तौर पर बताया गया है जिसके पास एक फ़ील्ड count
है. सबसे सही तरीका यह है कि आप fields
एट्रिब्यूट का इस्तेमाल करके,
सेवा देने वाली कंपनी के फ़ील्ड साफ़ तौर पर बताएं.
आसपेक्ट ऐप्लिकेशन A(X) के लिए कंपनियों का सेट, उन कंपनियों का ग्रुप होता है
जो टारगेट X के लिए नियम लागू करने और आसपेक्ट A के लागू होने
से आते हैं. नियम लागू करने की प्रक्रिया लागू करने वाली कंपनियों को, पहलुओं को लागू करने से पहले बनाया और फ़्रीज़ किया जाता है. साथ ही, उन्हें किसी आसपेक्ट से बदला नहीं जा सकता. अगर किसी टारगेट और पहलू पर लागू किया गया कोई टारगेट और पहलू,
सेवा देने वाली कंपनी को एक ही तरह का डेटा देता है, तो
OutputGroupInfo
(जिसे मर्ज किया जाता है, लेकिन जब तक नियम और आसपेक्ट अलग-अलग आउटपुट ग्रुप तय करते हैं)
और InstrumentedFilesInfo
(जिसे इस पहलू से लिया जाता है) के अपवादों को छोड़कर, यह गड़बड़ी होती है. इसका मतलब है कि आसपेक्ट इंप्लीमेंटेशन, शायद
DefaultInfo
न दिखाएं.
पैरामीटर और निजी एट्रिब्यूट,
ctx
के एट्रिब्यूट में पास किए जाते हैं. इस उदाहरण में extension
पैरामीटर का रेफ़रंस दिया गया है और यह तय किया जाता है कि किन फ़ाइलों की गिनती की जाए.
लौटने वाली कंपनियों के लिए, एट्रिब्यूट की जिन वैल्यू के साथ-साथ पहलू को लागू किया जाता है (attr_aspects
सूची से) उन्हें उस पहलू के ऐप्लिकेशन के नतीजों से बदल दिया जाता है. उदाहरण के लिए, अगर
X के डिप में Y और Z हैं, तो A(X) के लिए ctx.rule.attr.deps
, [A(Y), A(Z)] होगा.
इस उदाहरण में, ctx.rule.attr.deps
ऐसे टारगेट ऑब्जेक्ट हैं जो
मूल टारगेट के 'डेप' पर लागू करने से मिले नतीजे हैं.
उदाहरण में, फ़ाइलों की कुल ट्रांज़िटिव संख्या को इकट्ठा करने के लिए, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) टारगेट की डिपेंडेंसी से, FileCountInfo
प्रोवाइडर को ऐक्सेस करता है.
किसी नियम के पहलू को लागू करना
def _file_count_rule_impl(ctx):
for dep in ctx.attr.deps:
print(dep[FileCountInfo].count)
file_count_rule = rule(
implementation = _file_count_rule_impl,
attrs = {
'deps' : attr.label_list(aspects = [file_count_aspect]),
'extension' : attr.string(default = '*'),
},
)
लागू किए गए नियम से यह पता चलता है कि ctx.attr.deps
के ज़रिए, FileCountInfo
को कैसे ऐक्सेस किया जाए.
नियम की परिभाषा से पता चलता है कि पैरामीटर (extension
) को कैसे तय किया जाता है और उसे डिफ़ॉल्ट वैल्यू (*
) कैसे दी जाती है. ध्यान दें कि अगर डिफ़ॉल्ट वैल्यू 'cc
', 'h
' या '*
' में से कोई भी न हो, तो यह आसपेक्ट डेफ़िनिशन में पैरामीटर पर लगी पाबंदियों की वजह से गड़बड़ी हो सकती है.
टारगेट नियम के ज़रिए किसी पहलू को लागू करना
load('//:file_count.bzl', 'file_count_rule')
cc_binary(
name = 'app',
...
)
file_count_rule(
name = 'file_count',
deps = ['app'],
extension = 'h',
)
यह बताता है कि नियम के ज़रिए, extension
पैरामीटर को
आसपेक्ट में कैसे पास किया जाता है. नियम लागू करने में extension
पैरामीटर की डिफ़ॉल्ट वैल्यू
है, इसलिए extension
को वैकल्पिक पैरामीटर माना जाएगा.
file_count
टारगेट बनाने के बाद, हमारे पहलू का आकलन खुद ही किया जाएगा. साथ ही, वे सभी टारगेट जिन्हें deps
के ज़रिए बार-बार ऐक्सेस किया जाएगा.