नियम ट्यूटोरियल

अभी तक किसी भी व्यक्ति ने चेक इन नहीं किया है किसी समस्या की शिकायत करें सोर्स देखें रात · 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Starlark, Python जैसा कॉन्फ़िगरेशन लैंग्वेज को मूल रूप से बेज़ल में इस्तेमाल करने के लिए बनाया गया था. आज से लेकर अब तक भी काम करता है. बेज़ल की BUILD और .bzl फ़ाइलें स्टारलार्क को "बिल्ड लैंग्वेज" के नाम से जाना जाता है, हालांकि यह आम तौर पर को "स्टारलार्क" कहा जाता है, खास तौर पर जब इस बात पर ज़ोर दिया जाता है कि सुविधा बिल्ड लैंग्वेज में बिल्ट-इन या "नेटिव" होने के बजाय इसकी जानकारी दी जाती है वाहन का पुर्ज़ा का नाम है. बेज़ल, ऐप्लिकेशन की मुख्य भाषा को बेहतर बनाने के लिए, कई तरह के बिल्ड से जुड़े फ़ंक्शन का इस्तेमाल करता है जैसे कि glob, genrule, java_binary वगैरह.

ज़्यादा जानकारी के लिए, Baze और Starlark के दस्तावेज़ ज़्यादा जानकारी और नियम SIG टेंप्लेट का इस्तेमाल नए नियमसेट के लिए शुरुआती पॉइंट.

खाली नियम

अपना पहला नियम बनाने के लिए, foo.bzl फ़ाइल बनाएं:

def _foo_binary_impl(ctx):
    pass

foo_binary = rule(
    implementation = _foo_binary_impl,
)

rule फ़ंक्शन को कॉल करने पर, कॉलबैक फ़ंक्शन तय करना ज़रूरी है. लॉजिक वहीं जाएगा, लेकिन फ़ंक्शन को अभी खाली छोड़ सकते हैं. ctx आर्ग्युमेंट टारगेट के बारे में जानकारी देता है.

किसी BUILD फ़ाइल से नियम लोड करके, उसका इस्तेमाल किया जा सकता है.

इसी डायरेक्ट्री में BUILD फ़ाइल बनाएं:

load(":foo.bzl", "foo_binary")

foo_binary(name = "bin")

अब, टारगेट बनाया जा सकता है:

$ bazel build bin
INFO: Analyzed target //:bin (2 packages loaded, 17 targets configured).
INFO: Found 1 target...
Target //:bin up-to-date (nothing to build)

भले ही नियम कुछ न करता हो, यह पहले से ही अन्य नियमों की तरह काम करता है: इसमें ज़रूरी है, क्योंकि यह visibility, testonly, और जैसे सामान्य एट्रिब्यूट के साथ काम करता है tags.

इवैलुएशन मॉडल

आगे बढ़ने से पहले, यह समझना ज़रूरी है कि कोड का मूल्यांकन कैसे किया जाता है.

foo.bzl को कुछ प्रिंट स्टेटमेंट से अपडेट करें:

def _foo_binary_impl(ctx):
    print("analyzing", ctx.label)

foo_binary = rule(
    implementation = _foo_binary_impl,
)

print("bzl file evaluation")

और बिल्ड:

load(":foo.bzl", "foo_binary")

print("BUILD file")
foo_binary(name = "bin1")
foo_binary(name = "bin2")

ctx.label जिस टारगेट का विश्लेषण किया जा रहा है उसके लेबल से मेल खाता हो. ctx ऑब्जेक्ट में यह है कई उपयोगी फ़ील्ड और तरीके; आप एक पूरी सूची देख सकते हैं. एपीआई के बारे में जानकारी.

कोड की क्वेरी करें:

$ bazel query :all
DEBUG: /usr/home/bazel-codelab/foo.bzl:8:1: bzl file evaluation
DEBUG: /usr/home/bazel-codelab/BUILD:2:1: BUILD file
//:bin2
//:bin1

कुछ निगरानी करें:

  • "bzl फ़ाइल का आकलन करना" पहले प्रिंट होता है. BUILD फ़ाइल का आकलन करने से पहले, Baज़ल, उन सभी फ़ाइलों की जांच करता है जिन्हें वह लोड करता है. अगर कई BUILD फ़ाइलें लोड हो रही हैं foo.bzl में है, तो आपको "bzl फ़ाइल आकलन" की सिर्फ़ एक बार दिखेगी क्योंकि Baज़र, जांच के नतीजे को कैश मेमोरी में सेव करता है.
  • कॉलबैक फ़ंक्शन _foo_binary_impl को कॉल नहीं किया गया है. बेज़ेल क्वेरी लोड होती हैं BUILD फ़ाइलें, लेकिन टारगेट का विश्लेषण नहीं करती हैं.

टारगेट का विश्लेषण करने के लिए, cquery ("कॉन्फ़िगर की गई क्वेरी") या build निर्देश:

$ bazel build :all
DEBUG: /usr/home/bazel-codelab/foo.bzl:8:1: bzl file evaluation
DEBUG: /usr/home/bazel-codelab/BUILD:2:1: BUILD file
DEBUG: /usr/home/bazel-codelab/foo.bzl:2:5: analyzing //:bin1
DEBUG: /usr/home/bazel-codelab/foo.bzl:2:5: analyzing //:bin2
INFO: Analyzed 2 targets (0 packages loaded, 0 targets configured).
INFO: Found 2 targets...

जैसा कि आपको दिख रहा है, _foo_binary_impl को अब दो बार कॉल किया गया है - हर टारगेट के लिए एक बार.

कुछ पाठकों को दिखेगा कि "bzl फ़ाइल का आकलन" किया जा रहा है दोबारा प्रिंट किया जाता है, हालांकि bazel query को कॉल करने के बाद, foo.bzl के आकलन को कैश मेमोरी में सेव किया जाता है. बेज़ल कोड का फिर से आकलन नहीं करता. यह सिर्फ़ प्रिंट इवेंट को फिर से चलाता है. भले ही तो आपको वही आउटपुट मिलता है.

फ़ाइल बनाना

अपने नियम को ज़्यादा काम का बनाने के लिए, उसे अपडेट करके फ़ाइल जनरेट करें. सबसे पहले, फ़ाइल डाउनलोड करें और उसे एक नाम दें. इस उदाहरण में, का लक्ष्य:

ctx.actions.declare_file(ctx.label.name)

अभी bazel build :all का इस्तेमाल करने पर, आपको गड़बड़ी का मैसेज दिखेगा:

The following files have no generating action:
bin2

जब भी आप किसी फ़ाइल का एलान करते हैं, तो आपको Basel को बताना होगा कि वह फ़ाइल को कोई कार्रवाई बनाएं. ctx.actions.write का इस्तेमाल करें, दिए गए कॉन्टेंट के साथ फ़ाइल बनाने के लिए.

def _foo_binary_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name)
    ctx.actions.write(
        output = out,
        content = "Hello\n",
    )

कोड मान्य है, लेकिन इससे कुछ नहीं होगा:

$ bazel build bin1
Target //:bin1 up-to-date (nothing to build)

ctx.actions.write फ़ंक्शन ने एक कार्रवाई रजिस्टर की, जिससे बेज़ल को ट्रेनिंग मिली फ़ाइल कैसे जनरेट करें. लेकिन Basel फ़ाइल तब तक नहीं बनाएगा, जब तक कि वह अनुरोध किया गया है. इसलिए, आखिरी बात यह है कि बेज़ल को बताया जाए कि नियम का आउटपुट है, न कि नियम में इस्तेमाल की जाने वाली अस्थायी फ़ाइल लागू करना.

def _foo_binary_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name)
    ctx.actions.write(
        output = out,
        content = "Hello!\n",
    )
    return [DefaultInfo(files = depset([out]))]

DefaultInfo और depset फ़ंक्शन बाद में देखें. अभी के लिए, मान लेते हैं कि आखिरी लाइन, नियम के आउटपुट चुनने का तरीका है.

अब, Bagel चलाएं:

$ bazel build bin1
INFO: Found 1 target...
Target //:bin1 up-to-date:
  bazel-bin/bin1

$ cat bazel-bin/bin1
Hello!

आपने सफलतापूर्वक एक फ़ाइल जनरेट कर ली है!

विशेषताएं

नियम को ज़्यादा काम का बनाने के लिए, नए एट्रिब्यूट जोड़ें attr मॉड्यूल में बदलाव करें और नियम की परिभाषा अपडेट करें.

username नाम की स्ट्रिंग एट्रिब्यूट जोड़ें:

foo_binary = rule(
    implementation = _foo_binary_impl,
    attrs = {
        "username": attr.string(),
    },
)

इसके बाद, इसे BUILD फ़ाइल में सेट करें:

foo_binary(
    name = "bin",
    username = "Alice",
)

कॉलबैक फ़ंक्शन में वैल्यू को ऐक्सेस करने के लिए, ctx.attr.username का इस्तेमाल करें. इसके लिए उदाहरण:

def _foo_binary_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name)
    ctx.actions.write(
        output = out,
        content = "Hello {}!\n".format(ctx.attr.username),
    )
    return [DefaultInfo(files = depset([out]))]

ध्यान दें कि आपके पास एट्रिब्यूट को ज़रूरी बनाने या उसकी डिफ़ॉल्ट वैल्यू सेट करने का विकल्प है. इसे देखें attr.string का दस्तावेज़. आप बूलियन जैसे दूसरे तरह के एट्रिब्यूट भी इस्तेमाल कर सकते हैं या पूर्णांकों की सूची शामिल करें.

डिपेंडेंसी

डिपेंडेंसी से जुड़े एट्रिब्यूट, जैसे कि attr.label और attr.label_list, उस टारगेट से डिपेंडेंसी घोषित करें जिसके पास टारगेट के लिए एट्रिब्यूट का मालिकाना हक है विशेषता के मान में लेबल दिखाई देता है. इस तरह की विशेषता देखें.

BUILD फ़ाइल में, टारगेट लेबल, स्ट्रिंग ऑब्जेक्ट के तौर पर दिखता है, जैसे //pkg:name. लागू करने के फ़ंक्शन में, टारगेट को Target ऑब्जेक्ट. उदाहरण के लिए, दिखाई गई फ़ाइलें Target.files का इस्तेमाल करके टारगेट किया गया है.

कई फ़ाइलें

डिफ़ॉल्ट रूप से, सिर्फ़ नियमों से बनाए गए टारगेट ही डिपेंडेंसी के तौर पर दिख सकते हैं, जैसे कि foo_library() टारगेट). अगर एट्रिब्यूट को ऐसे टारगेट स्वीकार करना है जो इनपुट फ़ाइलें (जैसे कि रिपॉज़िटरी में सोर्स फ़ाइलें), तो आप allow_files और स्वीकार किए जाने वाले फ़ाइल एक्सटेंशन की सूची बताएं (या True को किसी भी फ़ाइल एक्सटेंशन को अनुमति दें):

"srcs": attr.label_list(allow_files = [".java"]),

इस सूची की फ़ाइलें, ctx.files.<attribute name> का इस्तेमाल करके ऐक्सेस की जा सकती हैं. इसके लिए उदाहरण के लिए, srcs एट्रिब्यूट में मौजूद फ़ाइलों की सूची को यहां से ऐक्सेस किया जा सकता है

ctx.files.srcs

एक फ़ाइल

अगर आपको सिर्फ़ एक फ़ाइल की ज़रूरत है, तो allow_single_file का इस्तेमाल करें:

"src": attr.label(allow_single_file = [".java"])

इसके बाद, इस फ़ाइल को ctx.file.<attribute name> से ऐक्सेस किया जा सकेगा:

ctx.file.src

टेंप्लेट का इस्तेमाल करके फ़ाइल बनाना

आपके पास ऐसा नियम बनाने का विकल्प है जो टेंप्लेट के आधार पर .cc फ़ाइल जनरेट करता है. साथ ही, आपने ctx.actions.write का इस्तेमाल करके, नियम में बनाई गई स्ट्रिंग का आउटपुट दे सकता है लागू किया गया है, लेकिन इसमें दो समस्याएं हैं. सबसे पहले, टेंप्लेट की मदद से फ़ाइल बहुत बड़ी हो जाती है, तो उसे अलग फ़ाइल में रखने और विश्लेषण के दौरान बड़ी स्ट्रिंग बनाकर. दूसरा, किसी फ़ाइल उपयोगकर्ता के लिए ज़्यादा सुविधाजनक होती है. इसके बजाय, ctx.actions.expand_template जो टेंप्लेट फ़ाइल पर विकल्प देता है.

टेंप्लेट पर डिपेंडेंसी का एलान करने के लिए, template एट्रिब्यूट बनाएं फ़ाइल:

def _hello_world_impl(ctx):
    out = ctx.actions.declare_file(ctx.label.name + ".cc")
    ctx.actions.expand_template(
        output = out,
        template = ctx.file.template,
        substitutions = {"{NAME}": ctx.attr.username},
    )
    return [DefaultInfo(files = depset([out]))]

hello_world = rule(
    implementation = _hello_world_impl,
    attrs = {
        "username": attr.string(default = "unknown person"),
        "template": attr.label(
            allow_single_file = [".cc.tpl"],
            mandatory = True,
        ),
    },
)

उपयोगकर्ता नियम का इस्तेमाल इस तरह कर सकते हैं:

hello_world(
    name = "hello",
    username = "Alice",
    template = "file.cc.tpl",
)

cc_binary(
    name = "hello_bin",
    srcs = [":hello"],
)

अगर आपको असली उपयोगकर्ता को टेंप्लेट नहीं दिखाना है और हमेशा उसी का इस्तेमाल करके, डिफ़ॉल्ट वैल्यू सेट की जा सकती है और एट्रिब्यूट को निजी बनाया जा सकता है:

    "_template": attr.label(
        allow_single_file = True,
        default = "file.cc.tpl",
    ),

अंडरस्कोर से शुरू होने वाली विशेषताएं निजी होती हैं और इन्हें BUILD फ़ाइल. टेंप्लेट अब इंप्लिसिट डिपेंडेंसी है: हर hello_world लक्ष्य की इस फ़ाइल पर निर्भरता है. इस फ़ाइल को सभी के लिए उपलब्ध कराना न भूलें अन्य पैकेज में जोड़ने के लिए, BUILD फ़ाइल को अपडेट करें और exports_files:

exports_files(["file.cc.tpl"])

आगे बढ़ते रहें