Os grupos de execução permitem várias plataformas de execução em um único destino. Cada grupo de execução tem suas próprias dependências de toolchain e executa a própria resolução de toolchain.
Contexto
Os grupos de execução permitem que o autor da regra defina conjuntos de ações, cada um com uma plataforma de execução potencialmente diferente. Várias plataformas de execução podem permitir que as ações sejam executadas de maneira diferente, por exemplo, compilando um app iOS em um worker remoto (Linux) e vinculando/assinando o código em um worker local do Mac.
A capacidade de definir grupos de ações também ajuda a aliviar o uso de mnemônicos de ação como um substituto para especificar ações. Não há garantia de que as mnemônicas sejam exclusivas e só podem fazer referência a uma única ação. Isso é especialmente útil para alocar recursos extras para ações específicas de memória e processamento como a vinculação em builds C++ sem alocar demais para tarefas menos exigentes.
Como definir grupos de execução
Durante a definição de regras, os autores podem
declare
um conjunto de grupos de execução. Em cada grupo de execução, o autor da regra pode especificar
tudo o que for necessário para selecionar uma plataforma de execução para esse grupo,
ou seja, qualquer restrição usando exec_compatible_with
e tipos de conjunto de ferramentas usando
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"))
},
)
No snippet de código acima, é possível ver que as dependências de ferramentas também podem especificar
a transição de um grupo de execução usando o parâmetro de atributo
cfg
e o módulo
config
. O módulo expõe uma função exec
que usa um único parâmetro de string,
que é o nome do grupo de execução para o qual a dependência precisa ser
criada.
Como nas regras nativas, o grupo de execução test
está presente por padrão nas regras de teste
do Starlark.
Herança de grupos de execução
Além de definir as próprias restrições e toolchains, um novo grupo de execução
pode declarar que quer herdar do grupo de execução padrão da regra
transmitindo o parâmetro copy_from_rule = True
. É um erro definir
copy_from_rule
como verdadeiro e também transmitir exec_compatible_with
ou
toolchains
.
Um grupo de execução que herda do grupo de execução padrão copia restrições, toolchains e propriedades de execução do padrão. Isso inclui restrições e propriedades de execução definidas no nível de destino, não apenas aquelas especificadas pela própria regra. Em outras palavras, considerando o seguinte:
# 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"],
)
O grupo de execução copied
para o destino configurado demo
vai incluir todos
os seguintes itens:
- //fool_tools:toolchain_type
- @platforms//os:linux
- :local_constraint
Acessar grupos de execução
Na implementação da regra, é possível declarar que as ações precisam ser executadas na
plataforma de execução de um grupo de execução. Para fazer isso, use o parâmetro exec_group
dos métodos de geração de ação, especificamente ctx.actions.run
e
ctx.actions.run_shell
.
# foo.bzl
def _impl(ctx):
ctx.actions.run(
inputs = [ctx.attr._some_tool, ctx.srcs[0]]
exec_group = "compile",
# ...
)
Os autores de regras também poderão acessar as toolchains resolvidas dos grupos de execução, de forma semelhante a como é possível acessar a toolchain resolvida de um 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",
# ...
)
Usar grupos de execução para definir propriedades de execução
Os grupos de execução são integrados ao atributo
exec_properties
que existe em todas as regras e permitem que o gravador de destino especifique um
dict de string de propriedades que é transmitido para o maquinário de execução. Por
exemplo, se você quiser definir alguma propriedade (por exemplo, memória) para o destino e dar
a determinadas ações uma alocação de memória maior, grave uma entrada exec_properties
com uma chave aumentada pelo grupo de execução, como:
# BUILD
my_rule(
name = 'my_target',
exec_properties = {
'mem': '12g',
'link.mem': '16g'
}
…
)
Todas as ações com exec_group = "link"
mostrariam o dicionário de propriedades
de execução como {"mem": "16g"}
. Como você pode ver aqui, as configurações no nível do grupo de execução
substituem as configurações no nível da segmentação.
Grupos de execução para regras nativas
Os seguintes grupos de execução estão disponíveis para ações definidas por regras nativas:
test
: ações do test runner.cpp_link
: ações de vinculação do C++.
Criar grupos de execução para definir propriedades de execução
Às vezes, você quer usar um grupo de execução para atribuir ações específicas a diferentes propriedades
de execução, mas não quer toolchains ou restrições diferentes da
regra. Para essas situações, é possível criar grupos de execução usando o 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 execução e propriedades de execução da plataforma
É possível definir exec_properties
para grupos de execução arbitrários em
destinos de plataforma. Ao contrário de exec_properties
definido diretamente em um destino, em que
as propriedades de grupos de execução desconhecidos são rejeitadas. Em seguida, os alvos herdam o exec_properties
da plataforma de execução que afetam o grupo de execução padrão e outros grupos de execução relevantes.
Por exemplo, suponha que a execução de um teste em C++ exija que algum recurso esteja disponível, mas que ele não seja necessário para compilação e vinculação. Isso pode ser modelado da seguinte forma:
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"],
)
O exec_properties
definido diretamente nos destinos tem precedência sobre os que
são herdados da plataforma de execução.