Los grupos de ejecución permiten varias plataformas de ejecución dentro de un solo objetivo. Cada grupo de ejecución tiene sus propias dependencias de cadena de herramientas y realiza su propia resolución de cadena de herramientas.
Fondo
Los grupos de ejecución permiten que el autor de la regla defina conjuntos de acciones, cada uno con una plataforma de ejecución potencialmente diferente. Varias plataformas de ejecución pueden permitir que las acciones se ejecuten de manera diferente, por ejemplo, compilar una app para iOS en un trabajador remoto (Linux) y, luego, vincular o firmar el código en un trabajador local de Mac.
La capacidad de definir grupos de acciones también ayuda a aliviar el uso de mnemónicos de acción como proxy para especificar acciones. No se garantiza que los mnemónicos sean únicos y solo pueden hacer referencia a una sola acción. Esto es especialmente útil para asignar recursos adicionales a acciones específicas de memoria y procesamiento intensivo, como la vinculación en compilaciones de C++, sin asignar en exceso a tareas menos exigentes.
Cómo definir grupos de ejecución
Durante la definición de reglas, los autores de reglas pueden
declarar
un conjunto de grupos de ejecución. En cada grupo de ejecución, el autor de la regla puede especificar todo lo necesario para seleccionar una plataforma de ejecución para ese grupo de ejecución, es decir, cualquier restricción a través de exec_compatible_with y tipos de cadena de herramientas a través de toolchain.
# foo.bzl
my_rule = rule(
_impl,
exec_groups = {
“link”: exec_group(
exec_compatible_with = [ "@platforms//os:linux" ]
toolchains = ["//foo:toolchain_type"],
),
“test”: exec_group(
toolchains = ["//foo_tools:toolchain_type"],
),
},
attrs = {
"_compiler": attr.label(cfg = config.exec("link"))
},
)
En el fragmento de código anterior, puedes ver que las dependencias de herramientas también pueden especificar
la transición para un grupo de ejecución con el
cfg
parámetro de atributo y el
config
módulo. El módulo expone una función exec que toma un solo parámetro de cadena, que es el nombre del grupo de ejecución para el que se debe compilar la dependencia.
Al igual que en las reglas nativas, el grupo de ejecución test está presente de forma predeterminada en las reglas de prueba de Starlark.
Herencia del grupo de ejecución
Además de definir sus propias restricciones y cadenas de herramientas, un nuevo grupo de ejecución puede declarar que desea heredar del grupo de ejecución predeterminado de la regla pasando el parámetro copy_from_rule = True. Es un error establecer copy_from_rule como verdadero y también pasar exec_compatible_with o toolchains.
Un grupo de ejecución que hereda del grupo de ejecución predeterminado copia las restricciones, las cadenas de herramientas y las propiedades de ejecución del valor predeterminado. Esto incluye las restricciones y las propiedades de ejecución establecidas en el nivel de destino, no solo las especificadas por la regla. En otras palabras, dado lo siguiente:
# foo.bzl
my_rule = rule(
_impl,
exec_groups = {
“copied”: exec_group(
copy_from_rule = True,
# This will inherit exec_compatible_with and toolchains.
# Setting them here directly would be an error, however.
),
},
toolchains = ["//foo_tools:toolchain_type"],
exec_compatible_with = ["@platforms//os:linux"],
)
# BUILD
my_rule(
name = "demo",
exec_compatible_with = [":local_constraint"],
)
El grupo de ejecución copied para el destino configurado demo incluirá todo lo siguiente:
- //fool_tools:toolchain_type
- @platforms//os:linux
- :local_constraint
Cómo acceder a los grupos de ejecución
En la implementación de la regla, puedes declarar que las acciones se deben ejecutar en la plataforma de ejecución de un grupo de ejecución. Para ello, usa el exec_group
parámetro de los métodos de generación de acciones, específicamente ctx.actions.run y
ctx.actions.run_shell.
# foo.bzl
def _impl(ctx):
ctx.actions.run(
inputs = [ctx.attr._some_tool, ctx.srcs[0]]
exec_group = "compile",
# ...
)
Los autores de reglas también podrán acceder a las cadenas de herramientas resueltas de los grupos de ejecución, de manera similar a como tú puedes acceder a la cadena de herramientas resuelta de un destino:
# foo.bzl
def _impl(ctx):
foo_info = ctx.exec_groups["link"].toolchains["//foo:toolchain_type"].fooinfo
ctx.actions.run(
inputs = [foo_info, ctx.srcs[0]]
exec_group = "link",
# ...
)
Cómo usar grupos de ejecución para establecer propiedades de ejecución
Los grupos de ejecución se integran con el
exec_properties
atributo que existe en cada regla y permite que el escritor de destino especifique un
diccionario de cadenas de propiedades que luego se pasa a la maquinaria de ejecución. Por ejemplo, si deseas establecer alguna propiedad, como la memoria, para el destino y asignar una mayor asignación de memoria a ciertas acciones, escribirías una entrada exec_properties con una clave aumentada del grupo de ejecución, como la siguiente:
# BUILD
my_rule(
name = 'my_target',
exec_properties = {
'mem': '12g',
'link.mem': '16g'
}
…
)
Todas las acciones con exec_group = "link" verían el diccionario de propiedades de ejecución
como {"mem": "16g"}. Como puedes ver aquí, la configuración a nivel del grupo de ejecución anula la configuración a nivel del destino.
Grupos de ejecución para reglas nativas
Los siguientes grupos de ejecución están disponibles para las acciones definidas por reglas nativas:
test: Acciones del ejecutor de pruebascpp_link: Acciones de vinculación de C++
Cómo crear grupos de ejecución para establecer propiedades de ejecución
A veces, deseas usar un grupo de ejecución para asignar diferentes propiedades de ejecución a acciones específicas, pero no deseas cadenas de herramientas ni restricciones diferentes a las de la regla. En estas situaciones, puedes crear grupos de ejecución con el parámetro copy_from_rule:
# foo.bzl
# Creating an exec group with `copy_from_rule=True` is the same as explicitly
# setting the exec group's toolchains and constraints to the same values as the
# rule's respective parameters.
my_rule = rule(
_impl,
exec_compatible_with = ["@platforms//os:linux"],
toolchains = ["//foo:toolchain_type"],
exec_groups = {
# The following two groups have the same toolchains and constraints:
“foo”: exec_group(copy_from_rule = True),
"bar": exec_group(
exec_compatible_with = ["@platforms//os:linux"],
toolchains = ["//foo:toolchain_type"],
),
},
)
#
Grupos de ejecución y propiedades de ejecución de la plataforma
Es posible definir exec_properties para grupos de ejecución arbitrarios en destinos de plataforma (a diferencia de exec_properties establecidos directamente en un destino, en el que se rechazan las propiedades de grupos de ejecución desconocidos). Luego, los destinos heredan las exec_properties de la plataforma de ejecución que afectan al grupo de ejecución predeterminado y a cualquier otro grupo de ejecución pertinente.
Por ejemplo, supongamos que ejecutar una prueba de C++ requiere que haya algún recurso disponible, pero no es necesario para compilar y vincular. Esto se puede modelar de la siguiente manera:
constraint_setting(name = "resource")
constraint_value(name = "has_resource", constraint_setting = ":resource")
platform(
name = "platform_with_resource",
constraint_values = [":has_resource"],
exec_properties = {
"test.resource": "...",
},
)
cc_test(
name = "my_test",
srcs = ["my_test.cc"],
exec_compatible_with = [":has_resource"],
)
Las exec_properties definidas directamente en los destinos tienen prioridad sobre las que se heredan de la plataforma de ejecución.