कॉन्फ़िगर किए जा सकने वाले बिल्ड एट्रिब्यूट

किसी समस्या की शिकायत करें सोर्स देखें रात · 7.4 को अपनाएं. 7.3 · 7.2 · 7.1 · 7.0 · 6.5

कॉन्फ़िगरेशन एट्रिब्यूट, आम तौर पर 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 जैसे फ़्लैग, Bazel में पहले से मौजूद होते हैं: सभी प्रोजेक्ट के सभी बिल्ड के लिए, बिल्ड टूल उन्हें नेटिव तौर पर समझता है. इन्हें इनके साथ तय किया जाता है: 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 का इस्तेमाल नहीं किया जा सकता, क्योंकि इससे सिर्फ़ इस बात पर असर पड़ता है कि Bazel, उपयोगकर्ता को प्रोग्रेस की रिपोर्ट कैसे दिखाता है. टारगेट, अपने नतीजे बनाने के लिए उस फ़्लैग का इस्तेमाल नहीं कर सकते. इस्तेमाल किए जा सकने वाले फ़्लैग का सटीक सेट, दस्तावेज़ित. आम तौर पर, "काम के" ज़्यादातर फ़्लैग काम करते हैं.

पसंद के मुताबिक बनाए गए फ़्लैग

Starlark बिल्ड सेटिंग की मदद से, प्रोजेक्ट के हिसाब से फ़्लैग बनाए जा सकते हैं. इन फ़्लैग को, पहले से मौजूद फ़्लैग के उलट, बाइल्ड टारगेट के तौर पर तय किया जाता है. इसलिए, Bazel इनका रेफ़रंस टारगेट लेबल के साथ देता है.

ये 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 को मैच करना है, तो AND का इस्तेमाल करके चेन बनाएं.

या चेन बनाना

इसके लिए, इन्हें आज़माएं:

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"] को एक से ज़्यादा बार न दोहराना अच्छा होगा बार.

एक विकल्प यह है कि वैल्यू को BUILD वैरिएबल के तौर पर पहले से तय किया जाए:

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

Skylib के selects मॉड्यूल में with_or मैक्रो, सीधे तौर पर select में ORing कंडीशन के साथ काम करता है:

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 मॉड्यूल ORing के कई 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 शेयर कर सकते हैं.

जब तक कोई एक साफ़-साफ़ पता नहीं चलता, तब तक कई शर्तों का मिलान करने में गड़बड़ी होती है "विशेषज्ञता" या वे सभी एक ही वैल्यू पर हों. जानकारी के लिए यहां देखें.

AND चेन

अगर आपको एक से ज़्यादा शर्तें पूरी होने पर मैच करने के लिए 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 को सीधे select में AND नहीं किया जा सकता. आपको उन्हें साफ़ तौर पर 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 कौनसा पाथ चुनेगा, काम नहीं करेगा क्योंकि मैक्रो का आकलन बेज़ल के लोड होने के चरण में होता है, जो फ़्लैग की वैल्यू पता चलने से पहले होती है. यह Basel के डिज़ाइन से जुड़ी मुख्य पाबंदी है. जल्द ही, इसे बदला नहीं जा सकता.

दूसरा, मैक्रो जिन्हें सिर्फ़ सभी select पाथ में दोहराना होता है, जबकि तकनीकी तौर पर संभव है, लेकिन एक आसान यूज़र इंटरफ़ेस (यूआई) नहीं है. इसे बदलने के लिए, और डिज़ाइन करना ज़रूरी है.

बेज़ेल क्वेरी और cquery

Basel query, Basel की लोड होने का फ़ेज़. इसका मतलब है कि इसे इस बात की जानकारी नहीं होती कि उन कमांड लाइन के बाद से टारगेट फ़्लैग का मूल्यांकन तब तक नहीं किया जाता जब तक कि वह बिल्ड में ( विश्लेषण का चरण). इसलिए, यह तय नहीं किया जा सकता कि कौनसी select() शाखाएं चुनी गई हैं.

Bazel cquery, विश्लेषण के बाद काम करता है. इसलिए, उसके पास यह सारी जानकारी होती है और वह 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.

इस क्रम को बदला नहीं जा सकता, क्योंकि इसके हिसाब से, मैक्रो का आकलन, बज़ल के बिल्ड के कमांड लाइन फ़्लैग को पढ़ने से पहले किया जाता है. इसका मतलब है कि select()s का आकलन करने के लिए, ज़रूरत के मुताबिक जानकारी उपलब्ध नहीं है.

हालांकि, मैक्रो 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 डिज़ाइन स्टैंडर्ड के मुताबिक, कुछ अपवादों को छोड़कर सभी ऑब्जेक्ट अपने-आप True दिखाते हैं.

क्या select() को डिक्शनरी की तरह पढ़ा जा सकता है?

मैक्रो चयनों का मूल्यांकन नहीं कर सकते क्योंकि मैक्रो पहले से ही आकलन करते हैं Basel को बिल्ड के कमांड लाइन पैरामीटर के बारे में पता है. क्या वे कम से कम पढ़ सकते हैं उदाहरण के लिए, select() के शब्दकोश से हर वैल्यू के लिए सफ़िक्स जोड़ना है?

सैद्धांतिक तौर पर, ऐसा किया जा सकता है. हालांकि, फ़िलहाल यह Bazel की सुविधा नहीं है. आज आप जो कर सकते हैं, वह है एक सीधा शब्दकोश तैयार करना, फिर उसे किसी 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() एक repo नियम है, न कि BUILD नियम.

रेपो नियमों का कोई खास कॉन्फ़िगरेशन नहीं होता है और इनका आकलन नहीं किया जाता है BUILD के नियमों की तरह ही है. इसलिए, bind() में select() यह नहीं कर सकता तो किसी खास ब्रांच का आकलन कर सकता है.

इसके बजाय, आपको alias() का इस्तेमाल करना चाहिए, जिसके साथ select() इस तरह से रन-टाइम तय करने के लिए, actual एट्रिब्यूट. यह सही तरीके से काम करता है, क्योंकि alias() एक बिल्ड नियम है और इसका आकलन खास कॉन्फ़िगरेशन.

$ 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)

//myapp:foo के बगल में मौजूद (12e23b9a2b534a), कॉन्फ़िगरेशन का हैश है. यह //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 एक ही बिल्ड में अलग-अलग कॉन्फ़िगरेशन में मौजूद हो सकता है. सही somepath चुनने के लिए, somepath का इस्तेमाल करने के बारे में जानकारी पाने के लिए, cquery दस्तावेज़ देखें.

select(), प्लैटफ़ॉर्म के साथ काम क्यों नहीं करता?

Bazel, कॉन्फ़िगर किए जा सकने वाले एट्रिब्यूट के साथ काम नहीं करता. इससे यह पता नहीं चलता कि कोई प्लैटफ़ॉर्म टारगेट प्लैटफ़ॉर्म है या नहीं. ऐसा इसलिए है, क्योंकि सेमेटिक्स साफ़ तौर पर नहीं दिखते.

उदाहरण के लिए:

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 की टीम ऐसा करने का सुझाव नहीं देती है; यह आपके बिल्ड को बहुत ज़्यादा सीमित करता है और जब ज़रूरी शर्तें पूरी नहीं होती हैं, तब उपयोगकर्ताओं को भ्रम हो सकता है.