पहलू

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

यह पृष्ठ एस्पेक्ट और आसान और ऐडवांस सुविधाएं देते हैं उदाहरण.

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

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

आसपेक्ट से जुड़ी बुनियादी बातें

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 फ़ाइल डिपेंडेंसी ग्राफ़.

Basel ने इस डिपेंडेंसी ग्राफ़ का विश्लेषण करने के लिए, संबंधित नियम (इस मामले में "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 []

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

  • 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 के ज़रिए बार-बार ऐक्सेस किया जा सकता है.

रेफ़रंस