Plataformas

Informar um problema Mostrar fonte Por noite · 7,3 · 7,2 · 7,1 · 7,0 · 6,5

Ele pode criar e testar código em vários hardwares, sistemas operacionais e configurações do sistema, usando muitas versões diferentes de ferramentas de build, como vinculadores e compiladores. Para ajudar a lidar com essa complexidade, o Bazel tem um conceito de constraints e platforms. Uma restrição é uma dimensão em que a criação ou ambientes de produção podem ser diferentes, como a arquitetura da CPU, a presença ou a ausência de uma GPU ou a versão de um compilador instalado pelo sistema. Uma plataforma é coleção nomeada de opções para essas restrições, representando a os recursos disponíveis em determinado ambiente.

Modelar o ambiente como uma plataforma ajuda o Bazel a selecionar automaticamente os apropriado conjuntos de ferramentas para ações de build. As plataformas também podem ser usadas em combinação com as config_setting para escrever atributos configuráveis.

O Bazel reconhece três papéis que uma plataforma pode disponibilizar:

  • Host: a plataforma em que o próprio Bazel é executado.
  • Execução: uma plataforma em que as ferramentas de compilação executam ações de compilação para e produz saídas intermediárias e finais.
  • Destino: uma plataforma em que uma saída final reside e é executada.

O Bazel oferece suporte aos seguintes cenários de build relacionados a plataformas:

  • Compilações de plataforma única (padrão): host, execução e plataformas de destino são iguais. Por exemplo, criar um executável do Linux no Ubuntu executado em uma CPU Intel x64.

  • Compilações de compilação cruzada: as plataformas host e de execução são as mesmas, mas a plataforma de destino é diferente. Por exemplo, criar um app iOS no macOS em execução em um MacBook Pro.

  • Compilações multiplataforma: as plataformas host, de execução e de destino são diferente.

Como definir restrições e plataformas

O espaço de escolhas possíveis para plataformas é definido usando a propriedade constraint_setting e constraint_value em arquivos BUILD. constraint_setting cria uma nova dimensão, enquanto constraint_value cria um novo valor para uma determinada dimensão. juntos eles definir efetivamente um tipo enumerado e os possíveis valores dele. Por exemplo, os seguintes O snippet de um arquivo BUILD introduz uma restrição para a versão glibc do sistema com dois valores possíveis.

constraint_setting(name = "glibc_version")

constraint_value(
    name = "glibc_2_25",
    constraint_setting = ":glibc_version",
)

constraint_value(
    name = "glibc_2_26",
    constraint_setting = ":glibc_version",
)

As restrições e seus valores podem ser definidos em diferentes pacotes na espaço de trabalho. Eles são referenciados por rótulo e sujeitos à visibilidade comum controles de segurança. Se a visibilidade permitir, você pode estender uma configuração de restrição existente definir seu próprio valor para ele.

A regra platform apresenta uma nova plataforma com certas opções de valores de restrição. O a seguir cria uma plataforma chamada linux_x86 e informa que ela descreve qualquer do Google que executa um sistema operacional Linux em uma arquitetura x86_64 com um versão 2.25 do glibc. Confira abaixo mais informações sobre as restrições integradas do Bazel.

platform(
    name = "linux_x86",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:x86_64",
        ":glibc_2_25",
    ],
)

Restrições e plataformas geralmente úteis

Para manter o ecossistema consistente, a equipe do Bazel mantém um repositório definições de restrições para as arquiteturas de CPU mais populares e sistemas sistemas. Todos eles estão localizados em https://github.com/bazelbuild/platforms.

O Bazel é enviado com a seguinte definição de plataforma especial: @platforms//host (alias de alias como @bazel_tools//tools:host_platform). Esta é a valor da plataforma host detectado automaticamente - representa a plataforma detectada automaticamente no sistema em que o Bazel está sendo executado.

Como especificar uma plataforma para um build

Você pode especificar as plataformas de host e destino para um build usando o seguinte sinalizações de linha de comando:

  • --host_platform: o padrão é @bazel_tools//tools:host_platform.
    • Este destino tem o alias definido como @platforms//host, que é apoiado por um repositório que detecta o SO e a CPU do host e grava o destino da plataforma.
    • Há também @platforms//host:constraints.bzl, que expõe uma matriz chamada HOST_CONSTRAINTS, que pode ser usada em outros projetos Starlark.
  • --platforms: o padrão é a plataforma de host
    • Isso significa que, quando nenhuma outra flag for definida, @platforms//host é a plataforma de destino.
    • Se --host_platform estiver definido e não --platforms, o valor de --host_platform é a plataforma de host e de destino.

Pulando destinos incompatíveis

Ao desenvolver para uma plataforma de destino específica, muitas vezes é desejável ignorar que nunca funcionarão nessa plataforma. Por exemplo, seu dispositivo Windows o driver provavelmente vai gerar muitos erros do compilador ao compilar em uma Máquina Linux com //.... Use o target_compatible_with para informar ao Bazel quais restrições de plataforma de destino seu código tem.

O uso mais simples desse atributo restringe um destino a uma única plataforma. O destino não será criado para uma plataforma que não atenda a todos os restrições. O exemplo a seguir restringe win_driver_lib.cc a 64 bits Windows.

cc_library(
    name = "win_driver_lib",
    srcs = ["win_driver_lib.cc"],
    target_compatible_with = [
        "@platforms//cpu:x86_64",
        "@platforms//os:windows",
    ],
)

:win_driver_lib é compatível apenas para criação com Windows de 64 bits e incompatível com todos os outros. A incompatibilidade é transitiva. Qualquer meta que dependem transitivamente de um alvo incompatível são considerados incompatíveis.

Quando as metas são ignoradas?

Os destinos são ignorados quando são considerados incompatíveis e incluídos no como parte da expansão de um padrão de destino. Por exemplo, os dois as invocações pulam todos os destinos incompatíveis encontrados em uma expansão de padrão de destino.

$ bazel build --platforms=//:myplatform //...
$ bazel build --platforms=//:myplatform //:all

Os testes incompatíveis em um test_suite são ignorado de forma semelhante se test_suite for especificado na linha de comando com --expand_test_suites Em outras palavras, os destinos test_suite na linha de comando se comportam como :all e ... O uso de --noexpand_test_suites evita a expansão e causa test_suite destinos com testes incompatíveis também são incompatíveis.

Especificar explicitamente um destino incompatível na linha de comando resulta em um e uma versão com falha.

$ bazel build --platforms=//:myplatform //:target_incompatible_with_myplatform
...
ERROR: Target //:target_incompatible_with_myplatform is incompatible and cannot be built, but was explicitly requested.
...
FAILED: Build did NOT complete successfully

Destinos explícitos incompatíveis são ignorados silenciosamente se --skip_incompatible_explicit_targets está ativado.

Restrições mais expressivas

Para ter mais flexibilidade ao expressar restrições, use o @platforms//:incompatible constraint_value que nenhuma plataforma satisfaz.

Use select() em combinação com @platforms//:incompatible para expressar restrições mais complicadas. Para exemplo, use-o para implementar a lógica básica OR. O código a seguir marca uma biblioteca compatível com macOS e Linux, mas não com outras plataformas.

cc_library(
    name = "unixish_lib",
    srcs = ["unixish_lib.cc"],
    target_compatible_with = select({
        "@platforms//os:osx": [],
        "@platforms//os:linux": [],
        "//conditions:default": ["@platforms//:incompatible"],
    }),
)

A instrução acima pode ser interpretada da seguinte maneira:

  1. Ao segmentar o macOS, o destino não tem restrições.
  2. Ao segmentar o Linux, o destino não tem restrições.
  3. Caso contrário, o destino terá a restrição @platforms//:incompatible. Devido ao @platforms//:incompatible não faz parte de nenhuma plataforma, o objetivo é considerados incompatíveis.

Para deixar suas restrições mais legíveis, use skylib selects.with_or().

A compatibilidade inversa pode ser expressa de maneira semelhante. O exemplo a seguir descreve uma biblioteca compatível com tudo, exceto para ARM.

cc_library(
    name = "non_arm_lib",
    srcs = ["non_arm_lib.cc"],
    target_compatible_with = select({
        "@platforms//cpu:arm": ["@platforms//:incompatible"],
        "//conditions:default": [],
    }),
)

Como detectar destinos incompatíveis usando bazel cquery

Você pode usar o IncompatiblePlatformProvider na saída do Starlark de bazel cquery formato para diferenciar os destinos incompatíveis entre si.

Isso pode ser usado para filtrar destinos incompatíveis. O exemplo abaixo exibe apenas os rótulos para destinos compatíveis. Destinos incompatíveis são não impresso.

$ cat example.cquery

def format(target):
  if "IncompatiblePlatformProvider" not in providers(target):
    return target.label
  return ""


$ bazel cquery //... --output=starlark --starlark:file=example.cquery

Problemas conhecidos

Destinos incompatíveis ignoram a visibilidade restrições.