पहलू

किसी समस्या की शिकायत करें सोर्स देखें Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

इस पेज पर, ऐस्पेक्ट इस्तेमाल करने के बुनियादी तरीकों और फ़ायदों के बारे में बताया गया है. साथ ही, आसान और बेहतर उदाहरण भी दिए गए हैं.

'आसप' की मदद से, ज़्यादा जानकारी जोड़कर डिपेंडेंसी वाले ग्राफ़ को बेहतर बनाया जा सकता है और कार्रवाइयां. ऐसे कुछ सामान्य मामले जिनमें आसपेक्ट काम के हो सकते हैं:

  • Bazel को इंटिग्रेट करने वाले आईडीई, प्रोजेक्ट के बारे में जानकारी इकट्ठा करने के लिए, ऐस्पेक्ट का इस्तेमाल कर सकते हैं.
  • कोड जनरेट करने वाले टूल, अपने इनपुट पर काम करने के लिए पहलुओं का इस्तेमाल कर सकते हैं टारगेट-एग्नोस्टिक तरीके का इस्तेमाल किया जा सकता है. उदाहरण के लिए, BUILD फ़ाइलें protobuf लाइब्रेरी की परिभाषाओं की हैरारकी तय कर सकती हैं. साथ ही, भाषा के हिसाब से बने नियम, किसी खास भाषा के लिए protobuf सहायता कोड जनरेट करने वाली कार्रवाइयों को अटैच करने के लिए, आसपेक्ट का इस्तेमाल कर सकते हैं.

आसपेक्ट रेशियो के बारे में बुनियादी जानकारी

BUILD फ़ाइलें, किसी प्रोजेक्ट के सोर्स कोड के बारे में जानकारी देती हैं: प्रोजेक्ट का कौनसा सोर्स फ़ाइल हिस्सा है, उन फ़ाइलों से कौनसे आर्टफ़ैक्ट (टारगेट) बनाए जाने चाहिए, उन फ़ाइलों के बीच कौनसी डिपेंडेंसी हैं वगैरह. Bazel, बिल्ड करने के लिए इस जानकारी का इस्तेमाल करता है. इसका मतलब है कि यह आर्टफ़ैक्ट बनाने के लिए ज़रूरी कार्रवाइयों (जैसे, कंपाइलर या लिंकर चलाना) का सेट तय करता है और उन कार्रवाइयों को पूरा करता है. 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 एट्रिब्यूट होना चाहिए. इसमें, ऐस्पेक्ट लागू करने का तरीका, ऐस्पेक्ट की परिभाषा, और 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 []

आसपेक्ट लागू करने वाले फ़ंक्शन, नियम लागू करने वाले फ़ंक्शन से मिलते-जुलते हैं. ये प्रोवाइडर दिखाते हैं, कार्रवाइयां जनरेट कर सकते हैं, और दो आर्ग्युमेंट लेते हैं:

  • 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 सूची से) को बदल दिया जाता है जिनके लिए एस्पेक्ट लागू किया गया है. उदाहरण के लिए, अगर टारगेट 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 = '*'),
    },
)

नियम के लागू होने पर, FileCountInfo को ऐक्सेस करने का तरीका पता चलता है ctx.attr.deps से.

नियम की परिभाषा से पता चलता है कि किसी पैरामीटर (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 के ज़रिए बार-बार ऐक्सेस किया जा सकता है.

रेफ़रंस