Grupos de execução

Informar um problema Acessar código-fonte

Os grupos de execução permitem várias plataformas de execução dentro de um único alvo. Cada grupo de execução tem as próprias dependências do conjunto de ferramentas e executa a própria resolução de conjunto de ferramentas.

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, compilar um app iOS em um worker remoto (Linux) e vinculação/assinatura de código em um worker do Mac local.

A capacidade de definir grupos de ações também ajuda a aliviar o uso de mnemônicas de ação como um proxy para especificar ações. Não há garantia de que as mnemônicas sejam exclusivas e só podem referenciar uma única ação. Isso é especialmente útil para alocar recursos extras a memórias específicas e ações de processamento intensivo, como vinculações em builds C++ sem alocação excessiva para tarefas menos exigentes.

Como definir grupos de execução

Durante a definição da regra, os autores de regras podem declarar um conjunto de grupos de execução. Em cada grupo de execução, o autor da regra pode especificar tudo o que é necessário para selecionar uma plataforma de execução para esse grupo, ou seja, quaisquer restrições usando exec_compatible_with e tipos de conjunto de ferramentas via 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 observar que as dependências de ferramentas também podem especificar a transição para 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 em que a dependência 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 do grupo de execução

Além de definir as próprias restrições e conjuntos de ferramentas, 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 herdado do grupo de execução padrão copia restrições, conjuntos de ferramentas e propriedades de execução do padrão. Isso inclui restrições e propriedades de execução definidas no nível da meta, não apenas as especificadas pela regra em si. 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 demo de destino configurado vai incluir: - //fool_tools:toolchain_type - @platforms//os:linux - :local_constraint

Como acessar grupos de execução

Na implementação da regra, é possível declarar que as ações precisam ser executadas na plataforma 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 os conjuntos de ferramentas resolvidos de grupos de execução, da mesma forma que você pode acessar o conjunto de ferramentas resolvido 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",
     # ...
  )

Como 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" veriam o dicionário de propriedades exec como {"mem": "16g"}. Como mostrado aqui, as configurações no nível do grupo de execução substituem as no nível da meta.

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 executor de teste.
  • cpp_link: ações de vinculação C++.

Como criar grupos "exec" para definir as propriedades "exec"

Às vezes, você quer usar um grupo "exec" para atribuir diferentes propriedades "exec" a ações específicas, mas não quer conjuntos de ferramentas 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 do exec_properties definido diretamente em um destino, em que as propriedades de grupos de execução desconhecidos são rejeitadas. Os destinos herdam o exec_properties da plataforma de execução, que afeta o grupo de execução padrão e quaisquer 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 não é 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"],
)

exec_properties definidos diretamente nos destinos têm precedência sobre aqueles herdados da plataforma de execução.