कॉन्फ़िगरेशन एट्रिब्यूट, आम तौर पर select()
के नाम से जाना जाता है. यह बेज़ल फ़ीचर है. इसकी मदद से लोग, वैल्यू को टॉगल कर सकते हैं
बिल्ड नियम एट्रिब्यूट का इस्तेमाल किया जा सकता है.
उदाहरण के लिए, इसका इस्तेमाल किसी ऐसी मल्टीप्लैटफ़ॉर्म लाइब्रेरी के लिए किया जा सकता है जो अपने-आप आर्किटेक्चर के लिए सही लागू करने का विकल्प चुनता है या सुविधा-कॉन्फ़िगर की जा सकने वाली बाइनरी, जिसे बिल्ड के समय पसंद के मुताबिक बनाया जा सकता है.
उदाहरण
# myapp/BUILD
cc_binary(
name = "mybinary",
srcs = ["main.cc"],
deps = select({
":arm_build": [":arm_lib"],
":x86_debug_build": [":x86_dev_lib"],
"//conditions:default": [":generic_lib"],
}),
)
config_setting(
name = "arm_build",
values = {"cpu": "arm"},
)
config_setting(
name = "x86_debug_build",
values = {
"cpu": "x86",
"compilation_mode": "dbg",
},
)
यह उस cc_binary
का एलान करता है जो "चुनता है" यहां के झंडों पर आधारित
कमांड लाइन लिखें. खास तौर पर, deps
का नाम:
आदेश | deps = |
bazel build //myapp:mybinary --cpu=arm |
[":arm_lib"] |
bazel build //myapp:mybinary -c dbg --cpu=x86 |
[":x86_dev_lib"] |
bazel build //myapp:mybinary --cpu=ppc |
[":generic_lib"] |
bazel build //myapp:mybinary -c dbg --cpu=ppc |
[":generic_lib"] |
select()
एक ऐसी वैल्यू के लिए प्लेसहोल्डर के तौर पर काम करता है जिसे इस आधार पर चुना जाएगा
कॉन्फ़िगरेशन की शर्तें, जो config_setting
से जुड़े लेबल हैं
टारगेट के लिए. कॉन्फ़िगर किए जा सकने वाले एट्रिब्यूट में select()
का इस्तेमाल करके, एट्रिब्यूट
अलग-अलग शर्तों के होने पर, असरदार तरीके से अलग-अलग वैल्यू अपनाता है.
मैच साफ़ तौर पर होने चाहिए: अगर कई शर्तें मेल खाती हैं, तो दोनों में से कोई भी एक मैच होता है
* वे सभी एक ही वैल्यू पर सेट होते हैं. उदाहरण के लिए, linux x86 पर इस्तेमाल किया जा रहा है, तो यह साफ़ है
{"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"}
, क्योंकि दोनों ब्रांच का जवाब "हैलो" होता है.
* एक का values
, अन्य सभी का सख्त सुपरसेट है. उदाहरण के लिए, values = {"cpu": "x86", "compilation_mode": "dbg"}
साफ़ तौर पर values = {"cpu": "x86"}
की विशेषज्ञता है.
बिल्ट-इन शर्त //conditions:default
अपने-आप तब मैच होती है, जब
कुछ नहीं करता.
इस उदाहरण में deps
का इस्तेमाल किया गया है, लेकिन select()
srcs
पर भी ठीक से काम करता है,
resources
, cmd
, और ज़्यादातर एट्रिब्यूट. विशेषताओं की सिर्फ़ कुछ संख्या
जिन्हें कॉन्फ़िगर नहीं किया जा सकता और इनके बारे में साफ़ तौर पर बताया गया हो. उदाहरण के लिए,
config_setting
के अपने
values
एट्रिब्यूट को कॉन्फ़िगर नहीं किया जा सकता.
select()
और डिपेंडेंसी
कुछ एट्रिब्यूट, सभी ट्रांज़िटिव डिपेंडेंसी के लिए बिल्ड पैरामीटर को बदलते हैं
कमाया जा सकता है. उदाहरण के लिए, genrule
का tools
, --cpu
के सीपीयू में बदल जाता है
मशीनी ब्राउज़र पर गेम चल रहा है (जो क्रॉस-कंपाइलेशन की वजह से, मॉडल से अलग हो सकता है)
वाला सीपीयू (CPU) जिसे टारगेट किया गया है). इसे
कॉन्फ़िगरेशन ट्रांज़िशन.
दिया गया
#myapp/BUILD
config_setting(
name = "arm_cpu",
values = {"cpu": "arm"},
)
config_setting(
name = "x86_cpu",
values = {"cpu": "x86"},
)
genrule(
name = "my_genrule",
srcs = select({
":arm_cpu": ["g_arm.src"],
":x86_cpu": ["g_x86.src"],
}),
tools = select({
":arm_cpu": [":tool1"],
":x86_cpu": [":tool2"],
}),
)
cc_binary(
name = "tool1",
srcs = select({
":arm_cpu": ["armtool.cc"],
":x86_cpu": ["x86tool.cc"],
}),
)
चालू
$ bazel build //myapp:my_genrule --cpu=arm
x86
डेवलपर मशीन पर बिल्ड को g_arm.src
, tool1
, और
x86tool.cc
. my_genrule
से अटैच किए गए दोनों select
, my_genrule
का इस्तेमाल करते हैं
बिल्ड पैरामीटर शामिल हैं, जिनमें --cpu=arm
शामिल है. tools
एट्रिब्यूट में बदलाव होता है
tool1
और इसकी ट्रांज़िटिव डिपेंडेंसी के लिए --cpu
से x86
. select
चालू
tool1
, tool1
के बिल्ड पैरामीटर का इस्तेमाल करता है. इन पैरामीटर में --cpu=x86
शामिल होता है.
कॉन्फ़िगरेशन की शर्तें
कॉन्फ़िगर किए जा सकने वाले एट्रिब्यूट में मौजूद हर कुंजी,
config_setting
या
constraint_value
.
config_setting
,
कमांड लाइन फ़्लैग की अनुमानित सेटिंग. इन्हें एक टारगेट में इनकैप्सुलेट करके, यह
बनाए रखने में आसान "मानक" ऐसी स्थितियां जिन्हें उपयोगकर्ता एक से ज़्यादा जगहों से देख सकें.
constraint_value
एक से ज़्यादा प्लैटफ़ॉर्म के व्यवहार के लिए सहायता देता है.
पहले से मौजूद फ़्लैग
--cpu
जैसे फ़्लैग Baज़र में पहले से मौजूद हैं: बिल्ड टूल मूल रूप से इसे समझता है
बनाने के लिए डिज़ाइन किया गया है. इन्हें इनके साथ तय किया जाता है:
config_setting
की
values
एट्रिब्यूट:
config_setting(
name = "meaningful_condition_name",
values = {
"flag1": "value1",
"flag2": "value2",
...
},
)
flagN
एक फ़्लैग नाम है (--
के बिना, इसलिए "--cpu"
की जगह "cpu"
). valueN
उस फ़्लैग के लिए अपेक्षित मान है. :meaningful_condition_name
मेल खाता हो, अगर
values
की सभी एंट्री मेल खाती हैं. क्रम सही नहीं है.
valueN
को ऐसे पार्स किया जाता है जैसे कि उसे कमांड लाइन पर सेट किया गया हो. इसका मतलब है:
values = { "compilation_mode": "opt" }
bazel build -c opt
से मेल खाता हैvalues = { "force_pic": "true" }
bazel build --force_pic=1
से मेल खाता हैvalues = { "force_pic": "0" }
bazel build --noforce_pic
से मेल खाता है
config_setting
सिर्फ़ ऐसे फ़्लैग के साथ काम करता है जो टारगेट के व्यवहार पर असर डालते हैं. उदाहरण के लिए,
--show_progress
की अनुमति नहीं है, क्योंकि
इससे सिर्फ़ इस बात पर असर पड़ता है कि Ba ज़रिए, उपयोगकर्ता को आपकी प्रोग्रेस कैसे रिपोर्ट की जाती है. टारगेट, इसका इस्तेमाल नहीं कर सकते
फ़्लैग कर दें. इस्तेमाल किए जा सकने वाले फ़्लैग का सटीक सेट,
दस्तावेज़ित. व्यावहारिक तौर पर, "काम की बात" वाले ज़्यादातर फ़्लैग काम.
पसंद के मुताबिक बनाए गए फ़्लैग
आप इसके साथ अपने प्रोजेक्ट-विशिष्ट झंडों का मॉडल बना सकते हैं Starlark की बिल्ड सेटिंग. पहले से मौजूद फ़्लैग के उलट, ये बिल्ड टारगेट के तौर पर परिभाषित किया गया है, इसलिए Basel ने उन्हें टारगेट लेबल के साथ रेफ़रंस किया.
ये config_setting
से ट्रिगर होते हैं
flag_values
विशेषता:
config_setting(
name = "meaningful_condition_name",
flag_values = {
"//myflags:flag1": "value1",
"//myflags:flag2": "value2",
...
},
)
व्यवहार, पहले से मौजूद फ़्लैग जैसा ही होता है. यहां देखें देखें.
--define
कस्टम फ़्लैग के लिए एक वैकल्पिक लेगसी सिंटैक्स है (उदाहरण के लिए
--define foo=bar
). इसे यहां दिए गए किसी भी तरीके से समझा जा सकता है
values एट्रिब्यूट
(values = {"define": "foo=bar"}
) या
define_values विशेषता
(define_values = {"foo": "bar"}
). --define
का इस्तेमाल, सिर्फ़ पीछे जाने की सुविधा के लिए किया जा सकता है
साथ काम करता है. जब भी मुमकिन हो, Starlark की बिल्ड सेटिंग को प्राथमिकता दें.
values
, flag_values
, और define_values
अलग-अलग आकलन करते हैं. कॉन्टेंट बनाने
अगर सभी वैल्यू मेल खाती हैं, तो config_setting
मैच होता है.
डिफ़ॉल्ट शर्त
बिल्ट-इन शर्त //conditions:default
तब मेल खाती है, जब कोई दूसरी शर्त पूरी नहीं होती है
मैच करता है.
"बिलकुल एक मिलान" शब्द की वजह से नियम, कोई मिलान नहीं होने वाला कॉन्फ़िगर किया जा सकने वाला एट्रिब्यूट
साथ ही, किसी भी डिफ़ॉल्ट स्थिति से "no matching conditions"
गड़बड़ी नहीं होती. यह काम कर सकता है
अचानक होने वाली सेटिंग की मदद से, आवाज़ के बिना होने वाली गड़बड़ियों से सुरक्षित रखता है:
# myapp/BUILD
config_setting(
name = "x86_cpu",
values = {"cpu": "x86"},
)
cc_library(
name = "x86_only_lib",
srcs = select({
":x86_cpu": ["lib.cc"],
}),
)
$ bazel build //myapp:x86_only_lib --cpu=arm
ERROR: Configurable attribute "srcs" doesn't match this configuration (would
a default condition help?).
Conditions checked:
//myapp:x86_cpu
और साफ़ गड़बड़ियों के लिए, आप select()
के साथ कस्टम मैसेज सेट कर सकते हैं
no_match_error
एट्रिब्यूट.
प्लैटफ़ॉर्म
कमांड लाइन पर एक से ज़्यादा फ़्लैग तय करने की सुविधा से साथ ही, हर बार हर Chromebook को अलग-अलग सेट करना मुश्किल भी हो सकता है आपको कोई टारगेट बनाना है. प्लैटफ़ॉर्म आसानी से बंडल शेयर करें.
# myapp/BUILD
sh_binary(
name = "my_rocks",
srcs = select({
":basalt": ["pyroxene.sh"],
":marble": ["calcite.sh"],
"//conditions:default": ["feldspar.sh"],
}),
)
config_setting(
name = "basalt",
constraint_values = [
":black",
":igneous",
],
)
config_setting(
name = "marble",
constraint_values = [
":white",
":metamorphic",
],
)
# constraint_setting acts as an enum type, and constraint_value as an enum value.
constraint_setting(name = "color")
constraint_value(name = "black", constraint_setting = "color")
constraint_value(name = "white", constraint_setting = "color")
constraint_setting(name = "texture")
constraint_value(name = "smooth", constraint_setting = "texture")
constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")
platform(
name = "basalt_platform",
constraint_values = [
":black",
":igneous",
],
)
platform(
name = "marble_platform",
constraint_values = [
":white",
":smooth",
":metamorphic",
],
)
प्लैटफ़ॉर्म के बारे में कमांड लाइन पर जानकारी दी जा सकती है. यह सुविधा चालू करने पर,
config_setting
जिनमें प्लैटफ़ॉर्म के constraint_values
का सबसेट शामिल है,
उन config_setting
को select()
एक्सप्रेशन में मैच करने की अनुमति देता है.
उदाहरण के लिए, my_rocks
के srcs
एट्रिब्यूट को calcite.sh
पर सेट करने के लिए,
बस, अपनी वेबसाइट पर
bazel build //my_app:my_rocks --platforms=//myapp:marble_platform
प्लैटफ़ॉर्म के बिना, यह कुछ ऐसा दिख सकता है
bazel build //my_app:my_rocks --define color=white --define texture=smooth --define type=metamorphic
select()
, सीधे तौर पर constraint_value
का डेटा भी पढ़ सकता है:
constraint_setting(name = "type")
constraint_value(name = "igneous", constraint_setting = "type")
constraint_value(name = "metamorphic", constraint_setting = "type")
sh_binary(
name = "my_rocks",
srcs = select({
":igneous": ["igneous.sh"],
":metamorphic" ["metamorphic.sh"],
}),
)
यह बॉयलरप्लेट config_setting
की ज़रूरत को कम करने के लिए ही करता है
एकल मानों के लिए जांच करें.
प्लैटफ़ॉर्म पर अब भी काम चल रहा है. ज़्यादा जानकारी के लिए, दस्तावेज़ देखें.
select()
को जोड़ा जा रहा है
select
एक ही एट्रिब्यूट में कई बार दिख सकता है:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"] +
select({
":armeabi_mode": ["armeabi_src.sh"],
":x86_mode": ["x86_src.sh"],
}) +
select({
":opt_mode": ["opt_extras.sh"],
":dbg_mode": ["dbg_extras.sh"],
}),
)
select
, किसी अन्य select
के अंदर नहीं दिख सकते. अगर आपको selects
नेस्ट करना है
और आपका एट्रिब्यूट दूसरे टारगेट को वैल्यू के तौर पर लेता है, तो इंटरमीडिएट टारगेट का इस्तेमाल करें:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":armeabi_mode": [":armeabi_lib"],
...
}),
)
sh_library(
name = "armeabi_lib",
srcs = select({
":opt_mode": ["armeabi_with_opt.sh"],
...
}),
)
अगर कई शर्तों के मेल खाने पर, आपको select
की ज़रूरत है, तो और
चेन बनाना.
या चेन बनाना
इसके लिए, इन्हें आज़माएं:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1": [":standard_lib"],
":config2": [":standard_lib"],
":config3": [":standard_lib"],
":config4": [":special_lib"],
}),
)
ज़्यादातर स्थितियां एक ही डिपार्टमेंट के हिसाब से होती हैं. हालांकि, इस सिंटैक्स को पढ़ना मुश्किल है और
बनाए रखें. [":standard_lib"]
को एक से ज़्यादा बार न दोहराना अच्छा होगा
बार.
वैल्यू को बिल्ड वैरिएबल के रूप में पहले से तय करना एक विकल्प है:
STANDARD_DEP = [":standard_lib"]
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1": STANDARD_DEP,
":config2": STANDARD_DEP,
":config3": STANDARD_DEP,
":config4": [":special_lib"],
}),
)
इससे डिपेंडेंसी को मैनेज करना आसान हो जाता है. हालांकि, इसकी वजह से अब भी डुप्लिकेशन.
सीधे तौर पर ज़्यादा मदद पाने के लिए, इनमें से किसी एक विकल्प का इस्तेमाल करें:
selects.with_or
कॉन्टेंट बनाने
with_or
Skylib के प्रोसेसर में मैक्रो
selects
मॉड्यूल सीधे select
के अंदर OR
ing की स्थितियों के साथ काम करता है:
load("@bazel_skylib//lib:selects.bzl", "selects")
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = selects.with_or({
(":config1", ":config2", ":config3"): [":standard_lib"],
":config4": [":special_lib"],
}),
)
selects.config_setting_group
कॉन्टेंट बनाने
config_setting_group
Skylib के प्रोसेसर में मैक्रो
selects
मॉड्यूल OR
ing के कई config_setting
का समर्थन करता है:
load("@bazel_skylib//lib:selects.bzl", "selects")
config_setting(
name = "config1",
values = {"cpu": "arm"},
)
config_setting(
name = "config2",
values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
name = "config1_or_2",
match_any = [":config1", ":config2"],
)
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1_or_2": [":standard_lib"],
"//conditions:default": [":other_lib"],
}),
)
selects.with_or
के उलट, अलग-अलग टारगेट के हिसाब से :config1_or_2
का इस्तेमाल सभी जगहों पर किया जा सकता है
अलग-अलग एट्रिब्यूट शामिल करें.
जब तक कोई एक साफ़-साफ़ पता नहीं चलता, तब तक कई शर्तों का मिलान करने में गड़बड़ी होती है "विशेषज्ञता" या वे सभी एक ही वैल्यू पर हों. जानकारी के लिए यहां देखें.
और चेन बनाना
अगर कई शर्तों के मैच होने पर, आपको select
ब्रांच की ज़रूरत है, तो इसका इस्तेमाल करें
Skylib मैक्रो
config_setting_group:
config_setting(
name = "config1",
values = {"cpu": "arm"},
)
config_setting(
name = "config2",
values = {"compilation_mode": "dbg"},
)
selects.config_setting_group(
name = "config1_and_2",
match_all = [":config1", ":config2"],
)
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1_and_2": [":standard_lib"],
"//conditions:default": [":other_lib"],
}),
)
OR चेनिंग के उलट, मौजूदा config_setting
को सीधे AND
नहीं किया जा सकता
select
के अंदर. आपको उन्हें साफ़ तौर पर config_setting_group
में रैप करना होगा.
कस्टम गड़बड़ी के मैसेज
डिफ़ॉल्ट रूप से, कोई भी शर्त मेल न खाने पर, select()
जिस टारगेट से जुड़ा होता है
इस गड़बड़ी की वजह से काम नहीं करता:
ERROR: Configurable attribute "deps" doesn't match this configuration (would
a default condition help?).
Conditions checked:
//tools/cc_target_os:darwin
//tools/cc_target_os:android
इसे no_match_error
की मदद से, पसंद के मुताबिक बनाया जा सकता है
विशेषता:
cc_library(
name = "my_lib",
deps = select(
{
"//tools/cc_target_os:android": [":android_deps"],
"//tools/cc_target_os:windows": [":windows_deps"],
},
no_match_error = "Please build with an Android or Windows toolchain",
),
)
$ bazel build //myapp:my_lib
ERROR: Configurable attribute "deps" doesn't match this configuration: Please
build with an Android or Windows toolchain
नियमों के साथ काम करता है
नियम लागू करने के लिए कॉन्फ़िगर की जा सकने वाली हल की गई वैल्यू मिलती हैं एट्रिब्यूट की वैल्यू सबमिट करें. उदाहरण के लिए:
# myapp/BUILD
some_rule(
name = "my_target",
some_attr = select({
":foo_mode": [":foo"],
":bar_mode": [":bar"],
}),
)
$ bazel build //myapp/my_target --define mode=foo
नियम लागू करने के कोड को ctx.attr.some_attr
[":foo"]
दिखता है.
मैक्रो select()
क्लॉज़ को स्वीकार कर सकते हैं और उन्हें नेटिव तक पहुंचा सकते हैं
नियम. हालांकि, वे सीधे तौर पर उनमें हेर-फेर नहीं कर सकते. उदाहरण के लिए,
मैक्रो के लिए
select({"foo": "val"}, ...)
से
select({"foo": "val_with_suffix"}, ...)
ऐसा दो वजहों से होता है.
सबसे पहले, वे मैक्रो जिन्हें यह जानने की ज़रूरत है कि select
कौनसा पाथ चुनेगा, काम नहीं करेगा
क्योंकि मैक्रो का आकलन बेज़ेल के लोड होने के चरण में किया जाता है,
जो फ़्लैग की वैल्यू पता चलने से पहले होती है.
यह Baज़ल डिज़ाइन से जुड़ी मुख्य पाबंदी है. जल्द ही, इसे बदलने की संभावना कम है.
दूसरा, मैक्रो जिन्हें सिर्फ़ सभी select
पाथ में दोहराना होता है, जबकि
तकनीकी तौर पर संभव है, लेकिन एक आसान यूज़र इंटरफ़ेस (यूआई) नहीं है. बदलने के लिए और डिज़ाइन ज़रूरी है
यह.
बेज़ल क्वेरी और cquery
Basel query
, Basel की
लोड होने का फ़ेज़.
इसका मतलब है कि इसे इस बात की जानकारी नहीं होती कि उन कमांड लाइन के बाद से टारगेट
फ़्लैग का मूल्यांकन तब तक नहीं किया जाता जब तक कि वह बिल्ड (
विश्लेषण का चरण).
इसलिए, यह तय नहीं किया जा सकता कि कौनसी select()
ब्रांच चुनी गई हैं.
Baज़ल cquery
, Basel के विश्लेषण चरण के बाद काम करता है, इसलिए उसके पास
ये सभी जानकारी उपलब्ध कराई जाती है और select()
का सटीक तरीके से समाधान किया जा सकता है.
आकलन करते समय इन बातों का ध्यान रखें:
load("@bazel_skylib//rules:common_settings.bzl", "string_flag")
# myapp/BUILD
string_flag(
name = "dog_type",
build_setting_default = "cat"
)
cc_library(
name = "my_lib",
deps = select({
":long": [":foo_dep"],
":short": [":bar_dep"],
}),
)
config_setting(
name = "long",
flag_values = {":dog_type": "dachshund"},
)
config_setting(
name = "short",
flag_values = {":dog_type": "pug"},
)
query
, :my_lib
की डिपेंडेंसी का ज़्यादा अनुमान लगाता है:
$ bazel query 'deps(//myapp:my_lib)'
//myapp:my_lib
//myapp:foo_dep
//myapp:bar_dep
जबकि cquery
अपनी सटीक डिपेंडेंसी दिखाता है:
$ bazel cquery 'deps(//myapp:my_lib)' --//myapp:dog_type=pug
//myapp:my_lib
//myapp:bar_dep
अक्सर पूछे जाने वाले सवाल
मैक्रो में select() काम क्यों नहीं करता?
select() नियमों में काम करता है! इनके लिए नियम साथ काम करने की सुविधा देखें विवरण.
आम तौर पर, इस सवाल से जुड़ी मुख्य समस्या का मतलब यह है कि select() काम नहीं करता मैक्रो. ये नियमों से अलग होते हैं. ज़्यादा जानकारी के लिए, नियम और मैक्रो के बारे में दस्तावेज़ ताकि अंतर को समझा जा सके. यहां शुरुआत से लेकर आखिर तक का एक उदाहरण दिया गया है:
एक नियम और मैक्रो निर्धारित करें:
# myapp/defs.bzl
# Rule implementation: when an attribute is read, all select()s have already
# been resolved. So it looks like a plain old attribute just like any other.
def _impl(ctx):
name = ctx.attr.name
allcaps = ctx.attr.my_config_string.upper() # This works fine on all values.
print("My name is " + name + " with custom message: " + allcaps)
# Rule declaration:
my_custom_bazel_rule = rule(
implementation = _impl,
attrs = {"my_config_string": attr.string()},
)
# Macro declaration:
def my_custom_bazel_macro(name, my_config_string):
allcaps = my_config_string.upper() # This line won't work with select(s).
print("My name is " + name + " with custom message: " + allcaps)
नियम और मैक्रो इंस्टैंशिएट करें:
# myapp/BUILD
load("//myapp:defs.bzl", "my_custom_bazel_rule")
load("//myapp:defs.bzl", "my_custom_bazel_macro")
my_custom_bazel_rule(
name = "happy_rule",
my_config_string = select({
"//third_party/bazel_platforms/cpu:x86_32": "first string",
"//third_party/bazel_platforms/cpu:ppc": "second string",
}),
)
my_custom_bazel_macro(
name = "happy_macro",
my_config_string = "fixed string",
)
my_custom_bazel_macro(
name = "sad_macro",
my_config_string = select({
"//third_party/bazel_platforms/cpu:x86_32": "first string",
"//third_party/bazel_platforms/cpu:ppc": "other string",
}),
)
बिल्डिंग काम नहीं कर पाई, क्योंकि sad_macro
, select()
को प्रोसेस नहीं कर सका:
$ bazel build //myapp:all
ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
(most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().
ERROR: error loading package 'myapp': Package 'myapp' contains errors.
sad_macro
के टिप्पणी करने पर बिल्डिंग सफल होती है:
# Comment out sad_macro so it doesn't mess up the build.
$ bazel build //myapp:all
DEBUG: /myworkspace/myapp/defs.bzl:5:3: My name is happy_macro with custom message: FIXED STRING.
DEBUG: /myworkspace/myapp/hi.bzl:15:3: My name is happy_rule with custom message: FIRST STRING.
इसे बदलना नामुमकिन है, क्योंकि परिभाषा के मुताबिक मैक्रो का आकलन पहले किया जाता है Baज़ल, बिल्ड के कमांड लाइन फ़्लैग पढ़ता है. इसका मतलब यह है कि यह जानकारी का इस्तेमाल करें.
हालांकि, मैक्रो select()
को नियमों के लिहाज़ से ओपेक ब्लॉब के रूप में पास कर सकते हैं:
# myapp/defs.bzl
def my_custom_bazel_macro(name, my_config_string):
print("Invoking macro " + name)
my_custom_bazel_rule(
name = name + "_as_target",
my_config_string = my_config_string,
)
$ bazel build //myapp:sad_macro_less_sad
DEBUG: /myworkspace/myapp/defs.bzl:23:3: Invoking macro sad_macro_less_sad.
DEBUG: /myworkspace/myapp/defs.bzl:15:3: My name is sad_macro_less_sad with custom message: FIRST STRING.
select() हमेशा सही क्यों दिखाता है?
क्योंकि परिभाषा के अनुसार मैक्रो (लेकिन नियम नहीं)
select()
की जांच नहीं की जा सकती, ऐसा करने की कोई भी कोशिश
आम तौर पर कोई गड़बड़ी पैदा करता है:
ERROR: /myworkspace/myapp/BUILD:17:1: Traceback
(most recent call last):
File "/myworkspace/myapp/BUILD", line 17
my_custom_bazel_macro(name = "sad_macro", my_config_stri..."}))
File "/myworkspace/myapp/defs.bzl", line 4, in
my_custom_bazel_macro
my_config_string.upper()
type 'select' has no method upper().
बूलियन एक खास मामला है, जो बिना किसी सूचना के तुरंत खत्म हो जाता है. इसलिए, आपको इसे लोगों से सावधान रहें:
$ cat myapp/defs.bzl
def my_boolean_macro(boolval):
print("TRUE" if boolval else "FALSE")
$ cat myapp/BUILD
load("//myapp:defs.bzl", "my_boolean_macro")
my_boolean_macro(
boolval = select({
"//third_party/bazel_platforms/cpu:x86_32": True,
"//third_party/bazel_platforms/cpu:ppc": False,
}),
)
$ bazel build //myapp:all --cpu=x86
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.
$ bazel build //mypro:all --cpu=ppc
DEBUG: /myworkspace/myapp/defs.bzl:4:3: TRUE.
ऐसा इसलिए होता है, क्योंकि मैक्रो select()
की सामग्री को नहीं समझ पाते.
इसलिए, वे select()
ऑब्जेक्ट का ही आकलन कर रहे हैं. इसके अनुसार
Pythonic डिज़ाइन
मानकों के आधार पर, बहुत कम अपवादों को छोड़कर बाकी सभी ऑब्जेक्ट
अपने आप 'सही' दिखाता है.
क्या किसी निर्देश की तरह, Select() को पढ़ा जा सकता है?
मैक्रो चयनों का मूल्यांकन नहीं कर सकते क्योंकि मैक्रो पहले से ही आकलन करते हैं
Basel को बिल्ड के कमांड लाइन पैरामीटर के बारे में पता है. क्या वे कम से कम पढ़ सकते हैं
उदाहरण के लिए, select()
के शब्दकोश से हर वैल्यू के लिए सफ़िक्स जोड़ना है?
सैद्धांतिक तौर पर ऐसा किया जा सकता है, लेकिन यह अब तक Basel की सुविधा नहीं है.
आज आप जो कर सकते हैं, वह है एक सीधा शब्दकोश तैयार करना, फिर उसे किसी
select()
:
$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
for key in select_cmd.keys():
select_cmd[key] += " WITH SUFFIX"
native.genrule(
name = name,
outs = [name + ".out"],
srcs = [],
cmd = "echo " + select(select_cmd + {"//conditions:default": "default"})
+ " > $@"
)
$ cat myapp/BUILD
selecty_genrule(
name = "selecty",
select_cmd = {
"//third_party/bazel_platforms/cpu:x86_32": "x86 mode",
},
)
$ bazel build //testapp:selecty --cpu=x86 && cat bazel-genfiles/testapp/selecty.out
x86 mode WITH SUFFIX
अगर आपको select()
और नेटिव टाइप, दोनों का इस्तेमाल करना है, तो ऐसा किया जा सकता है:
$ cat myapp/defs.bzl
def selecty_genrule(name, select_cmd):
cmd_suffix = ""
if type(select_cmd) == "string":
cmd_suffix = select_cmd + " WITH SUFFIX"
elif type(select_cmd) == "dict":
for key in select_cmd.keys():
select_cmd[key] += " WITH SUFFIX"
cmd_suffix = select(select_cmd + {"//conditions:default": "default"})
native.genrule(
name = name,
outs = [name + ".out"],
srcs = [],
cmd = "echo " + cmd_suffix + "> $@",
)
Select(), bind() के साथ काम क्यों नहीं करता?
सबसे पहले, bind()
का इस्तेमाल न करें. अब इसका alias()
का इस्तेमाल किया जाता है.
तकनीकी जवाब यह है कि bind()
एक रेपो है
नियम, बिल्ड नियम नहीं.
रेपो नियमों का कोई खास कॉन्फ़िगरेशन नहीं होता है और इनका आकलन नहीं किया जाता है
BUILD के नियमों की तरह ही है. इसलिए, bind()
में select()
यह नहीं कर सकता
तो किसी खास ब्रांच का आकलन कर सकता है.
इसके बजाय, आपको alias()
का इस्तेमाल करना चाहिए, जिसके साथ select()
इस तरह से रन-टाइम तय करने के लिए, actual
एट्रिब्यूट. यह
सही तरीके से काम करता है, क्योंकि alias()
एक बिल्ड नियम है और इसका आकलन
खास कॉन्फ़िगरेशन.
ज़रूरत पड़ने पर, आपके पास alias()
के लिए bind()
का टारगेट पॉइंट भी हो सकता है.
$ cat WORKSPACE
workspace(name = "myapp")
bind(name = "openssl", actual = "//:ssl")
http_archive(name = "alternative", ...)
http_archive(name = "boringssl", ...)
$ cat BUILD
config_setting(
name = "alt_ssl",
define_values = {
"ssl_library": "alternative",
},
)
alias(
name = "ssl",
actual = select({
"//:alt_ssl": "@alternative//:ssl",
"//conditions:default": "@boringssl//:ssl",
}),
)
इस सेटअप की मदद से, --define ssl_library=alternative
और कोई भी टारगेट पास किया जा सकता है
जो //:ssl
या //external:ssl
पर निर्भर करती है उसे
@alternative//:ssl
पर मौजूद है.
हालांकि, bind()
का इस्तेमाल करना बंद कर दें.
मेरा Select(), मेरी उम्मीद के मुताबिक विकल्प क्यों नहीं चुनता?
अगर //myapp:foo
में select()
है, जो आपकी उम्मीद के मुताबिक स्थिति नहीं चुनता,
डीबग करने के लिए, cquery और bazel config
का इस्तेमाल करें:
अगर //myapp:foo
वह टॉप-लेवल टारगेट है जिसे आप बनाना चाहते हैं, तो चलाएं:
$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)
अगर आप कोई अन्य टारगेट //bar
बना रहे हैं, जो
//myapp:foo, इसके सबग्राफ़ में कहीं भी मौजूद है, रन:
$ bazel cquery 'somepath(//bar, //myapp:foo)' <desired build flags>
//bar:bar (3ag3193fee94a2)
//bar:intermediate_dep (12e23b9a2b534a)
//myapp:foo (12e23b9a2b534a)
(12e23b9a2b534a)
के पास //myapp:foo
के बगल में स्थित हैश है
//myapp:foo
की select()
का समाधान करने वाला कॉन्फ़िगरेशन. जांच करके देखा जा सकता है कि
bazel config
वाले मान:
$ bazel config 12e23b9a2b534a
BuildConfigurationValue 12e23b9a2b534a
Fragment com.google.devtools.build.lib.analysis.config.CoreOptions {
cpu: darwin
compilation_mode: fastbuild
...
}
Fragment com.google.devtools.build.lib.rules.cpp.CppOptions {
linkopt: [-Dfoo=bar]
...
}
...
इसके बाद, इस आउटपुट की तुलना हर config_setting
की अनुमानित सेटिंग से करें.
//myapp:foo
एक ही बिल्ड में अलग-अलग कॉन्फ़िगरेशन में मौजूद हो सकते हैं. ज़्यादा जानकारी के लिए,
cquery docs का इस्तेमाल करके, somepath
के इस्तेमाल के बारे में दिशा-निर्देश पाएं.
एक.
select()
, प्लैटफ़ॉर्म के साथ काम क्यों नहीं करता?
Baज़ल, कॉन्फ़िगर किए जा सकने वाले एट्रिब्यूट के साथ काम नहीं करता. इसकी मदद से, यह पता लगाया जा सकता है कि किसी प्लैटफ़ॉर्म पर, को टारगेट प्लैटफ़ॉर्म है, क्योंकि सिमेंटिक्स साफ़ नहीं है.
उदाहरण के लिए:
platform(
name = "x86_linux_platform",
constraint_values = [
"@platforms//cpu:x86",
"@platforms//os:linux",
],
)
cc_library(
name = "lib",
srcs = [...],
linkopts = select({
":x86_linux_platform": ["--enable_x86_optimizations"],
"//conditions:default": [],
}),
)
इस BUILD
फ़ाइल में, किस select()
का इस्तेमाल करना चाहिए, अगर टारगेट प्लैटफ़ॉर्म में
@platforms//cpu:x86
और @platforms//os:linux
कंस्ट्रेंट, लेकिन पाबंदी नहीं है
:x86_linux_platform
यहां परिभाषित किया गया है? BUILD
फ़ाइल का लेखक और उपयोगकर्ता
जिन लोगों ने अलग प्लैटफ़ॉर्म बनाया है उनके आइडिया अलग हो सकते हैं.
इसके बजाय, मुझे क्या करना चाहिए?
इसके बजाय, एक ऐसा config_setting
तय करें जो किसी भी प्लैटफ़ॉर्म से मेल खाता हो
ये सीमाएं:
config_setting(
name = "is_x86_linux",
constraint_values = [
"@platforms//cpu:x86",
"@platforms//os:linux",
],
)
cc_library(
name = "lib",
srcs = [...],
linkopts = select({
":is_x86_linux": ["--enable_x86_optimizations"],
"//conditions:default": [],
}),
)
यह प्रोसेस खास सिमेंटिक्स के बारे में बताती है, जिससे उपयोगकर्ताओं को यह समझने में मदद मिलती है कि क्या प्लैटफ़ॉर्म ज़रूरी शर्तों को पूरा करते हों.
अगर मुझे प्लैटफ़ॉर्म पर वाकई में select
करना हो, तो क्या करना होगा?
अगर बिल्ड की ज़रूरी शर्तों के लिए खास तौर पर प्लैटफ़ॉर्म की जांच करना ज़रूरी हो, तो आपको
config_setting
में --platforms
फ़्लैग की वैल्यू बदली जा सकती है:
config_setting(
name = "is_specific_x86_linux_platform",
values = {
"platforms": ["//package:x86_linux_platform"],
},
)
cc_library(
name = "lib",
srcs = [...],
linkopts = select({
":is_specific_x86_linux_platform": ["--enable_x86_optimizations"],
"//conditions:default": [],
}),
)
Basel की टीम ऐसा करने का सुझाव नहीं देती है; यह आपके बिल्ड को बहुत ज़्यादा सीमित करता है और जब ज़रूरी शर्तें पूरी नहीं होती हैं, तब उपयोगकर्ताओं को भ्रम हो सकता है.