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

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

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

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

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

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

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

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

cpu और copt जैसे पारंपरिक फ़्लैग, नेटिव सेटिंग होते हैं — उनकी कुंजियां तय की जाती हैं और उनकी वैल्यू, नेटिव bazel java कोड में सेट की जाती हैं. Bazel के उपयोगकर्ता, इन फ़ाइलों को सिर्फ़ कमांड लाइन और नेटिव तौर पर मैनेज किए जाने वाले अन्य एपीआई के ज़रिए पढ़ और लिख सकते हैं. नेटिव फ़्लैग और उन्हें एक्सपोज़ करने वाले एपीआई में बदलाव करने के लिए, bazel रिलीज़ की ज़रूरत होती है. उपयोगकर्ता के हिसाब से बनाया गया बिल्ड सेटिंग .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 पैरामीटर होता है. इसकी मदद से, कमांड लाइन या bazelrcs में, फ़्लैग को कई बार सेट किया जा सकता है. हालांकि, उनकी डिफ़ॉल्ट वैल्यू अब भी स्ट्रिंग टाइप वाले एट्रिब्यूट के साथ सेट होती है:

# 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 लाइब्रेरी में पहले से तय सेटिंग का एक सेट होता है, जिसे बिना किसी का इस्तेमाल करना था.

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

# 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",
)

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

# 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

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

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

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

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

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

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

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

के बजाय

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

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

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

पूरी प्रोसेस का उदाहरण

अन्य बिल्ड सेटिंग के विपरीत, लेबल-टाइप सेटिंग को build_setting नियम पैरामीटर. इसके बजाय, bazel में दो बुनियादी नियम होते हैं: 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"
)

build settings और select()

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

उपयोगकर्ता इनमें से किसी का इस्तेमाल करके, बिल्ड सेटिंग में एट्रिब्यूट कॉन्फ़िगर कर सकते हैं select(). बिल्ड सेटिंग के टारगेट को, इसकी flag_values एट्रिब्यूट में पास किया जा सकता है config_setting. कॉन्फ़िगरेशन से मेल खाने वाली वैल्यू, इसके बाद, 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, एलान की गई सभी सेटिंग का डिक्शनरी {String:Object} है transition() के लिए inputs पैरामीटर में.

attr नियम की विशेषताओं और मानों का एक शब्दकोश है, जिसे ट्रांज़िशन अटैच किया गया है. जब आउटगोइंग किनारे का ट्रांज़िशन, इनके मान एट्रिब्यूट, सभी पोस्ट-select() रिज़ॉल्यूशन को कॉन्फ़िगर किए गए हैं. इस रूप में अटैच किए जाने पर इनकमिंग एज ट्रांज़िशन में, attr के लिए ऐसे एट्रिब्यूट को शामिल करें जिनकी वैल्यू बदलने के लिए, सिलेक्टर का इस्तेमाल किया जाता है. अगर कोई --foo पर इनकमिंग एज ट्रांज़िशन, bar एट्रिब्यूट को पढ़ता है. इसके बाद, --foo एट्रिब्यूट का इस्तेमाल करके bar एट्रिब्यूट सेट करता है. इसके बाद, ट्रांज़िशन में 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 ट्रांज़िशन को नेटिव नियमों से अटैच करने का कोई तरीका नहीं है. अगर आपको ऐसा करना है, तो समस्या हल करने के तरीकों के बारे में जानने के लिए, bazel-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+ हो सकते हैं.

ट्रांज़िशन वाले एट्रिब्यूट ऐक्सेस करना देखें का एक लिंक दिया गया है.

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

पूरी प्रोसेस का उदाहरण

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

# 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"]

काम न करने वाले नेटिव विकल्प

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

Bazel, --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

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

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

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

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

//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= \(\{0,1\}\)में मौजूद सभी \(b_i\) के लिए "\(b_0b_1...b_n\)".

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

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

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

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