कॉन्फ़िगरेशन

समस्या की शिकायत करें सोर्स देखें

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

इसकी मदद से, ये काम किए जा सकते हैं:

  • अपने प्रोजेक्ट के लिए कस्टम फ़्लैग को तय करें. इससे --define की ज़रूरत खत्म हो जाएगी
  • अपने पैरंट कॉन्फ़िगरेशन (जैसे, --compilation_mode=opt या --cpu=arm) के अलावा, अलग-अलग कॉन्फ़िगरेशन में डेस्क को कॉन्फ़िगर करने के लिए, ट्रांज़िशन का कोड लिखें
  • नियमों को बेहतर तरीके से डिफ़ॉल्ट तौर पर सेट करती है (जैसे कि किसी एसडीके की मदद से अपने-आप //my:android_app बनने का तरीका)

और भी बहुत कुछ, पूरी तरह से .bzl फ़ाइलों से लिया जाता है (Bzel रिलीज़ की ज़रूरत नहीं होती). उदाहरण के लिए, bazelbuild/examples रेपो देखें.

उपयोगकर्ता की ओर से तय की गई बिल्ड सेटिंग

बिल्ड सेटिंग, कॉन्फ़िगरेशन से जुड़ी जानकारी का एक हिस्सा है. कॉन्फ़िगरेशन को की/वैल्यू मैप के तौर पर देखें. --cpu=ppc और --copt="-DFoo" को सेट करने पर, {cpu: ppc, copt: "-DFoo"} जैसा कॉन्फ़िगरेशन जनरेट होता है. हर एंट्री एक बिल्ड सेटिंग है.

cpu और copt जैसे पारंपरिक फ़्लैग, नेटिव सेटिंग होते हैं — उनकी कुंजियां तय होती हैं और उनकी वैल्यू, नेटिव baज़ेन Java कोड में सेट होती हैं. Basel के उपयोगकर्ता उन्हें सिर्फ़ कमांड लाइन और दूसरे एपीआई के ज़रिए पढ़ और लिख सकते हैं. इन एपीआई को मैन्युअल तौर पर मैनेज किया जाता है. नेटिव फ़्लैग और उन्हें दिखाने वाले एपीआई बदलने के लिए, बेज़ल रिलीज़ की ज़रूरत होती है. उपयोगकर्ता की ओर से तय की गई बिल्ड सेटिंग .bzl फ़ाइलों में तय की जाती है. इसलिए, बदलाव रजिस्टर करने के लिए, बेज़ल रिलीज़ की ज़रूरत नहीं पड़ती. इन्हें कमांड लाइन की मदद से भी सेट किया जा सकता है. अगर इनका इस्तेमाल flags के तौर पर किया गया है, तो यहां ज़्यादा देखें. हालांकि, इन्हें उपयोगकर्ता के तय किए गए ट्रांज़िशन की मदद से भी सेट किया जा सकता है.

बिल्ड की सेटिंग तय की जा रही हैं

शुरू से आखिर तक का उदाहरण

build_setting rule() पैरामीटर

बिल्ड सेटिंग, किसी भी दूसरे नियम की तरह ही नियम होती हैं. इन नियमों को Starlark rule() फ़ंक्शन के build_setting एट्रिब्यूट का इस्तेमाल करके अलग-अलग किया जाता है.

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

build_setting एट्रिब्यूट एक फ़ंक्शन लेता है, जो यह बताता है कि बिल्ड सेटिंग किस तरह की है. यह टाइप, स्टारलार्क के एक सामान्य सेट तक सीमित है, जैसे कि bool और string. ज़्यादा जानकारी के लिए, config मॉड्यूल दस्तावेज़ देखें. नियम लागू करने के फ़ंक्शन में, ज़्यादा मुश्किल टाइप किया जा सकता है. इसके बारे में यहां और बताया गया है.

config मॉड्यूल के फ़ंक्शन में एक वैकल्पिक बूलियन पैरामीटर, flag लिया जाता है, जो डिफ़ॉल्ट रूप से 'गलत' पर सेट होता है. अगर flag को 'सही है' पर सेट किया जाता है, तो बिल्ड सेटिंग को कमांड लाइन पर सेट किया जा सकता है. साथ ही, इसे डिफ़ॉल्ट वैल्यू और ट्रांज़िशन के ज़रिए रूल राइटर भी सेट कर सकते हैं. यह ज़रूरी नहीं है कि उपयोगकर्ता सभी सेटिंग को सेट कर सकें. उदाहरण के लिए, अगर नियम लिखने वाले के पास कोई ऐसा डीबग मोड है जिसे आपको इन-साइड टेस्ट नियमों को चालू करना है, तो आपको उपयोगकर्ताओं को उन नियमों के तहत उस सुविधा को चालू करने की सुविधा नहीं देनी चाहिए जो जांच से अलग हैं.

ctx.build_setting_value का उपयोग करना

अन्य सभी नियमों की तरह, बिल्ड सेटिंग के नियमों में भी लागू करने के फ़ंक्शन होते हैं. बिल्ड सेटिंग की बेसिक Starlark-टाइप वैल्यू को ctx.build_setting_value तरीके से ऐक्सेस किया जा सकता है. यह तरीका सिर्फ़ बिल्ड सेटिंग के नियमों के ctx ऑब्जेक्ट के लिए उपलब्ध है. लागू करने के इन तरीकों से, बिल्ड सेटिंग की वैल्यू को सीधे तौर पर फ़ॉरवर्ड किया जा सकता है या इस पर अतिरिक्त काम किया जा सकता है. जैसे, टाइप चेकिंग या मुश्किल स्ट्रक्चर बनाना. यहां बताया गया है कि enum-टाइप की गई बिल्ड सेटिंग कैसे लागू की जाएगी:

# example/buildsettings/build_settings.bzl
TemperatureProvider = provider(fields = ['type'])

temperatures = ["HOT", "LUKEWARM", "ICED"]

def _impl(ctx):
    raw_temperature = ctx.build_setting_value
    if raw_temperature not in temperatures:
        fail(str(ctx.label) + " build setting allowed to take values {"
             + ", ".join(temperatures) + "} but was set to unallowed value "
             + raw_temperature)
    return TemperatureProvider(type = raw_temperature)

temperature = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)

कई सेट वाले स्ट्रिंग फ़्लैग तय किए जा रहे हैं

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

# example/buildsettings/build_settings.bzl
allow_multiple_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "allow_multiple_flag")
allow_multiple_flag(
    name = "roasts",
    build_setting_default = "medium"
)

फ़्लैग की हर सेटिंग को एक वैल्यू माना जाता है:

$ bazel build //my/target --//example:roasts=blonde \
    --//example:roasts=medium,dark

ऊपर दिए गए डेटा को {"//example:roasts": ["blonde", "medium,dark"]} में पार्स किया गया है और ctx.build_setting_value, ["blonde", "medium,dark"] सूची दिखाता है.

बिल्ड की सेटिंग चालू की जा रही हैं

build_setting पैरामीटर के साथ तय किए गए नियमों में, इंप्लिसिट ज़रूरी build_setting_default एट्रिब्यूट होता है. यह एट्रिब्यूट उसी टाइप का होगा जैसा build_setting पैरामीटर में बताया गया है.

# example/buildsettings/build_settings.bzl
FlavorProvider = provider(fields = ['type'])

def _impl(ctx):
    return FlavorProvider(type = ctx.build_setting_value)

flavor = rule(
    implementation = _impl,
    build_setting = config.string(flag = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)

पहले से तय सेटिंग

शुरू से आखिर तक का उदाहरण

Skylib लाइब्रेरी में पहले से तय की गई सेटिंग का एक सेट होता है जिसे अपनी पसंद के हिसाब से Starlark लिखे बिना इंस्टैंशिएट किया जा सकता है.

उदाहरण के लिए, ऐसी सेटिंग तय करने के लिए जो स्ट्रिंग वैल्यू के सीमित सेट को स्वीकार करती हो:

# example/BUILD
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
string_flag(
    name = "myflag",
    values = ["a", "b", "c"],
    build_setting_default = "a",
)

पूरी सूची के लिए, बिल्ड सेटिंग के सामान्य नियम देखें.

बिल्ड सेटिंग का इस्तेमाल करना

बिल्ड सेटिंग के आधार पर

अगर कोई टारगेट कॉन्फ़िगरेशन की कोई जानकारी पढ़ना चाहता है, तो वह सीधे तौर पर रेगुलर एट्रिब्यूट डिपेंडेंसी के ज़रिए बिल्ड सेटिंग पर निर्भर हो सकता है.

# example/rules.bzl
load("//example/buildsettings:build_settings.bzl", "FlavorProvider")
def _rule_impl(ctx):
    if ctx.attr.flavor[FlavorProvider].type == "ORANGE":
        ...

drink_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "flavor": attr.label()
    }
)
# example/BUILD
load("//example:rules.bzl", "drink_rule")
load("//example/buildsettings:build_settings.bzl", "flavor")
flavor(
    name = "favorite_flavor",
    build_setting_default = "APPLE"
)
drink_rule(
    name = "my_drink",
    flavor = ":favorite_flavor",
)

ऐसा हो सकता है कि भाषाएं, बिल्ड सेटिंग का ऐसा कैननिकल सेट बनाना चाहें जिस पर उस भाषा के सभी नियम निर्भर करते हों. हालांकि, Starlark के कॉन्फ़िगरेशन में अब fragments का नेटिव कॉन्सेप्ट, हार्डकोड ऑब्जेक्ट के तौर पर मौजूद नहीं है. हालांकि, इस कॉन्सेप्ट का अनुवाद करने के लिए, सामान्य इंप्लिसिट एट्रिब्यूट के सेट का इस्तेमाल किया जा सकता है. जैसे:

# kotlin/rules.bzl
_KOTLIN_CONFIG = {
    "_compiler": attr.label(default = "//kotlin/config:compiler-flag"),
    "_mode": attr.label(default = "//kotlin/config:mode-flag"),
    ...
}

...

kotlin_library = rule(
    implementation = _rule_impl,
    attrs = dicts.add({
        "library-attr": attr.string()
    }, _KOTLIN_CONFIG)
)

kotlin_binary = rule(
    implementation = _binary_impl,
    attrs = dicts.add({
        "binary-attr": attr.label()
    }, _KOTLIN_CONFIG)

कमांड लाइन पर बिल्ड सेटिंग का इस्तेमाल करना

ज़्यादातर नेटिव फ़्लैग की तरह, फ़्लैग के तौर पर मार्क की गई बिल्ड सेटिंग सेट करने के लिए कमांड लाइन का इस्तेमाल किया जा सकता है. बिल्ड सेटिंग का नाम, name=value सिंटैक्स का इस्तेमाल करके बनाया गया पूरा टारगेट पाथ है:

$ bazel build //my/target --//example:string_flag=some-value # allowed
$ bazel build //my/target --//example:string_flag some-value # not allowed

खास बूलियन सिंटैक्स का इस्तेमाल किया जा सकता है:

$ bazel build //my/target --//example:boolean_flag
$ bazel build //my/target --no//example:boolean_flag

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

आप अपनी बिल्ड सेटिंग के टारगेट पाथ के लिए उपनाम सेट कर सकते हैं, ताकि कमांड लाइन पर उसे पढ़ना आसान हो जाए. उपनाम, नेटिव फ़्लैग की तरह ही काम करते हैं और डबल-डैश विकल्प के सिंटैक्स का भी इस्तेमाल करते हैं.

अपने .bazelrc में --flag_alias=ALIAS_NAME=TARGET_PATH जोड़कर, दूसरा ईमेल पता सेट करें . उदाहरण के लिए, किसी उपनाम को coffee पर सेट करने के लिए:

# .bazelrc
build --flag_alias=coffee=//experimental/user/starlark_configurations/basic_build_setting:coffee-temp

सबसे सही तरीका: किसी उपनाम को कई बार सेट करने का नतीजा यह होता है कि सबसे हाल वाले को प्राथमिकता दी जाती है. पार्स करने के अनचाहे नतीजों से बचने के लिए, उपनाम के यूनीक नामों का इस्तेमाल करें.

उपनाम का इस्तेमाल करने के लिए, इसे बिल्ड सेटिंग टारगेट पाथ की जगह टाइप करें. ऊपर दिए गए coffee के उदाहरण से, उपयोगकर्ता के .bazelrc में सेट किया गया:

$ bazel build //my/target --coffee=ICED

के बजाय

$ bazel build //my/target --//experimental/user/starlark_configurations/basic_build_setting:coffee-temp=ICED

सबसे सही तरीका: हालांकि, उपनामों को कमांड लाइन पर सेट किया जा सकता है, लेकिन उन्हें .bazelrc में ही छोड़ दिया जाता है. इससे कमांड लाइन का इस्तेमाल कम होता है.

लेबल-टाइप की गई बिल्ड सेटिंग

शुरू से आखिर तक का उदाहरण

अन्य बिल्ड सेटिंग से अलग, लेबल टाइप की सेटिंग को build_setting नियम पैरामीटर का इस्तेमाल करके तय नहीं किया जा सकता. इसके बजाय, बेज़ल में दो पहले से मौजूद नियम होते हैं: label_flag और label_setting. ये नियम, असल टारगेट टारगेट करने वाली कंपनियों के बारे में बताते हैं. जिन पर बिल्ड सेटिंग सेट की गई है. label_flag और label_setting को ट्रांज़िशन के ज़रिए पढ़ा/लिखा जा सकता है और label_flag को उपयोगकर्ता, build_setting के अन्य नियमों की तरह सेट कर सकते हैं. फ़र्क़ सिर्फ़ यह है कि उन्हें पसंद के मुताबिक तय नहीं किया जा सकता.

लेबल-टाइप की गई सेटिंग, तय समय के बाद तय की गई डिफ़ॉल्ट सेटिंग की जगह ले लेंगी. देर से आने वाले डिफ़ॉल्ट एट्रिब्यूट, लेबल टाइप किए गए ऐसे एट्रिब्यूट होते हैं जिनकी फ़ाइनल वैल्यू पर कॉन्फ़िगरेशन का असर पड़ सकता है. Starlark में, यह configuration_field एपीआई की जगह लेगा.

# example/rules.bzl
MyProvider = provider(fields = ["my_field"])

def _dep_impl(ctx):
    return MyProvider(my_field = "yeehaw")

dep_rule = rule(
    implementation = _dep_impl
)

def _parent_impl(ctx):
    if ctx.attr.my_field_provider[MyProvider].my_field == "cowabunga":
        ...

parent_rule = rule(
    implementation = _parent_impl,
    attrs = { "my_field_provider": attr.label() }
)

# example/BUILD
load("//example:rules.bzl", "dep_rule", "parent_rule")

dep_rule(name = "dep")

parent_rule(name = "parent", my_field_provider = ":my_field_provider")

label_flag(
    name = "my_field_provider",
    build_setting_default = ":dep"
)

सेटिंग बनाएं और चुनें()

शुरू से आखिर तक का उदाहरण

उपयोगकर्ता select() का इस्तेमाल करके, बिल्ड सेटिंग में एट्रिब्यूट कॉन्फ़िगर कर सकते हैं. बिल्ड सेटिंग के टारगेट को config_setting के flag_values एट्रिब्यूट को पास किया जा सकता है. कॉन्फ़िगरेशन से मैच करने वाली वैल्यू को String के तौर पर पास किया जाता है. इसके बाद, इसे मैच करने के लिए बिल्ड सेटिंग के टाइप में पार्स किया जाता है.

config_setting(
    name = "my_config",
    flag_values = {
        "//example:favorite_flavor": "MANGO"
    }
)

उपयोगकर्ता के तय किए गए ट्रांज़िशन

कॉन्फ़िगरेशन ट्रांज़िशन, बिल्ड ग्राफ़ में, कॉन्फ़िगर किए गए एक टारगेट से दूसरे टारगेट में हुए ट्रांसफ़ॉर्मेशन को मैप करता है.

उन्हें सेट करने वाले नियमों में एक खास एट्रिब्यूट शामिल होना चाहिए:

  "_allowlist_function_transition": attr.label(
      default = "@bazel_tools//tools/allowlists/function_transition_allowlist"
  )

ट्रांज़िशन जोड़कर, अपने बिल्ड ग्राफ़ का साइज़ बहुत आसानी से बड़ा किया जा सकता है. इससे उन पैकेज के लिए अनुमति वाली सूची सेट हो जाती है जिनमें इस नियम के टारगेट बनाए जा सकते हैं. ऊपर दिए गए कोडब्लॉक में मौजूद डिफ़ॉल्ट वैल्यू में, सभी अनुमतियाँ शामिल हैं. हालांकि, अगर आपको यह तय करना है कि आपके नियम का इस्तेमाल कौन कर सकता है, तो उस एट्रिब्यूट को अपनी पसंद के मुताबिक बनाई गई अनुमति वाली सूची पर ले जाने के लिए सेट करें. ट्रांज़िशन से आपके बिल्ड की परफ़ॉर्मेंस पर क्या असर पड़ सकता है, इस बारे में कोई सलाह या मदद पाने के लिए, baज़ेन-discuss@googlegroups.com पर संपर्क करें.

परिभाषा तय करना

ट्रांज़िशन से, नियमों के बीच कॉन्फ़िगरेशन में होने वाले बदलावों का पता चलता है. उदाहरण के लिए, "किसी दूसरे सीपीयू के लिए मेरी डिपेंडेंसी को उसके पैरंट सीपीयू के मुकाबले कंपाइल करें" जैसे अनुरोध को ट्रांज़िशन से मैनेज किया जाता है.

औपचारिक रूप से, ट्रांज़िशन एक फ़ंक्शन है. यह इनपुट कॉन्फ़िगरेशन से एक या उससे ज़्यादा आउटपुट कॉन्फ़िगरेशन पर जाने का फ़ंक्शन है. ज़्यादातर ट्रांज़िशन 1:1 होते हैं, जैसे कि "इनपुट कॉन्फ़िगरेशन को --cpu=ppc से बदलें". 1:2 या उससे ज़्यादा ट्रांज़िशन भी मौजूद हो सकते हैं, लेकिन कुछ खास पाबंदियां भी लागू होती हैं.

Starlark में, ट्रांज़िशन को काफ़ी हद तक नियमों की तरह बताया जाता है. इनके बारे में एक खास transition() फ़ंक्शन और लागू करने का फ़ंक्शन होता है.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//example:favorite_flavor" : "MINT"}

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

transition() फ़ंक्शन को लागू करने का फ़ंक्शन, पढ़ने के लिए बिल्ड सेटिंग(inputs) और लिखने के लिए बिल्ड सेटिंग (outputs) का सेट मिलता है. लागू करने वाले फ़ंक्शन में दो पैरामीटर settings और attr होते हैं. settings, inputs पैरामीटर में transition() के लिए सेट की गई सभी सेटिंग का डिक्शनरी {String:Object} है.

attr, नियम की उन विशेषताओं और मानों का एक शब्दकोश है, जिससे ट्रांज़िशन जुड़ा है. आउटगोइंग एज ट्रांज़िशन के तौर पर अटैच किए जाने पर, इन एट्रिब्यूट की वैल्यू को पोस्ट-select() रिज़ॉल्यूशन में कॉन्फ़िगर किया जाता है. इनकमिंग एज ट्रांज़िशन के तौर पर अटैच किए जाने पर, attr ऐसे एट्रिब्यूट को शामिल नहीं करता जो अपनी वैल्यू को हल करने के लिए सिलेक्टर का इस्तेमाल करते हैं. अगर --foo पर आने वाले किसी उपयोगकर्ता के किनारे से होने वाला ट्रांज़िशन, bar एट्रिब्यूट को पढ़ता है और फिर bar एट्रिब्यूट को सेट करने के लिए, --foo को भी चुनता है, तो हो सकता है कि ट्रांज़िशन के दौरान, आने वाले एज ट्रांज़िशन की वजह से bar की गलत वैल्यू पढ़ी जा सके.

लागू करने वाले फ़ंक्शन को, लागू की जाने वाली नई बिल्ड सेटिंग वैल्यू का डिक्शनरी (या डिक्शनरी की सूची, एक से ज़्यादा आउटपुट कॉन्फ़िगरेशन वाले ट्रांज़िशन के मामले में) दिखाना होगा. लौटाए गए शब्दकोश कीसेट में बिलकुल वही बिल्ड सेटिंग शामिल होनी चाहिए जो ट्रांज़िशन फ़ंक्शन के outputs पैरामीटर को पास की जाती हैं. यह तब भी लागू होता है, जब ट्रांज़िशन के दौरान बिल्ड सेटिंग में वाकई कोई बदलाव नहीं किया गया हो - इसकी ओरिजनल वैल्यू को, उपलब्ध कराई गई डिक्शनरी में साफ़ तौर पर पास किया जाना चाहिए.

1:2+ ट्रांज़िशन के बारे में जानकारी

शुरू से आखिर तक का उदाहरण

आउटगोइंग किनारे का ट्रांज़िशन, किसी सिंगल इनपुट कॉन्फ़िगरेशन को दो या उससे ज़्यादा आउटपुट कॉन्फ़िगरेशन पर मैप कर सकता है. इससे ऐसे नियम तय करने में मदद मिलती है जिनमें एक से ज़्यादा आर्किटेक्चर वाले कोड शामिल होते हैं.

1:2+ ट्रांज़िशन को, ट्रांज़िशन लागू करने के फ़ंक्शन में डिक्शनरी की सूची दिखाकर तय किया जाता है.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return [
        {"//example:favorite_flavor" : "LATTE"},
        {"//example:favorite_flavor" : "MOCHA"},
    ]

coffee_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

वे ऐसी कस्टम कुंजियां भी सेट कर सकते हैं जिनका इस्तेमाल नियम लागू करने वाला फ़ंक्शन, अलग-अलग डिपेंडेंसी पढ़ने के लिए कर सके:

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

ट्रांज़िशन अटैच किए जा रहे हैं

शुरू से आखिर तक का उदाहरण

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

ध्यान दें: फ़िलहाल, नेटिव नियमों में Starlark ट्रांज़िशन अटैच करने का कोई तरीका नहीं है. अगर आपको ऐसा करना है, तो समाधान के बारे में जानने के लिए, baज़ेन-discuss@googlegroups.com पर संपर्क करें.

इनकमिंग एज ट्रांज़िशन

इनकमिंग किनारे के ट्रांज़िशन rule() के cfg पैरामीटर में transition ऑब्जेक्ट (transition() ने बनाया है) को अटैच करके चालू किए जाते हैं:

# example/rules.bzl
load("example/transitions:transitions.bzl", "hot_chocolate_transition")
drink_rule = rule(
    implementation = _impl,
    cfg = hot_chocolate_transition,
    ...

इनकमिंग एज ट्रांज़िशन 1:1 ट्रांज़िशन होने चाहिए.

आउटगोइंग एज ट्रांज़िशन

आउटगोइंग किनारे के ट्रांज़िशन, किसी एट्रिब्यूट के cfg पैरामीटर में transition ऑब्जेक्ट (transition() ने बनाया है) को अटैच करके चालू किए जाते हैं:

# example/rules.bzl
load("example/transitions:transitions.bzl", "coffee_transition")
drink_rule = rule(
    implementation = _impl,
    attrs = { "dep": attr.label(cfg = coffee_transition)}
    ...

आउटगोइंग एज ट्रांज़िशन 1:1 या 1:2+ हो सकते हैं.

इन कुंजियों को पढ़ने का तरीका जानने के लिए, ट्रांज़िशन वाले एट्रिब्यूट ऐक्सेस करना देखें.

नेटिव विकल्पों के हिसाब से ट्रांज़िशन

शुरू से आखिर तक का उदाहरण

स्टारलार्क ट्रांज़िशन, विकल्प के नाम के लिए खास प्रीफ़िक्स का इस्तेमाल करके, नेटिव बिल्ड कॉन्फ़िगरेशन के विकल्पों पर रीड और राइट का एलान भी कर सकते हैं.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {"//command_line_option:cpu": "k8"}

cpu_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]

असमर्थित निजी विकल्प

Baज़ल, --define को "//command_line_option:define" के साथ ट्रांज़िशन करने की सुविधा नहीं देता. इसके बजाय, कस्टम बिल्ड सेटिंग का इस्तेमाल करें. आम तौर पर, बिल्ड सेटिंग के लिए --define के नए इस्तेमाल की सलाह नहीं दी जाती.

Basel, --config पर ट्रांज़िशन की सुविधा नहीं देता है. ऐसा इसलिए है, क्योंकि --config एक "बड़ा किया गया" फ़्लैग है, जो दूसरे फ़्लैग तक बड़ा हो जाता है.

खास तौर पर, --config में ऐसे फ़्लैग शामिल हो सकते हैं जिनसे बिल्ड कॉन्फ़िगरेशन पर कोई असर नहीं पड़ता, जैसे कि --spawn_strategy. इस तरह के फ़्लैग को अलग-अलग टारगेट के लिए बाध्य नहीं किया जा सकता. इसका मतलब है कि ट्रांज़िशन में, उन्हें लागू करने का कोई आसान तरीका नहीं है.

वैकल्पिक हल के रूप में, आप उन फ़्लैग को साफ़ तौर पर आइटम बना सकते हैं जो आपके ट्रांज़िशन के कॉन्फ़िगरेशन का है हिस्सा है. इसके लिए --config के एक्सपैंशन को दो जगहों पर बनाए रखना ज़रूरी है. यह यूज़र इंटरफ़ेस (यूआई) की एक समस्या है.

ट्रांज़िशन, एक से ज़्यादा बिल्ड की सेटिंग को मंज़ूरी देने की अनुमति देता है

एक से ज़्यादा वैल्यू की अनुमति देने वाली बिल्ड सेटिंग को सेट करते समय, सेटिंग की वैल्यू को एक सूची के साथ सेट किया जाना चाहिए.

# example/buildsettings/build_settings.bzl
string_flag = rule(
    implementation = _impl,
    build_setting = config.string(flag = True, allow_multiple = True)
)
# example/BUILD
load("//example/buildsettings:build_settings.bzl", "string_flag")
string_flag(name = "roasts", build_setting_default = "medium")
# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    # Using a value of just "dark" here will throw an error
    return {"//example:roasts" : ["dark"]},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:roasts"]
)

नो-ऑप ट्रांज़िशन

अगर किसी ट्रांज़िशन से {}, [] या None वैल्यू मिलती है, तो यह सभी सेटिंग को उनकी मूल वैल्यू पर बनाए रखने का छोटा तरीका है. हर आउटपुट को साफ़ तौर पर उस पर सेट करने की तुलना में, ऐसा करना ज़्यादा आसान हो सकता है.

# example/transitions/transitions.bzl
def _impl(settings, attr):
    _ignore = (attr)
    if settings["//example:already_chosen"] is True:
      return {}
    return {
      "//example:favorite_flavor": "dark chocolate",
      "//example:include_marshmallows": "yes",
      "//example:desired_temperature": "38C",
    }

hot_chocolate_transition = transition(
    implementation = _impl,
    inputs = ["//example:already_chosen"],
    outputs = [
        "//example:favorite_flavor",
        "//example:include_marshmallows",
        "//example:desired_temperature",
    ]
)

ट्रांज़िशन वाले एट्रिब्यूट ऐक्सेस करना

शुरू से आखिर तक का उदाहरण

किसी आउटगोइंग किनारे में ट्रांज़िशन अटैच करते समय (चाहे ट्रांज़िशन 1:1 हो या 1:2+,), ctx.attr को सूची बनने के लिए मजबूर किया जाता है, अगर ऐसा पहले से नहीं हुआ है. इस सूची में एलिमेंट के क्रम की जानकारी नहीं है.

# example/transitions/rules.bzl
def _transition_impl(settings, attr):
    return {"//example:favorite_flavor" : "LATTE"},

coffee_transition = transition(
    implementation = _transition_impl,
    inputs = [],
    outputs = ["//example:favorite_flavor"]
)

def _rule_impl(ctx):
    # Note: List access even though "dep" is not declared as list
    transitioned_dep = ctx.attr.dep[0]

    # Note: Access doesn't change, other_deps was already a list
    for other_dep in ctx.attr.other_deps:
      # ...


coffee_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = coffee_transition)
        "other_deps": attr.label_list(cfg = coffee_transition)
    })

अगर ट्रांज़िशन 1:2+ है और कस्टम कुंजियां सेट की जाती हैं, तो हर कुंजी के अलग-अलग डेस्क पढ़ने के लिए ctx.split_attr का इस्तेमाल किया जा सकता है:

# example/transitions/rules.bzl
def _impl(settings, attr):
    _ignore = (settings, attr)
    return {
        "Apple deps": {"//command_line_option:cpu": "ppc"},
        "Linux deps": {"//command_line_option:cpu": "x86"},
    }

multi_arch_transition = transition(
    implementation = _impl,
    inputs = [],
    outputs = ["//command_line_option:cpu"]
)

def _rule_impl(ctx):
    apple_dep = ctx.split_attr.dep["Apple deps"]
    linux_dep = ctx.split_attr.dep["Linux deps"]
    # ctx.attr has a list of all deps for all keys. Order is not guaranteed.
    all_deps = ctx.attr.dep

multi_arch_rule = rule(
    implementation = _rule_impl,
    attrs = {
        "dep": attr.label(cfg = multi_arch_transition)
    })

यहां पूरा उदाहरण देखें.

प्लैटफ़ॉर्म और टूलचेन के साथ इंटिग्रेशन

--cpu और --crosstool_top जैसे आज के कई नेटिव फ़्लैग, टूलचेन रिज़ॉल्यूशन से जुड़े हैं. आने वाले समय में, हो सकता है कि इस तरह के फ़्लैग के लिए, साफ़ तौर पर दिखने वाले ट्रांज़िशन को टारगेट प्लैटफ़ॉर्म पर ट्रांज़िशन से बदल दिया जाए.

मेमोरी और परफ़ॉर्मेंस से जुड़ी ज़रूरी बातें

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

गलत तरीके से बनाई गई बिल्ड: एक केस स्टडी

बढ़ाए जा सकने की योग्यता वाला ग्राफ़

पहला डायग्राम. बड़े स्तर पर काम करने की सुविधा का ग्राफ़, जो टॉप लेवल टारगेट और उसकी डिपेंडेंसी को दिखाता है.

इस ग्राफ़ में टॉप लेवल टारगेट, //pkg:app दिखाया गया है, जो दो टारगेट पर निर्भर करता है: //pkg:1_0 और //pkg:1_1. ये दोनों टारगेट, दो टारगेट पर निर्भर करते हैं, //pkg:2_0 और //pkg:2_1. ये दोनों टारगेट, //pkg:3_0 और //pkg:3_1 पर निर्भर करते हैं. ऐसा //pkg:n_0 और //pkg:n_1 तक जारी रहेगा, जो दोनों एक ही टारगेट //pkg:dep पर निर्भर हैं.

//pkg:app बनाने के लिए, इन लक्ष्यों को \(2n+2\) टारगेट करना ज़रूरी है:

  • //pkg:app
  • //pkg:dep
  • \([1..n]\) \(i\) में //pkg:i_0 और //pkg:i_1

मान लें कि आप एक फ़्लैग implement करते हैं और --//foo:owner=<STRING> और //pkg:i_b लागू होता है

depConfig = myConfig + depConfig.owner="$(myConfig.owner)$(b)"

दूसरे शब्दों में, //pkg:i_b अपने सभी डिपों के लिए b को --owner की पुरानी वैल्यू में जोड़ता है.

इससे, ये कॉन्फ़िगर किए गए टारगेट जनरेट होते हैं:

//pkg:app                              //foo:owner=""
//pkg:1_0                              //foo:owner=""
//pkg:1_1                              //foo:owner=""
//pkg:2_0 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_0 (via //pkg:1_1)              //foo:owner="1"
//pkg:2_1 (via //pkg:1_0)              //foo:owner="0"
//pkg:2_1 (via //pkg:1_1)              //foo:owner="1"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_0)  //foo:owner="00"
//pkg:3_0 (via //pkg:1_0 → //pkg:2_1)  //foo:owner="01"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_0)  //foo:owner="10"
//pkg:3_0 (via //pkg:1_1 → //pkg:2_1)  //foo:owner="11"
...

//pkg:dep, \(2^n\) कॉन्फ़िगर किए गए टारगेट जनरेट करता है: config.owner= "\(b_0b_1...b_n\)", सभी के लिए \(b_i\) इन \(\{0,1\}\).

इससे बिल्ड ग्राफ़, टारगेट ग्राफ़ से बहुत ज़्यादा बड़ा हो जाता है. साथ ही, इससे मेमोरी और परफ़ॉर्मेंस पर असर पड़ सकता है.

काम की सूची: इन समस्याओं के आकलन और उन्हें कम करने के लिए रणनीतियां जोड़ें.

इसके बारे में और पढ़ें

बिल्ड कॉन्फ़िगरेशन में बदलाव करने के बारे में ज़्यादा जानकारी के लिए, यहां देखें: