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 restrições e plataformas. 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 atender:
- 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, o seguinte
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. A
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:
@local_config_platform//:host
: Este é o 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 é@local_config_platform//:host
.@local_config_platform
é uma regra de repositório que detecta o SO do host e CPU e grava o destino da plataforma.- Ela também cria
@local_config_platform//:constraintz.bzl
, que expõe uma matriz chamadaHOST_CONSTRAINTS
, que pode ser usada em outros projetos Starlark.
--platforms
: o padrão é a plataforma de host- Isso significa que, quando nenhuma outra sinalização for definida,
@local_config_platform//: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.
- Isso significa que, quando nenhuma outra sinalização for definida,
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?
As segmentações são ignoradas quando são consideradas incompatíveis e incluídas no é criado como parte de uma expansão de 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 uma 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:
- Ao segmentar o macOS, o destino não tem restrições.
- Ao segmentar o Linux, o destino não tem restrições.
- 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.