इस पेज पर Starlark कॉन्फ़िगरेशन के फ़ायदों और बुनियादी इस्तेमाल के बारे में बताया गया है. यह आपके प्रोजेक्ट को अपनी ज़रूरत के मुताबिक बनाने के लिए, Baze का एपीआई है. इसमें बिल्ड की सेटिंग तय करने का तरीका बताया गया है. साथ ही, उदाहरण भी दिए गए हैं.
इससे ये काम किए जा सकते हैं:
- अपने प्रोजेक्ट के लिए कस्टम फ़्लैग को तय करें. इससे
--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
फ़ाइलों में तय की जाती हैं. इसलिए, बदलावों को रजिस्टर करने के लिए, bazel रिलीज़ की ज़रूरत नहीं होती. इन्हें कमांड लाइन की मदद से भी सेट किया जा सकता है.
अगर इनका इस्तेमाल 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
जैसे बुनियादी Starlark टाइप के सेट तक सीमित है. ज़्यादा जानकारी के लिए, 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 लाइब्रेरी में, पहले से तय की गई सेटिंग का एक सेट शामिल होता है. इनका इस्तेमाल, कस्टम 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
सबसे सही तरीका: किसी उपनाम को कई बार सेट करने का नतीजा यह होता है कि सबसे हाल वाले को प्राथमिकता दी जाती है. अनचाहे पार्सिंग नतीजों से बचने के लिए, यूनीक उपनाम का इस्तेमाल करें.
किसी दूसरे नाम का इस्तेमाल करने के लिए, उसे बिल्ड सेटिंग के टारगेट पाथ की जगह पर टाइप करें.
उपयोगकर्ता के .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
नियम पैरामीटर का इस्तेमाल करके तय नहीं किया जा सकता. इसके बजाय, बेज़ल में दो ऐसे नियम मौजूद हैं जो पहले से मौजूद हैं:
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()
का इस्तेमाल करके, बिल्ड सेटिंग में एट्रिब्यूट कॉन्फ़िगर कर सकते हैं. बिल्ड सेटिंग टारगेट को 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"
)
ट्रांज़िशन जोड़कर, अपने बिल्ड ग्राफ़ का साइज़ आसानी से बढ़ाया जा सकता है. इससे उन पैकेज के लिए अनुमति वाली सूची सेट हो जाती है जिनमें इस नियम के टारगेट बनाए जा सकते हैं. ऊपर दिए गए कोडब्लॉक में मौजूद डिफ़ॉल्ट वैल्यू में, सभी अनुमतियाँ शामिल हैं. हालांकि, अगर आपको यह तय करना है कि आपके नियम का इस्तेमाल कौन कर सकता है, तो उस एट्रिब्यूट को अपनी पसंद के मुताबिक बनाई गई अनुमति वाली सूची पर ले जाने के लिए सेट किया जा सकता है. अगर आपको ट्रांज़िशन से, बिल्ड की परफ़ॉर्मेंस पर पड़ने वाले असर को समझने के लिए सलाह या मदद चाहिए, तो bazel-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 ट्रांज़िशन अटैच करने का कोई तरीका नहीं है. अगर आपको ऐसा करना है, तो समस्या हल करने के तरीकों के बारे में जानने के लिए, 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"]
काम न करने वाले नेटिव विकल्प
Bazel, "//command_line_option:define"
के साथ --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",
]
)
ट्रांज़िशन की मदद से एट्रिब्यूट ऐक्सेस करना
आउटगोइंग एज में ट्रांज़िशन अटैच करने पर, ctx.attr
को सूची में बदल दिया जाता है. भले ही, ट्रांज़िशन 1:1 या 1:2+ ट्रांज़िशन हो. इस सूची में एलिमेंट का क्रम तय नहीं है.
# 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
मान लें कि आपने कोई फ़्लैग लागू किया है और //pkg:i_b
लागू होता है--//foo:owner=<STRING>
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\}\).
इससे बिल्ड ग्राफ़, टारगेट ग्राफ़ की तुलना में काफ़ी बड़ा हो जाता है. साथ ही, इससे मेमोरी और परफ़ॉर्मेंस पर असर पड़ता है.
TODO: इन समस्याओं को मेज़र करने और कम करने के लिए रणनीतियां जोड़ें.
इसके बारे में और पढ़ें
बिल्ड कॉन्फ़िगरेशन में बदलाव करने के बारे में ज़्यादा जानने के लिए, ये लेख पढ़ें:
- Starlark बिल्ड कॉन्फ़िगरेशन
- Bazel को कॉन्फ़िगर करने का रोडमैप
- शुरू से अंत तक के उदाहरणों का पूरा सेट