Atribut yang dapat dikonfigurasi, umumnya dikenal sebagai select()
, adalah fitur Bazel yang memungkinkan pengguna mengubah nilai
atribut aturan build di command line.
Ini dapat digunakan, misalnya, untuk library multiplatform yang secara otomatis memilih implementasi yang sesuai untuk arsitektur, atau untuk biner yang dapat dikonfigurasi fitur yang dapat disesuaikan pada waktu {i>build<i}.
Contoh
# 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",
},
)
Tindakan ini mendeklarasikan cc_binary
yang "memilih" dependensinya berdasarkan flag di
command line. Secara khusus, deps
menjadi:
Perintah | dependensi = |
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()
berfungsi sebagai placeholder untuk nilai yang akan dipilih berdasarkan
kondisi konfigurasi, yang merupakan label yang mereferensikan target
config_setting
. Dengan menggunakan select()
dalam atribut yang dapat dikonfigurasi, atribut tersebut
secara efektif mengadopsi nilai yang berbeda
ketika kondisi yang berbeda berlaku.
Pencocokan harus tidak ambigu: jika beberapa kondisi cocok, maka
* Semuanya akan me-resolve ke nilai yang sama. Misalnya, saat berjalan di Linux x86, ini jelas
{"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"}
karena kedua cabang ditetapkan ke "hello".
* values
seseorang adalah superset ketat dari semua values
lainnya. Misalnya, values = {"cpu": "x86", "compilation_mode": "dbg"}
adalah spesialisasi values = {"cpu": "x86"}
yang tidak ambigu.
Kondisi bawaan //conditions:default
akan otomatis dicocokkan saat
tidak dilakukan apa pun.
Meskipun contoh ini menggunakan deps
, select()
juga berfungsi dengan baik di srcs
,
resources
, cmd
, dan sebagian besar atribut lainnya. Hanya sedikit atribut
tidak dapat dikonfigurasi, dan dianotasikan dengan jelas. Misalnya,
config_setting
milik sendiri
Atribut values
tidak dapat dikonfigurasi.
select()
dan dependensi
Atribut tertentu mengubah parameter build untuk semua dependensi transitif
di bawah target. Misalnya, tools
genrule
mengubah --cpu
menjadi CPU
mesin yang menjalankan Bazel (yang, berkat kompilasi silang, mungkin berbeda
dengan CPU yang digunakan untuk membuat target). Hal ini dikenal sebagai
transisi konfigurasi.
Diberikan
#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"],
}),
)
berlari
$ bazel build //myapp:my_genrule --cpu=arm
di mesin developer x86
akan mengikat build ke g_arm.src
, tool1
, dan
x86tool.cc
. Kedua select
yang dilampirkan ke my_genrule
menggunakan my_genrule
parameter build, yang mencakup --cpu=arm
. Atribut tools
mengubah
--cpu
menjadi x86
untuk tool1
dan dependensi transitifnya. select
di
tool1
menggunakan parameter build tool1
, yang menyertakan --cpu=x86
.
Kondisi konfigurasi
Setiap kunci dalam atribut yang dapat dikonfigurasi adalah referensi label ke
config_setting
atau
constraint_value
.
config_setting
hanyalah kumpulan
setelan flag command line yang diharapkan. Dengan mengenkapsulasinya dalam target, akan
mudah untuk mempertahankan kondisi "standar" yang dapat dirujuk pengguna dari beberapa tempat.
constraint_value
menyediakan dukungan untuk perilaku multi-platform.
Flag bawaan
Tanda seperti --cpu
sudah disertakan dalam Bazel: alat build memahami secara native
untuk semua build di semua project. Hal ini ditentukan dengan
config_setting
Atribut values
:
config_setting(
name = "meaningful_condition_name",
values = {
"flag1": "value1",
"flag2": "value2",
...
},
)
flagN
adalah nama tanda (tanpa --
, jadi "cpu"
, bukan "--cpu"
). valueN
adalah nilai yang diharapkan untuk tanda tersebut. :meaningful_condition_name
cocok jika
setiap entri dalam values
cocok. Pesanan tidak relevan.
valueN
diuraikan seolah-olah ditetapkan pada command line. Artinya:
values = { "compilation_mode": "opt" }
cocok denganbazel build -c opt
values = { "force_pic": "true" }
cocok denganbazel build --force_pic=1
values = { "force_pic": "0" }
cocok denganbazel build --noforce_pic
config_setting
hanya mendukung flag yang memengaruhi perilaku target. Misalnya,
--show_progress
tidak diizinkan karena
hanya memengaruhi cara Bazel melaporkan progres kepada pengguna. Target tidak dapat menggunakan flag tersebut untuk membuat hasilnya. Set tanda yang didukung tidak
terdokumentasi. Dalam praktiknya, sebagian besar flag yang "masuk akal" akan berfungsi.
Tanda kustom
Anda dapat membuat model flag khusus project Anda sendiri dengan setelan build Starlark. Tidak seperti penanda bawaan, ini adalah ditetapkan sebagai target build, jadi Bazel mereferensikannya dengan label target.
Peristiwa ini dipicu dengan config_setting
flag_values
:
config_setting(
name = "meaningful_condition_name",
flag_values = {
"//myflags:flag1": "value1",
"//myflags:flag2": "value2",
...
},
)
Perilakunya sama dengan tanda bawaan. Lihat di sini untuk sebuah contoh kerja.
--define
adalah sintaksis lama alternatif untuk tanda kustom (misalnya
--define foo=bar
). Hal ini dapat dinyatakan dalam
Atribut nilai
(values = {"define": "foo=bar"}
) atau
Atribut define_values
(define_values = {"foo": "bar"}
). --define
hanya didukung untuk versi mundur
kompatibilitas mundur. Pilih setelan build Starlark jika memungkinkan.
values
, flag_values
, dan define_values
dievaluasi secara independen. Tujuan
config_setting
cocok jika semua nilai di antaranya cocok.
Kondisi default
Kondisi bawaan //conditions:default
cocok saat tidak ada kondisi lain
yang cocok.
Karena "persis satu kecocokan" aturan, atribut yang dapat dikonfigurasi tanpa kecocokan
dan tidak ada kondisi default yang memunculkan error "no matching conditions"
. Hal ini dapat
melindungi dari kegagalan senyap dari setelan yang tidak terduga:
# 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
Untuk kesalahan yang lebih jelas lagi, Anda dapat menyetel pesan khusus dengan select()
Atribut no_match_error
.
Platform
Meskipun kemampuan untuk menentukan beberapa flag di command line memberikan fleksibilitas, hal ini juga dapat membebani untuk menetapkan setiap flag satu per satu setiap kali Anda ingin mem-build target. Platform memungkinkan Anda menggabungkannya menjadi beberapa paket sederhana.
# 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",
],
)
Platform dapat ditentukan di command line. Hal ini mengaktifkan
config_setting
yang berisi subset constraint_values
platform,
sehingga config_setting
tersebut dapat dicocokkan dalam ekspresi select()
.
Misalnya, untuk menetapkan atribut srcs
dari my_rocks
ke calcite.sh
,
Anda cukup menjalankan
bazel build //my_app:my_rocks --platforms=//myapp:marble_platform
Tanpa platform, ini mungkin terlihat seperti
bazel build //my_app:my_rocks --define color=white --define texture=smooth --define type=metamorphic
select()
juga dapat langsung membaca 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"],
}),
)
Hal ini menghemat kebutuhan config_setting
boilerplate saat Anda hanya perlu
memeriksa terhadap satu nilai.
Platform masih dalam pengembangan. Lihat dokumentasi untuk mengetahui detailnya.
Menggabungkan select()
select
dapat muncul beberapa kali dalam atribut yang sama:
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
tidak dapat muncul di dalam select
lain. Jika Anda perlu menyusun bertingkat selects
dan atribut Anda menggunakan target lain sebagai nilai, gunakan target perantara:
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"],
...
}),
)
Jika Anda memerlukan select
untuk dicocokkan saat beberapa kondisi cocok, pertimbangkan DAN
perantaian.
Perantaian OR
Pertimbangkan hal berikut:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1": [":standard_lib"],
":config2": [":standard_lib"],
":config3": [":standard_lib"],
":config4": [":special_lib"],
}),
)
Sebagian besar kondisi dievaluasi dengan dependensi yang sama. Tetapi {i>syntax<i} ini sulit dibaca dan
pertahankan. Sebaiknya Anda tidak perlu mengulangi [":standard_lib"]
beberapa
kali.
Salah satu opsinya adalah menetapkan nilainya di awal sebagai variabel 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"],
}),
)
Hal ini memudahkan pengelolaan dependensi. Tapi itu masih menyebabkan duplikasi.
Untuk dukungan yang lebih langsung, gunakan salah satu dari berikut ini:
selects.with_or
Tujuan
with_or
makro di kolom Skylib
selects
modul mendukung kondisi OR
ing langsung di dalam select
:
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
Makro
config_setting_group
di modul
selects
Skylib
mendukung OR
beberapa 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"],
}),
)
Tidak seperti selects.with_or
, target yang berbeda dapat berbagi :config1_or_2
dengan
atribut yang berbeda.
Ini merupakan error untuk beberapa kondisi yang cocok, kecuali jika salah satunya tidak ambigu "spesialisasi" dari yang lain atau mereka semua selesai pada nilai yang sama. Lihat di sini untuk mengetahui detailnya.
Perantaian AND
Jika Anda memerlukan cabang select
yang cocok saat beberapa kondisi cocok, gunakan makro
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"],
}),
)
Tidak seperti rantai OR, config_setting
yang ada tidak dapat langsung di-AND
di dalam select
. Anda harus menggabungkannya secara eksplisit dalam config_setting_group
.
Pesan error khusus
Secara default, jika tidak ada kondisi yang cocok, target yang dilampirkan ke select()
akan gagal dengan error:
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
Hal ini dapat disesuaikan dengan atribut 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
Kompatibilitas aturan
Penerapan aturan menerima nilai yang telah di-resolve dari nilai yang dapat dikonfigurasi . Misalnya, jika:
# myapp/BUILD
some_rule(
name = "my_target",
some_attr = select({
":foo_mode": [":foo"],
":bar_mode": [":bar"],
}),
)
$ bazel build //myapp/my_target --define mode=foo
Kode penerapan aturan melihat ctx.attr.some_attr
sebagai [":foo"]
.
Makro dapat menerima klausul select()
dan meneruskannya ke aturan native. Namun, pengguna tidak dapat langsung memanipulasinya. Misalnya, tidak ada cara
untuk makro mengonversi
select({"foo": "val"}, ...)
hingga
select({"foo": "val_with_suffix"}, ...)
Ini karena dua alasan.
Pertama, makro yang perlu mengetahui jalur mana yang akan dipilih select
tidak dapat berfungsi
karena makro dievaluasi pada fase pemuatan Bazel,
yang terjadi sebelum nilai penanda diketahui.
Ini adalah batasan desain Bazel inti yang tidak mungkin berubah dalam waktu dekat.
Kedua, makro yang hanya perlu melakukan iterasi di semua jalur select
, meskipun
secara teknis memungkinkan, tidak memiliki UI yang koheren. Desain lebih lanjut diperlukan untuk mengubah
hal ini.
Kueri dan kueri Bazel
query
Bazel beroperasi melalui
fase pemuatan Bazel.
Artinya, build tidak mengetahui flag command line yang digunakan target karena
flag tersebut tidak dievaluasi hingga nanti dalam build (dalam
fase analisis).
Jadi, tidak dapat menentukan cabang select()
mana yang dipilih.
Bazel cquery
beroperasi setelah fase analisis Bazel, sehingga memiliki
semua informasi ini dan dapat me-resolve select()
secara akurat.
Pertimbangkan:
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
melebihi perkiraan dependensi :my_lib
:
$ bazel query 'deps(//myapp:my_lib)'
//myapp:my_lib
//myapp:foo_dep
//myapp:bar_dep
sementara cquery
menunjukkan dependensi persisnya:
$ bazel cquery 'deps(//myapp:my_lib)' --//myapp:dog_type=pug
//myapp:my_lib
//myapp:bar_dep
FAQ
Mengapa select() tidak berfungsi dalam makro?
select() berfungsi dalam aturan. Lihat Kompatibilitas aturan untuk mengetahui detailnya.
Masalah utama yang biasanya dimaksud dengan pertanyaan ini adalah bahwa select() tidak berfungsi di makro. Hal ini berbeda dengan aturan. Lihat dokumentasi tentang aturan dan makro untuk memahami perbedaannya. Berikut adalah contoh menyeluruh:
Tentukan aturan dan makro:
# 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)
Buat instance aturan dan makro:
# 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({
"//tools/target_cpu:x86": "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({
"//tools/target_cpu:x86": "first string",
"//third_party/bazel_platforms/cpu:ppc": "other string",
}),
)
Pembuatan gagal karena sad_macro
tidak dapat memproses 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.
Build berhasil jika Anda mengomentari 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.
Hal ini tidak mungkin diubah karena makro berdasarkan definisi dievaluasi sebelum Bazel membaca flag command line build. Artinya, tidak ada cukup informasi untuk mengevaluasi select().
Namun, makro dapat meneruskan select()
sebagai blob buram ke aturan:
# 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.
Mengapa select() selalu menampilkan true?
Karena makro (tetapi bukan aturan) menurut definisinya
tidak dapat mengevaluasi select()
, setiap upaya untuk melakukannya
biasanya akan menghasilkan error:
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().
Boolean adalah kasus khusus yang gagal secara diam-diam, jadi Anda harus waspada dengan mereka:
$ 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({
"//tools/target_cpu:x86": 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.
Hal ini terjadi karena makro tidak memahami konten select()
.
Jadi, yang benar-benar dievaluasi adalah objek select()
itu sendiri. Menurut
standar desain
Pythonic, semua objek selain sejumlah kecil pengecualian
otomatis menampilkan true.
Dapatkah saya membaca select() seperti kamus?
Makro tidak dapat mengevaluasi pilihan karena makro dievaluasi sebelum
Bazel mengetahui parameter command line build. Bisakah mereka setidaknya membaca
kamus select()
, misalnya, untuk menambahkan akhiran ke setiap nilai?
Secara konsep, hal ini dapat dilakukan, tetapi belum menjadi fitur Bazel.
Yang dapat Anda lakukan sekarang adalah menyiapkan kamus langsung, lalu memasukkannya ke dalam
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 = {
"//tools/target_cpu:x86": "x86 mode",
},
)
$ bazel build //testapp:selecty --cpu=x86 && cat bazel-genfiles/testapp/selecty.out
x86 mode WITH SUFFIX
Jika ingin mendukung select()
dan jenis native, Anda dapat melakukannya:
$ 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 + "> $@",
)
Mengapa select() tidak berfungsi dengan bind()?
Karena bind()
adalah aturan WORKSPACE, bukan aturan BUILD.
Aturan Workspace tidak memiliki konfigurasi khusus, dan tidak dievaluasi di
dengan cara yang sama seperti aturan BUILD. Oleh karena itu, select()
di bind()
tidak dapat
benar-benar dievaluasi ke
cabang tertentu.
Sebagai gantinya, Anda harus menggunakan alias()
, dengan select()
di
atribut actual
untuk melakukan jenis penentuan waktu proses ini. Hal ini
berfungsi dengan benar, karena alias()
adalah aturan BUILD, dan dievaluasi dengan
konfigurasi tertentu.
Anda bahkan dapat memiliki titik target bind()
ke alias()
, jika diperlukan.
$ 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",
}),
)
Dengan penyiapan ini, Anda dapat meneruskan --define ssl_library=alternative
, dan target apa pun
yang bergantung pada //:ssl
atau //external:ssl
akan melihat alternatif
yang terletak di @alternative//:ssl
.
Mengapa select() saya tidak memilih yang saya harapkan?
Jika //myapp:foo
memiliki select()
yang tidak memilih kondisi yang Anda harapkan,
gunakan cquery dan bazel config
untuk men-debug:
Jika //myapp:foo
adalah target tingkat teratas yang Anda build, jalankan:
$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)
Jika Anda mem-build beberapa target //bar
lain yang bergantung pada
//myapp:foo di suatu tempat dalam subgrafiknya, jalankan:
$ bazel cquery 'somepath(//bar, //myapp:foo)' <desired build flags>
//bar:bar (3ag3193fee94a2)
//bar:intermediate_dep (12e23b9a2b534a)
//myapp:foo (12e23b9a2b534a)
(12e23b9a2b534a)
di samping //myapp:foo
adalah hash dari konfigurasi yang me-resolve select()
//myapp:foo
. Anda dapat memeriksa nilainya
dengan 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]
...
}
...
Kemudian, bandingkan output ini dengan setelan yang diharapkan oleh setiap config_setting
.
//myapp:foo
mungkin berada di konfigurasi yang berbeda dalam build yang sama. Lihat
dokumen cquery untuk mendapatkan panduan tentang cara menggunakan somepath
untuk mendapatkan yang
tepat.
Mengapa select()
tidak berfungsi dengan platform?
Bazel tidak mendukung atribut yang dapat dikonfigurasi untuk memeriksa apakah platform tertentu adalah platform target karena semantiknya tidak jelas.
Contoh:
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": [],
}),
)
Dalam file BUILD
ini, select()
yang harus digunakan jika platform target memiliki
@platforms//cpu:x86
dan @platforms//os:linux
, tetapi bukan
:x86_linux_platform
ditentukan di sini? Penulis file BUILD
dan pengguna
yang mendefinisikan platform terpisah
mungkin memiliki gagasan yang berbeda.
Apa yang harus saya lakukan?
Sebagai gantinya, tentukan config_setting
yang cocok dengan platform mana pun dengan
batasan berikut:
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": [],
}),
)
Proses ini mendefinisikan semantik tertentu, sehingga lebih jelas bagi pengguna apa memenuhi kondisi yang diinginkan.
Bagaimana jika saya benar-benar ingin select
di platform?
Jika persyaratan build Anda secara khusus memerlukan pemeriksaan platform, Anda
dapat membalik nilai flag --platforms
di config_setting
:
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": [],
}),
)
Tim Bazel tidak mendukung tindakan ini; hal itu terlalu membatasi build Anda dan akan membingungkan pengguna jika kondisi yang diharapkan tidak cocok.