Los atributos configurables, comúnmente conocidos como select()
, son una función de Bazel que permite a los usuarios activar o desactivar los valores.
de atributos de reglas de compilación en la línea de comandos.
Se puede usar, por ejemplo, para una biblioteca multiplataforma que que elija la implementación adecuada para la arquitectura binario configurable por atributos que se puede personalizar en el tiempo de compilación.
Ejemplo
# 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",
},
)
De esta manera, se declara un cc_binary
que "elige" sus dependencias en función de las marcas del
la línea de comandos. Específicamente, deps
se convierte en lo siguiente:
Comando | dependencias = |
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()
sirve como marcador de posición para un valor que se elegirá en función de lo siguiente:
condiciones de configuración, que son etiquetas que hacen referencia a config_setting
objetivos. Cuando usas select()
en un atributo configurable, el atributo
adopta con eficacia diferentes valores cuando se cumplen diferentes condiciones.
Las coincidencias no deben ser ambiguas: si hay varias condiciones que coinciden,
* Todas se resuelven con el mismo valor. Por ejemplo, cuando se ejecuta en Linux x86, no hay ambigüedades.
{"@platforms//os:linux": "Hello", "@platforms//cpu:x86_64": "Hello"}
porque ambas ramas se resuelven en “hello”.
* El values
de uno es un superconjunto estricto de todos los demás. Por ejemplo, values = {"cpu": "x86", "compilation_mode": "dbg"}
.
es una especialización inequívoca de values = {"cpu": "x86"}
.
La condición integrada //conditions:default
coincide automáticamente cuando
nada más.
Si bien en este ejemplo se usa deps
, select()
funciona igual de bien en srcs
,
resources
, cmd
y la mayoría de los demás atributos. Solo una pequeña cantidad de atributos
no son configurables y están anotadas de forma clara. Por ejemplo:
De config_setting
El atributo values
no se puede configurar.
select()
y dependencias
Ciertos atributos cambian los parámetros de compilación para todas las dependencias transitivas
en un objetivo. Por ejemplo, tools
de genrule
cambia --cpu
a la CPU de
la máquina que ejecuta Bazel (que, gracias a la compilación cruzada, puede ser diferente
que la CPU para la que está construido el destino). Esto se conoce como
transición de configuración.
Proporcionado
#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"],
}),
)
activo
$ bazel build //myapp:my_genrule --cpu=arm
En una máquina de desarrollador de x86
, vincula la compilación a g_arm.src
, tool1
y
x86tool.cc
Ambos select
adjuntos a my_genrule
usan my_genrule
.
parámetros de compilación, que incluyen --cpu=arm
. Cambia el atributo tools
--cpu
a x86
para tool1
y sus dependencias transitivas. El select
en
tool1
usa los parámetros de compilación de tool1
, que incluyen --cpu=x86
.
Condiciones de configuración
Cada clave de un atributo configurable es una referencia de etiqueta a un
config_setting
o
constraint_value
config_setting
es solo una colección de
la configuración esperada de la marca de línea de comandos. Cuando se encapsulan en un objetivo,
fácil de mantener “estándar” condiciones a las que los usuarios pueden consultar desde varios lugares.
constraint_value
proporciona compatibilidad con el comportamiento multiplataforma.
Funciones experimentales integradas
Las marcas como --cpu
están integradas en Bazel: la herramienta de compilación comprende de forma nativa
para las compilaciones de todos los proyectos. Se especifican con
De config_setting
Atributo values
:
config_setting(
name = "meaningful_condition_name",
values = {
"flag1": "value1",
"flag2": "value2",
...
},
)
flagN
es el nombre de una marca (sin --
, por lo que "cpu"
en lugar de "--cpu"
). valueN
es el valor esperado para esa marca. :meaningful_condition_name
coincide si
todas las entradas de values
coinciden. El orden es irrelevante.
valueN
se analiza como si se hubiera establecido en la línea de comandos. Esto significa lo siguiente:
values = { "compilation_mode": "opt" }
coincide conbazel build -c opt
values = { "force_pic": "true" }
coincide conbazel build --force_pic=1
values = { "force_pic": "0" }
coincide conbazel build --noforce_pic
config_setting
solo admite marcas que afectan el comportamiento objetivo. Por ejemplo:
--show_progress
no se permite porque
solo afecta la forma en que Bazel informa el progreso al usuario. Los destinos no pueden usar esa opción
para construir sus resultados. El conjunto exacto de marcas admitidas
documentados. En la práctica, la mayoría de las marcas que "tienen sentido" el trabajo.
Marcas personalizadas
Puedes modelar tus propias marcas específicas del proyecto con Configuración de compilación de Starlark. A diferencia de los indicadores integrados, estos son definidos como destinos de compilación, por lo que Bazel hace referencia a ellos con etiquetas de destino.
Se activan con los atributos config_setting
flag_values
atributo:
config_setting(
name = "meaningful_condition_name",
flag_values = {
"//myflags:flag1": "value1",
"//myflags:flag2": "value2",
...
},
)
El comportamiento es el mismo que el de las marcas integradas. Ver aquí para ver un ejemplo funcional.
--define
es una sintaxis heredada alternativa para las marcas personalizadas (por ejemplo,
--define foo=bar
). Esto se puede expresar en el
atributo values
(values = {"define": "foo=bar"}
) o en
Atributo define_values
(define_values = {"foo": "bar"}
). --define
solo es compatible con versiones anteriores
compatibilidad. Se prefiere la configuración de compilación de Starlark siempre que sea posible.
values
, flag_values
y define_values
se evalúan de forma independiente. El
config_setting
coincide si todos los valores de todos coinciden.
La condición predeterminada
La condición integrada //conditions:default
coincide cuando no hay ninguna otra condición.
coincidencias.
Por la coincidencia "exactamente una coincidencia" regla, un atributo configurable sin coincidencias
y ninguna condición predeterminada emite un error "no matching conditions"
. Esto puede
Proteger contra fallas silenciosas de configuraciones inesperadas:
# 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
Para errores aún más claros, puedes configurar mensajes personalizados con la política de select()
no_match_error
.
Plataformas
Si bien la capacidad de especificar varias marcas en la línea de comandos proporciona Además, puede ser agotador establecer cada uno individualmente cada vez en las que quieres crear un objetivo. Plataformas te permiten consolidarlos en paquetes simples.
# 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",
],
)
Se puede especificar la plataforma en la línea de comandos. Activa la
config_setting
que contienen un subconjunto de constraint_values
de la plataforma
lo que permite que esos config_setting
coincidan en expresiones select()
.
Por ejemplo, para establecer el atributo srcs
de my_rocks
en calcite.sh
, haz lo siguiente:
puedes simplemente ejecutar
bazel build //my_app:my_rocks --platforms=//myapp:marble_platform
Sin plataformas, esto podría parecerse a
bazel build //my_app:my_rocks --define color=white --define texture=smooth --define type=metamorphic
select()
también puede leer directamente 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"],
}),
)
Esto ahorra la necesidad de config_setting
estándares cuando solo necesitas
verificar con valores únicos.
Las plataformas aún están en desarrollo. Consulta la documentación para obtener más información.
Combinación de select()
select
puede aparecer varias veces en el mismo atributo:
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
no puede aparecer dentro de otro select
. Si necesitas anidar selects
Si el atributo toma otros objetivos como valores, usa un objetivo intermedio:
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"],
...
}),
)
Si necesitas un select
para que coincida cuando varias condiciones coinciden, considera Y
encadenamiento.
OR encadenamiento
Ten en cuenta lo siguiente:
sh_binary(
name = "my_target",
srcs = ["always_include.sh"],
deps = select({
":config1": [":standard_lib"],
":config2": [":standard_lib"],
":config3": [":standard_lib"],
":config4": [":special_lib"],
}),
)
La mayoría de las condiciones se evalúan como la misma dependencia. Pero esta sintaxis es difícil de leer y
mantener. Sería bueno no tener que repetir [":standard_lib"]
varias veces.
veces.
Una opción es predefinir el valor como una variable de COMPILACIÓN:
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"],
}),
)
Esto facilita la administración de la dependencia. Pero aun así genera causas la duplicación.
Para obtener asistencia más directa, usa una de las siguientes opciones:
selects.with_or
El
with_or
en una macro de Skylib
selects
El módulo admite condiciones de OR
ing directamente en un 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
El
config_setting_group
en una macro de Skylib
selects
El módulo admite OR
varias 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"],
}),
)
A diferencia de selects.with_or
, diferentes objetivos pueden compartir :config1_or_2
en
diferentes atributos.
Es un error de coincidencia de varias condiciones, a menos que una de ellas no sea ambigua "especialización" de las demás o todas se resuelven con el mismo valor. Consulta los detalles aquí.
Encadenamiento AND
Si necesitas que una rama select
coincida cuando varias condiciones coincidan, usa
Macro 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"],
}),
)
A diferencia del encadenamiento OR, los elementos config_setting
existentes no se pueden AND
de forma directa
dentro de un select
. Debes unirlos de manera explícita en una config_setting_group
.
Mensajes de error personalizados
De forma predeterminada, cuando ninguna condición coincide, se adjunta el destino al que se adjunta select()
.
falla con el siguiente 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
Se puede personalizar con no_match_error
.
atributo:
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
Compatibilidad de las reglas
Las implementaciones de reglas reciben los valores resueltos de las reglas atributos. Por ejemplo:
# myapp/BUILD
some_rule(
name = "my_target",
some_attr = select({
":foo_mode": [":foo"],
":bar_mode": [":bar"],
}),
)
$ bazel build //myapp/my_target --define mode=foo
El código de implementación de reglas ve ctx.attr.some_attr
como [":foo"]
.
Las macros pueden aceptar cláusulas select()
y pasarlas a aplicaciones nativas
las reglas de firewall. Sin embargo, no pueden manipularlas directamente. Por ejemplo, no hay manera
para que una macro convierta
select({"foo": "val"}, ...)
para
select({"foo": "val_with_suffix"}, ...)
Esto es por dos razones.
Primero, las macros que necesitan saber qué ruta elegirá un select
no funcionan
porque las macros se evalúan en la fase de carga de Bazel
que ocurre antes de que se conozcan
los valores de las marcas.
Esta es una restricción de diseño principal de Bazel que es poco probable que cambie pronto.
En segundo lugar, las macros que solo necesitan iterar en todas las rutas de acceso select
, mientras que
técnicamente factible, carecer de una IU coherente. Se necesita más diseño para cambiar
esto.
Consulta y cquery de Bazel
Bazel query
opera sobre la base de datos
fase de carga.
Esto significa que no sabe qué marcas de línea de comandos usa un destino, ya que
no se evalúan hasta más adelante en la compilación (en el
fase de análisis).
Por lo tanto, no puede determinar qué ramas de select()
se eligen.
Bazel cquery
funciona después de la fase de análisis de Bazel, por lo que tiene
toda esta información y puede resolver con precisión select()
s.
Considera:
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
supera las dependencias de :my_lib
:
$ bazel query 'deps(//myapp:my_lib)'
//myapp:my_lib
//myapp:foo_dep
//myapp:bar_dep
mientras que cquery
muestra sus dependencias exactas:
$ bazel cquery 'deps(//myapp:my_lib)' --//myapp:dog_type=pug
//myapp:my_lib
//myapp:bar_dep
Preguntas frecuentes
¿Por qué select() no funciona en macros?
select() funciona en las reglas. Consulta Compatibilidad de reglas para obtener más detalles.
El problema clave que suele significar esta pregunta es que select() no funciona en macros. Estas son diferentes de las reglas. Consulta la documentación sobre reglas y macros para entender la diferencia. A continuación, se muestra un ejemplo completo:
Define una regla y una macro:
# 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)
Crea una instancia de la regla y la macro:
# 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",
}),
)
La compilación falla porque sad_macro
no puede procesar el 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.
La compilación se realiza de forma correcta cuando marcas como comentario 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.
Esto es imposible de cambiar porque las macros por definición se evalúan antes Bazel lee las marcas de línea de comandos de la compilación. Eso significa que no hay suficiente información para evaluar select()s.
Sin embargo, las macros pueden pasar objetos select()
como BLOB opacos a las reglas:
# 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.
¿Por qué select() siempre muestra el resultado verdadero?
Porque son macros (pero no reglas) por definición
no se pueden evaluar las select()
, ningún intento de hacerlo
suele producir un 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().
Los booleanos son un caso especial que fallan silenciosamente, así que deberías ser estén atentos:
$ 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.
Esto sucede porque las macros no comprenden el contenido de select()
.
Por lo tanto, lo que realmente evalúan es el objeto select()
en sí. Según
Diseño Python
estándares, todos los objetos, excepto una pequeña cantidad de excepciones
devuelven automáticamente el valor true.
¿Puedo leer select() como un dict?
Las macros no pueden evaluar selecciones porque lo hacen antes
Bazel sabe cuáles son los parámetros de la línea de comandos de la compilación. ¿Pueden al menos leer
el diccionario de select()
para, por ejemplo, agregar un sufijo a cada valor?
Conceptualmente, esto es posible, pero todavía no es una función de Bazel.
Lo que puedes hacer hoy es preparar un diccionario directo y, luego, incorporarlo en un
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
Si deseas admitir tipos nativos y de select()
, puedes hacer lo siguiente:
$ 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 + "> $@",
)
¿Por qué select() no funciona con bind()?
Debido a que bind()
es una regla de WORKSPACE, no una de BUILD.
Las reglas de Workspace no tienen una configuración específica y no se evalúan en
del mismo modo que las reglas de COMPILACIÓN. Por lo tanto, un select()
en una bind()
no puede
evaluar en cualquier rama específica.
En cambio, debes usar alias()
, con un select()
en
El atributo actual
para realizar este tipo de determinación del tiempo de ejecución Esta
funciona correctamente, ya que alias()
es una regla de COMPILACIÓN y se evalúa con un
configuración específica.
Incluso puedes tener un punto de destino bind()
a un alias()
, si es necesario.
$ 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",
}),
)
Con esta configuración, puedes pasar --define ssl_library=alternative
y cualquier objetivo
que dependa de //:ssl
o //external:ssl
verán la alternativa
ubicado en @alternative//:ssl
.
¿Por qué mi select() no elige lo que espero?
Si //myapp:foo
tiene un select()
que no elige la condición que esperas,
Usa cquery y bazel config
para depurar:
Si //myapp:foo
es el objetivo de nivel superior que estás compilando, ejecuta lo siguiente:
$ bazel cquery //myapp:foo <desired build flags>
//myapp:foo (12e23b9a2b534a)
Si quieres compilar otro //bar
de destino que dependa de
//myapp:foo en alguna parte de su subgrafo ejecuta:
$ bazel cquery 'somepath(//bar, //myapp:foo)' <desired build flags>
//bar:bar (3ag3193fee94a2)
//bar:intermediate_dep (12e23b9a2b534a)
//myapp:foo (12e23b9a2b534a)
El (12e23b9a2b534a)
junto a //myapp:foo
es un hash del
de Terraform que resuelve el select()
de //myapp:foo
. Puedes inspeccionar su
valores con 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]
...
}
...
Luego, compara este resultado con la configuración que espera cada config_setting
.
//myapp:foo
puede existir en diferentes configuraciones en la misma compilación. Consulta la
documentos de cquery para obtener orientación sobre cómo usar somepath
para hacer lo correcto
uno.
¿Por qué select()
no funciona con plataformas?
Bazel no admite atributos configurables que verifiquen si una plataforma determinada. es la plataforma de destino porque la semántica no es clara.
Por ejemplo:
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": [],
}),
)
En este archivo BUILD
, que select()
debe usarse si la plataforma de destino tiene
@platforms//cpu:x86
y @platforms//os:linux
, pero no es la
¿:x86_linux_platform
se definió aquí? El autor del archivo BUILD
y el usuario
que definió la plataforma independiente
pueden tener ideas diferentes.
¿Qué otra opción debería usar?
En cambio, define un config_setting
que coincida con cualquier plataforma con
estas restricciones:
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": [],
}),
)
Este proceso define una semántica específica y aclara a los usuarios qué plataformas cumplan con las condiciones deseadas.
¿Qué sucede si de verdad quiero select
en la plataforma?
Si tus requisitos de compilación requieren específicamente que verifiques la plataforma, puedes
Se puede cambiar el valor de la marca --platforms
en un 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": [],
}),
)
El equipo de Bazel no recomienda hacer esto; limita demasiado la compilación y confunde a los usuarios cuando la condición esperada no coincide.