यह पृष्ठ एस्पेक्ट और आसान और ऐडवांस सुविधाएं देते हैं उदाहरण.
'आसप' की मदद से, ज़्यादा जानकारी जोड़कर डिपेंडेंसी वाले ग्राफ़ को बेहतर बनाया जा सकता है और कार्रवाइयां. कुछ सामान्य स्थितियां, जब पहलू उपयोगी हो सकते हैं:
- बेज़ल को इंटिग्रेट करने वाले IDEs, पहलुओं का इस्तेमाल करके, प्रोजेक्ट.
- कोड जनरेट करने वाले टूल, अपने इनपुट पर काम करने के लिए पहलुओं का इस्तेमाल कर सकते हैं
टारगेट-एग्नोस्टिक तरीके का इस्तेमाल किया जा सकता है. उदाहरण के लिए,
BUILD
फ़ाइलों में हैरारकी के हिसाब से जानकारी दी जा सकती है protobuf लाइब्रेरी का और भाषा के हिसाब से तय किए गए नियमों में, पहलुओं का इस्तेमाल करके उन्हें अटैच किया जा सकता है किसी खास भाषा के लिए प्रोटोबफ़ सहायता कोड जनरेट करने वाली कार्रवाइयां.
आसपेक्ट से जुड़ी बुनियादी बातें
BUILD
फ़ाइलें किसी प्रोजेक्ट के सोर्स कोड की जानकारी देती हैं: कौनसा सोर्स
फ़ाइलें प्रोजेक्ट का हिस्सा हैं और उन्हें किन आर्टफ़ैक्ट (टारगेट) से बनाया जाना चाहिए
वे फ़ाइलें, उन फ़ाइलों के बीच की निर्भरताएँ क्या हैं वगैरह. Baज़र,
बिल्ड करने के लिए इस जानकारी का इस्तेमाल किया जाता है, यानी कि यह कार्रवाइयों के सेट का पता लगाता है
आर्टफ़ैक्ट बनाने के लिए (जैसे: कंपाइलर या लिंकर चलाना) और
उन कार्रवाइयों को लागू करता है. 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
फ़ाइलें जैसे आर्टफ़ैक्ट बनाने और जानकारी पास करने की सुविधा, जैसे कि जगह की जानकारी
के साथ-साथ उन आर्टफ़ैक्ट के नामों के बारे में भी बताएं जो डेटा,
providers के ज़रिए.
ऐसेट, नियमों से मिलती-जुलती होती हैं. इनमें लागू करने का एक फ़ंक्शन होता है, जो कार्रवाइयां जनरेट करता है और सेवा देने वाली कंपनियों की जानकारी दिखाता है. हालांकि, उनकी ताकत इनसे आती है डिपेंडेंसी ग्राफ़ बनाने का तरीका. किसी पहलू को लागू करने का तरीका और उन सभी एट्रिब्यूट की सूची होती है जिन्हें वह प्रॉडक्ट के साथ दिखाता है. ऐसे पहलू A पर विचार करें जो "deps" नाम के एट्रिब्यूट के साथ आगे बढ़ता है. इस ऐस्पेक्ट को किसी टारगेट X पर लागू किया जा सकता है, जिससे ऐस्पेक्ट ऐप्लिकेशन नोड A(X) बनता है. लागू करने के दौरान, ऐस्पेक्ट A को उन सभी टारगेट पर बार-बार लागू किया जाता है जिनके बारे में X अपने "deps" एट्रिब्यूट (A की प्रॉपेगेशन सूची में मौजूद सभी एट्रिब्यूट) में बताता है.
इस तरह, किसी टारगेट X पर एस्पेक्ट A को लागू करने से, टारगेट के मूल डिपेंडेंसी ग्राफ़ का "शैडो ग्राफ़" बन जाता है. यह ग्राफ़, नीचे दिए गए चित्र में दिखाया गया है:
दूसरी इमेज. पहलुओं के साथ ग्राफ़ बनाएं.
सिर्फ़ प्रॉपेगेशन सेट में मौजूद एट्रिब्यूट के किनारों को ही शेडो किया जाता है. इसलिए, इस उदाहरण में runtime_deps
एज को शेडो नहीं किया गया है. इसके बाद, शैडो ग्राफ़ के सभी नोड पर, ऐस्पेक्ट लागू करने वाला फ़ंक्शन लागू किया जाता है. यह उसी तरह होता है जिस तरह ओरिजनल ग्राफ़ के नोड पर नियम लागू किए जाते हैं.
आसान उदाहरण
यह उदाहरण दिखाता है कि
नियम और इसकी सभी डिपेंडेंसी जिनके पास deps
एट्रिब्यूट है. यह दिखाता है
पहलू लागू करना, पहलू की परिभाषा, और पहलू को लागू करने का तरीका
डाउनलोड करने की सुविधा देता है.
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 []
आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) लागू करने वाले फ़ंक्शन, नियम लागू करने से मिलते-जुलते होते हैं फ़ंक्शन. ये प्रोवाइडर दिखाते हैं, कार्रवाइयां जनरेट कर सकते हैं, और दो आर्ग्युमेंट लेते हैं:
target
: वह टारगेट जिस पर पहलू लागू किया जा रहा है.ctx
:ctx
ऑब्जेक्ट, जिसका इस्तेमाल एट्रिब्यूट ऐक्सेस करने और आउटपुट और कार्रवाइयां जनरेट करने के लिए किया जा सकता है.
लागू करने वाला फ़ंक्शन, टारगेट नियम के एट्रिब्यूट को इसके ज़रिए ऐक्सेस कर सकता है:
ctx.rule.attr
. यह उन कंपनियों की जांच कर सकती है जो
जिस टारगेट पर इसे लागू किया गया है उसके ज़रिए दिया गया (target
तर्क के ज़रिए).
जानकारी देने वाली कंपनियों की सूची दिखाने के लिए, आसपेक्ट रेशियो (लंबाई-चौड़ाई का अनुपात) देना ज़रूरी है. इस उदाहरण में, आसपेक्ट रेशियो कुछ नहीं दिखाता है. इसलिए, यह खाली सूची दिखाता है.
कमांड लाइन का इस्तेमाल करके पहलू को शुरू करना
किसी आसपेक्ट को लागू करने का सबसे आसान तरीका, कमांड लाइन से --aspects
आर्ग्युमेंट का इस्तेमाल करना है. मान लें कि ऊपर दिया गया आसपेक्ट रेशियो, print.bzl
नाम की फ़ाइल में तय किया गया था:
bazel build //MyExample:example --aspects print.bzl%print_aspect
print_aspect
को टारगेट example
और उन सभी टारगेट नियमों पर लागू करेगा जो 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
सूची से) को इससे बदल दिया जाता है
उस पहलू को लागू करने से मिले नतीजे. उदाहरण के लिए, अगर target
X के डिपेंडेंसी में Y और Z हैं, तो A(X) के लिए ctx.rule.attr.deps
[A(Y), A(Z)] होगा.
इस उदाहरण में, ctx.rule.attr.deps
ऐसे टारगेट ऑब्जेक्ट हैं जो
पहलू को '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
के ज़रिए बार-बार ऐक्सेस किया जा सकता है.