Atribut yang dapat dikonfigurasi, umumnya dikenal sebagai select()
, adalah fitur Bazel yang memungkinkan pengguna mengalihkan nilai
atribut aturan build di command line.
Ini dapat digunakan, misalnya, untuk library multiplatform yang otomatis memilih implementasi yang sesuai untuk arsitektur, atau untuk biner yang dapat dikonfigurasi fitur yang dapat disesuaikan pada waktu build.
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",
},
)
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 merujuk ke target
config_setting
. Dengan menggunakan select()
dalam atribut yang dapat dikonfigurasi, atribut tersebut
secara efektif mengadopsi nilai yang berbeda saat kondisi yang berbeda dipertahankan.
Kecocokan harus jelas: jika beberapa kondisi cocok, maka keduanya harus menyelesaikan nilai yang sama. Misalnya, saat berjalan di linux x86, ini tidak ambigu
{"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"}
karena kedua cabang diselesaikan menjadi "halo".
* values
adalah superset ketat dari semua produk lain. Misalnya, values = {"cpu": "x86", "compilation_mode": "dbg"}
adalah spesialisasi values = {"cpu": "x86"}
yang tidak ambigu.
Kondisi bawaan //conditions:default
otomatis cocok saat
tidak ada yang cocok.
Meskipun contoh ini menggunakan deps
, select()
juga berfungsi dengan baik di srcs
,
resources
, cmd
, dan sebagian besar atribut lainnya. Hanya sejumlah kecil atribut
yang tidak dapat dikonfigurasi, dan ini dijelaskan dengan jelas. Misalnya, atribut values
milik config_setting
tidak dapat dikonfigurasi.
select()
dan dependensi
Atribut tertentu mengubah parameter build untuk semua dependensi transitif
di bawah target. Misalnya, tools
genrule
mengubah --cpu
ke CPU
mesin yang menjalankan Bazel (yang, berkat kompilasi silang, mungkin berbeda
dengan CPU yang dibuat untuk target tersebut). 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"],
}),
)
sedang berjalan
$ bazel build //myapp:my_genrule --cpu=arm
pada mesin developer x86
mengikat build ke g_arm.src
, tool1
, dan
x86tool.cc
. Kedua select
yang dilampirkan ke my_genrule
menggunakan parameter build my_genrule
, yang mencakup --cpu=arm
. Atribut tools
mengubah
--cpu
menjadi x86
untuk tool1
dan dependensi transitifnya. select
pada
tool1
menggunakan parameter build tool1
, yang mencakup --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 mengenkapsulasi ini dalam target, mudah untuk mempertahankan kondisi "standar" yang dapat direferensikan pengguna dari beberapa tempat.
constraint_value
memberikan dukungan untuk perilaku multi-platform.
Flag bawaan
Flag seperti --cpu
di-build ke dalam Bazel: alat build secara native memahaminya untuk semua build di semua project. Atribut ini ditentukan dengan
atribut values
config_setting
:
config_setting(
name = "meaningful_condition_name",
values = {
"flag1": "value1",
"flag2": "value2",
...
},
)
flagN
adalah nama flag (tanpa --
, jadi "cpu"
bukan "--cpu"
). valueN
adalah nilai yang diharapkan untuk flag 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 progres laporan Bazel untuk pengguna. Target tidak dapat menggunakan flag tersebut untuk membuat hasilnya. Kumpulan flag yang didukung secara persis tidak didokumentasikan. Dalam praktiknya, sebagian besar tanda yang "masuk akal" berfungsi.
Tanda kustom
Anda dapat membuat model flag khusus project dengan setelan build Starlark. Tidak seperti flag bawaan, flag ini ditentukan sebagai target build, sehingga Bazel mereferensikannya dengan label target.
Peristiwa ini dipicu dengan atribut
flag_values
config_setting
:
config_setting(
name = "meaningful_condition_name",
flag_values = {
"//myflags:flag1": "value1",
"//myflags:flag2": "value2",
...
},
)
Perilakunya sama seperti tanda bawaan. Lihat di sini untuk mengetahui contoh yang berfungsi.
--define
adalah sintaksis lama alternatif untuk flag kustom (misalnya
--define foo=bar
). Ini dapat dinyatakan dalam
atribut values
(values = {"define": "foo=bar"}
) atau atribut
define_values
(define_values = {"foo": "bar"}
). --define
hanya didukung untuk kompatibilitas
mundur. Pilih setelan build Starlark jika memungkinkan.
values
, flag_values
, dan define_values
mengevaluasi secara independen. config_setting
cocok jika semua nilai di semuanya cocok.
Kondisi default
Kondisi bawaan //conditions:default
cocok jika tidak ada kondisi lain yang cocok.
Karena aturan "tepat satu kecocokan", atribut yang dapat dikonfigurasi tanpa kecocokan dan tidak ada kondisi default akan menghasilkan error "no matching conditions"
. Langkah 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 error yang lebih jelas lagi, Anda dapat menetapkan pesan kustom dengan atribut no_match_error
select()
.
Platform
Meskipun kemampuan untuk menentukan beberapa flag pada command line memberikan fleksibilitas, penetapan setiap flag juga mungkin akan sulit setiap kali Anda ingin mem-build target. Platform memungkinkan Anda menggabungkannya ke dalam 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 pada command line. Metode ini mengaktifkan
config_setting
yang berisi subset constraint_values
platform,
yang memungkinkan config_setting
tersebut dicocokkan dalam ekspresi select()
.
Misalnya, untuk menyetel atribut srcs
dari my_rocks
ke calcite.sh
,
Anda dapat menjalankan
bazel build //my_app:my_rocks --platforms=//myapp:marble_platform
Tanpa platform, tampilannya mungkin terlihat seperti ini
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"],
}),
)
Dengan begitu, kebutuhan terhadap boilerplate config_setting
tidak diperlukan saat Anda hanya
perlu memeriksa nilai tunggal.
Platform masih dalam pengembangan. Lihat dokumentasi untuk mengetahui detailnya.
Menggabungkan select()
select
dapat muncul beberapa kali di 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
lainnya. Jika Anda perlu menyarangkan 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 rantai DAN.
Perantaian ATAU
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 bernilai sesuai dependensi yang sama. Namun, sintaksis ini sulit dibaca dan dikelola. Sebaiknya Anda tidak perlu mengulangi [":standard_lib"]
beberapa
kali.
Salah satu opsinya adalah menentukan terlebih dahulu nilai 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. Namun, metode ini tetap menyebabkan duplikasi yang tidak perlu.
Untuk mendapatkan dukungan langsung lebih lanjut, gunakan salah satu hal berikut:
selects.with_or
Makro
with_or
dalam modul
selects
Skylib mendukung kondisi OR
ing langsung 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
dalam modul selects
Skylib mendukung OR
ing 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
di seluruh atribut yang berbeda.
Ini adalah error jika ada beberapa kondisi yang cocok, kecuali salah satunya adalah "spesialisasi" yang tidak ambigu dari yang lain atau semuanya diselesaikan ke nilai yang sama. Lihat di sini untuk mengetahui detailnya.
DAN rantai
Jika Anda memerlukan cabang select
untuk dicocokkan 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 perantaian, config_setting
yang ada tidak dapat langsung 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 select()
akan dilampirkan
ke kegagalan 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
Atribut 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
Implementasi aturan menerima nilai yang diselesaikan dari atribut 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 klausa select()
dan meneruskannya ke aturan
native. Namun, mereka tidak dapat memanipulasinya secara langsung. Misalnya, makro tidak dapat dikonversi
select({"foo": "val"}, ...)
hingga
select({"foo": "val_with_suffix"}, ...)
Hal ini disebabkan oleh dua alasan.
Pertama, makro yang perlu mengetahui jalur mana yang akan dipilih select
tidak dapat berfungsi karena makro dievaluasi dalam fase pemuatan Bazel, yang terjadi sebelum nilai flag diketahui.
Ini adalah batasan desain Bazel inti yang kemungkinan tidak akan berubah dalam waktu dekat.
Kedua, makro yang hanya perlu melakukan iterasi pada semua jalur select
, meskipun secara teknis dapat dilakukan, tidak memiliki UI yang koheren. Desain lebih lanjut diperlukan untuk mengubahnya.
Kueri Bazel dan cquery
Bazel query
beroperasi selama
fase pemuatan Bazel.
Artinya, fungsi tidak mengetahui flag command line apa yang digunakan oleh target karena flag tersebut tidak dievaluasi sampai nanti dalam build (dalam fase analisis).
Jadi, aplikasi tidak dapat menentukan cabang select()
mana yang dipilih.
Bazel cquery
beroperasi setelah fase analisis Bazel, sehingga memiliki
semua informasi ini dan dapat menyelesaikan 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 di makro?
select() berfungsi dalam aturan! Lihat Kompatibilitas aturan untuk mengetahui detailnya.
Masalah utama yang biasanya disebabkan oleh pertanyaan ini adalah bahwa select() tidak berfungsi di makro. Aturan 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",
}),
)
Pembangunan 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.
Pembuatan berhasil saat Anda memberi komentar pada 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 nilai benar?
Karena makro (tetapi bukan aturan) menurut definisi
tidak dapat mengevaluasi select()
, setiap upaya untuk melakukannya
biasanya 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 tanpa ada peringatan, jadi Anda harus sangat waspada terhadapnya:
$ 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, objek yang benar-benar dievaluasi adalah objek select()
itu sendiri. Menurut standar desain Pythonic, semua objek selain sejumlah kecil pengecualian secara otomatis menampilkan nilai benar.
Dapatkah saya membaca select() seperti dict?
Makro tidak dapat mengevaluasi pilihan karena makro dievaluasi sebelum
Bazel mengetahui parameter command line build. Bisakah mereka membaca setidaknya kamus select()
, misalnya, untuk menambahkan akhiran ke setiap nilai?
Secara konseptual, fitur ini memungkinkan, tetapi belum menjadi fitur Bazel.
Yang dapat Anda lakukan sekarang adalah menyiapkan kamus langsung, lalu memasukkannya ke
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 jenis native dan select()
, 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 binding()?
Karena bind()
adalah aturan WORKSPACE, bukan aturan BUILD.
Aturan Workspace tidak memiliki konfigurasi tertentu, dan tidak dievaluasi dengan cara yang sama seperti aturan BUILD. Oleh karena itu, select()
dalam bind()
sebenarnya tidak dapat dievaluasi ke cabang tertentu.
Sebagai gantinya, Anda harus menggunakan alias()
, dengan select()
dalam
atribut actual
, untuk melakukan jenis penentuan runtime ini. Ini berfungsi dengan benar, karena alias()
adalah aturan BUILD, dan dievaluasi dengan konfigurasi tertentu.
Anda bahkan dapat memiliki bind()
target poin 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 apa yang saya harapkan?
Jika //myapp:foo
memiliki select()
yang tidak memilih kondisi yang Anda harapkan,
gunakan cquery dan bazel config
untuk melakukan debug:
Jika //myapp:foo
adalah target tingkat atas yang Anda buat, jalankan:
$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)
Jika Anda membuat //bar
target lain yang bergantung pada
//myapp:foo di suatu tempat di 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 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]
...
}
...
Lalu bandingkan output ini dengan setelan yang diharapkan oleh setiap config_setting
.
//myapp:foo
mungkin ada dalam konfigurasi yang berbeda-beda pada build yang sama. Lihat
dokumen cquery untuk panduan penggunaan somepath
guna mendapatkan dokumen
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()
mana yang harus digunakan jika platform target memiliki batasan
@platforms//cpu:x86
dan @platforms//os:linux
, tetapi bukan
:x86_linux_platform
yang ditentukan di sini? Penulis file BUILD
dan pengguna yang menentukan platform terpisah mungkin memiliki ide yang berbeda.
Apa yang harus saya lakukan?
Sebagai gantinya, tentukan config_setting
yang cocok dengan platform apa 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 menentukan semantik tertentu, memperjelas kepada pengguna platform apa yang memenuhi kondisi yang diinginkan.
Bagaimana jika saya benar-benar ingin select
di platform ini?
Jika persyaratan build Anda secara khusus mengharuskan pemeriksaan platform, Anda
dapat membalikkan nilai flag --platforms
dalam 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 ini terlalu membatasi build dan membingungkan pengguna saat kondisi yang diharapkan tidak cocok.