O Bazel tem suporte sofisticado à modelagem de plataformas e conjuntos de ferramentas. A integração com projetos reais exige uma cooperação cuidadosa entre proprietários de código, mantenedores de regras e desenvolvedores principais do Bazel.
Esta página resume a finalidade das plataformas e mostra como criar com elas.
tl;dr: as APIs de plataforma e de conjunto de ferramentas do Bazel estão disponíveis, mas não funcionam em todos os lugares até que todas as regras de linguagem, select()
s e outras referências legadas sejam atualizadas. Esse trabalho é constante. Todos os builds serão baseados em plataforma.
Leia abaixo para saber onde seus builds se encaixam.
Para consultar uma documentação mais formal, consulte:
Contexto
As plataformas e os conjuntos de ferramentas foram introduzidos para padronizar a forma como os projetos de software visam máquinas diferentes e criar com as ferramentas de linguagem corretas.
Essa é uma adição relativamente recente ao Bazel. Ele foi
inspirado
na observação de que os mantenedores de linguagem já estavam fazendo isso de
maneiras ad hoc e incompatíveis. Por exemplo, as regras C++ usam --cpu
e --crosstool_top
para definir a CPU de destino e o conjunto de ferramentas C++ de um build. Nenhuma das opções modela corretamente
uma "plataforma". As tentativas anteriores de fazer isso causaram builds estranhos e imprecisos.
Essas sinalizações também não controlam a compilação Java, que desenvolveu a própria
interface independente com --java_toolchain
.
O Bazel é destinado a projetos grandes, com várias linguagens e várias plataformas. Isso exige mais suporte a esses conceitos, incluindo APIs claras que incentivam a interoperabilidade de linguagem e projeto. É para isso que essas novas APIs servem.
Migração
As APIs de plataforma e de conjunto de ferramentas só funcionam quando os projetos as utilizam. Isso
não é trivial porque a lógica da regra, os conjuntos de ferramentas, as dependências e
select()
s de um projeto precisam ser compatíveis com eles. Isso requer uma sequência de migração cuidadosa
para manter todos os projetos e as dependências funcionando corretamente.
Por exemplo, as Regras C++ do Bazel oferecem suporte a plataformas. Mas as regras da Apple não. Seu projeto em C++ pode não se importar com a Apple. No entanto, outras podem. Portanto, ainda não é seguro ativar globalmente as plataformas para todos os builds em C++.
O restante desta página descreve essa sequência de migração e como e quando seus projetos podem se encaixar.
Meta
A migração da plataforma do Bazel é concluída quando todos os projetos são compilados com o formulário:
bazel build //:myproject --platforms=//:myplatform
Isso implica:
- As regras usadas pelo projeto podem inferir os conjuntos de ferramentas corretos de
//:myplatform
. - As regras usadas pelas dependências do projeto podem inferir os conjuntos de ferramentas corretos
de
//:myplatform
. - Os projetos dependem do suporte do
//:myplatform
ou seu projeto oferece suporte às APIs legadas (como--crosstool_top
). //:myplatform
faz referência a [declarações comuns][Common Platform Declaration]{: .external} deCPU
,OS
e outros conceitos genéricos que são compatíveis com a compatibilidade automática entre projetos.- Todos os
select()
s dos projetos relevantes entendem as propriedades da máquina implícitas em//:myplatform
. //:myplatform
é definido em um local claro e reutilizável: no repositório do projeto, se a plataforma for exclusiva para ele. Caso contrário, em algum lugar que todos os projetos que podem usar essa plataforma possam encontrar.
As APIs antigas serão removidas assim que esse objetivo for alcançado. Essa será a maneira padrão que os projetos usam para selecionar plataformas e conjuntos de ferramentas.
Devo usar plataformas?
Se você quiser apenas criar ou fazer uma compilação cruzada de um projeto, siga a documentação oficial dele.
Se você é um mantenedor de projeto, linguagem ou cadeia de ferramentas, vai querer oferecer suporte às novas APIs. A espera até a conclusão da migração global ou a ativação antecipada depende das suas necessidades específicas de valor / custo:
Valor
- É possível usar
select()
ou escolher toolchains nas propriedades exatas que você considera importantes em vez de flags codificadas, como--cpu
. Por exemplo, várias CPUs podem ser compatíveis com o mesmo conjunto de instruções. - Builds mais corretos. Se você
select()
com--cpu
no exemplo acima e adicionar uma nova CPU compatível com o mesmo conjunto de instruções, oselect()
não reconhecerá a nova CPU. Mas umselect()
nas plataformas continua preciso. - Experiência do usuário mais simples. Todos os projetos entendem:
--platforms=//:myplatform
. Não é necessário usar várias flags específicas de idioma na linha de comando. - Design de linguagem mais simples. Todos os idiomas compartilham uma API comum para definir e usar toolchains e selecionar a toolchain certa para uma plataforma.
- Os destinos podem ser ignorados na fase de criação e teste se forem incompatíveis com a plataforma de destino.
Custos
- Projetos dependentes que ainda não são compatíveis com plataformas podem não funcionar automaticamente com o seu.
- Para fazê-los funcionar, você pode precisar de manutenção temporária adicional.
- A coexistência de APIs novas e legadas requer uma orientação do usuário mais cuidadosa para evitar confusão.
- As definições canônicas de propriedades comuns, como
OS
eCPU
, ainda estão em evolução e podem exigir mais contribuições iniciais. - As definições canônicas para toolchains específicos de linguagem ainda estão em evolução e podem exigir contribuições iniciais extras.
Revisão pela API
Um platform
é uma coleção de
destinos constraint_value
:
platform(
name = "myplatform",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:arm",
],
)
Uma constraint_value
é uma propriedade de máquina. Os valores do mesmo "tipo" são agrupados em um constraint_setting
comum:
constraint_setting(name = "os")
constraint_value(
name = "linux",
constraint_setting = ":os",
)
constraint_value(
name = "mac",
constraint_setting = ":os",
)
Uma toolchain
é uma regra Starlark. Os
atributos declaram as ferramentas de uma linguagem (como compiler =
"//mytoolchain:custom_gcc"
). Os provedores transmitem
essas informações para regras que precisam ser criadas com essas ferramentas.
As cadeias de ferramentas declaram as constraint_value
s de máquinas que podem
ser direcionadas
(target_compatible_with = ["@platforms//os:linux"]
) e as máquinas em que as ferramentas podem
ser executadas
(exec_compatible_with = ["@platforms//os:mac"]
).
Ao criar $ bazel build //:myproject --platforms=//:myplatform
, o Bazel
seleciona automaticamente um conjunto de ferramentas que pode ser executado na máquina de build e
binários de build para //:myplatform
. Isso é conhecido como resolução do conjunto de ferramentas.
O conjunto de toolchains disponíveis pode ser registrado no WORKSPACE
com
register_toolchains
ou na
linha de comando com --extra_toolchains
.
Veja mais detalhes aqui.
Status
A compatibilidade atual com a plataforma varia de acordo com o idioma. Todas as principais regras do Bazel são migradas para plataformas. Mas esse processo vai demorar. Isso se deve a três motivos principais:
A lógica de regra precisa ser atualizada para receber informações da ferramenta da nova API do conjunto de ferramentas (
ctx.toolchains
) e parar de ler configurações legadas, como--cpu
e--crosstool_top
. Isso é relativamente simples.Os mantenedores do conjunto de ferramentas precisam definir conjuntos de ferramentas e torná-los acessíveis aos usuários (em repositórios do GitHub e entradas
WORKSPACE
). Isso é tecnicamente simples, mas precisa ser organizado de forma inteligente para manter uma experiência fácil para o usuário.As definições de plataforma também são necessárias (a menos que você crie para a mesma máquina em que o Bazel é executado). Geralmente, os projetos precisam definir as próprias plataformas.
É necessário migrar projetos existentes.
select()
s e transições também precisam ser migrados. Esse é o maior desafio. Isso é particularmente desafiador para projetos multilíngues, que podem falhar se todos os idiomas não conseguirem ler--platforms
.
Se você estiver criando um novo conjunto de regras, precisará oferecer suporte às plataformas desde o início. Isso torna automaticamente suas regras compatíveis com outras regras e projetos, aumentando o valor à medida que a API da plataforma se torna mais onipresente.
Propriedades comuns da plataforma
Propriedades da plataforma, como OS
e CPU
, que são comuns em todos os projetos, precisam
ser declaradas em um local padrão e centralizado. Isso incentiva a compatibilidade
entre projetos e linguagens.
Por exemplo, se MyApp tiver um select()
em constraint_value
@myapp//cpus:arm
e SomeCommonLib tiver um select()
em
@commonlib//constraints:arm
, eles vão acionar os modos "arm" com critérios
incompatíveis.
Propriedades globalmente comuns são declaradas no repositório @platforms
. Portanto, o rótulo canônico do exemplo acima é @platforms//cpu:arm
. As propriedades linguísticas comuns precisam ser declaradas nos repositórios das respectivas linguagens.
Plataformas padrão
Geralmente, os proprietários de projetos precisam definir
plataformas explícitas para descrever os
tipos de máquinas para os quais eles querem criar. Em seguida, eles são acionados com
--platforms
.
Quando --platforms
não está definido, o Bazel usa o padrão platform
, que representa a
máquina de build local. Isso é gerado automaticamente em @local_config_platform//:host
,
então não é necessário defini-lo explicitamente. Ele mapeia o OS
e o CPU
da máquina local com constraint_value
s declarados em
@platforms
.
C++
As regras C++ do Bazel usam plataformas para selecionar toolchains quando você define
--incompatible_enable_cc_toolchain_resolution
(#7260).
Isso significa que é possível configurar um projeto em C++ com:
bazel build //:my_cpp_project --platforms=//:myplatform
em vez do legado:
bazel build //:my_cpp_project` --cpu=... --crosstool_top=... --compiler=...
Se seu projeto for C++ puro e não depender de projetos que não sejam C++, você poderá usar
plataformas com segurança, desde que suas select
s e
transições sejam compatíveis. Consulte
#7260 e
Como configurar os conjuntos de ferramentas do C++ para ver mais orientações.
Esse modo não está ativado por padrão. Isso ocorre porque os projetos da Apple
ainda configuram dependências C++ com --cpu
e --crosstool_top
(exemplo). Isso depende das regras da Apple migrando para as plataformas.
Java
As regras Java do Bazel usam plataformas.
Isso substitui as sinalizações legadas --java_toolchain
, --host_java_toolchain
, --javabase
e --host_javabase
.
Para saber como usar as flags de configuração, consulte o manual Bazel e Java. Para mais informações, consulte o documento de design.
Se você ainda estiver usando sinalizações legadas, siga o processo de migração no Problema 7849.
Android
As regras do Bazel para Android usam plataformas para selecionar conjuntos de ferramentas quando você define
--incompatible_enable_android_toolchain_resolution
.
Essa opção não é ativada por padrão. Mas a migração está a caminho.
Apple
As regras da Apple do Bazel ainda não oferecem suporte a plataformas para selecionar cadeias de ferramentas da Apple.
Elas também não oferecem suporte a dependências C++ ativadas pela plataforma porque usam o
--crosstool_top
legado para definir a cadeia de ferramentas C++. Até que isso seja migrado, é
possível misturar projetos da Apple com C++ compatível com platorm e mapeamentos
de plataforma
(exemplo).
Outros idiomas
- As regras Rust do Bazel oferecem suporte total a plataformas.
- As regras do Go do Bazel oferecem suporte total a plataformas (detalhes).
Se você estiver criando regras para um novo idioma, use plataformas para selecionar os conjuntos de ferramentas do idioma. Consulte a documentação de cadeias de ferramentas para conferir um bom tutorial.
select()
Os projetos podem select()
em
constraint_value
de destino, mas não em plataformas
completas. Isso é intencional para que select()
s ofereça suporte a uma variedade
de máquinas o mais ampla possível. Uma biblioteca com fontes específicas de ARM
precisa oferecer suporte a
todas as máquinas com tecnologia ARM
, a menos que haja uma razão para ser mais específica.
Para selecionar em um ou mais constraint_value
s, use:
config_setting(
name = "is_arm",
constraint_values = [
"@platforms//cpu:arm",
],
)
Isso é equivalente à seleção tradicional em --cpu
:
config_setting(
name = "is_arm",
values = {
"cpu": "arm",
},
)
Veja mais detalhes neste link.
select
s em --cpu
, --crosstool_top
etc. não entendem --platforms
. Ao
migrar seu projeto para plataformas, é necessário convertê-lo em
constraint_values
ou usar mapeamentos de plataforma para oferecer suporte
a ambos os estilos durante a janela de migração.
Transições
As transições do Starlark mudam
as flags para partes do gráfico de build. Se o projeto usar uma transição que
define --cpu
, --crossstool_top
ou outras flags legadas, as regras que leem
--platforms
não vão notar essas mudanças.
Ao migrar seu projeto para plataformas, é necessário converter mudanças como
return { "//command_line_option:cpu": "arm" }
para return {
"//command_line_option:platforms": "//:my_arm_platform" }
ou usar mapeamentos
de plataforma para oferecer suporte aos dois estilos durante a janela
de migração.
Como usar as plataformas atualmente
Se você quiser apenas criar ou fazer uma compilação cruzada de um projeto, siga a documentação oficial dele. Cabe aos mantenedores da linguagem e do projeto determinar como e quando integrar as plataformas e que valor isso oferece.
Se você for um administrador de projetos, linguagens ou conjuntos de ferramentas e sua versão não usar plataformas por padrão, você terá três opções além de aguardar a migração global:
Ative a flag "use platforms" para as linguagens do seu projeto (se houver uma) e faça os testes necessários para saber se os projetos que você quer trabalhar funcionam.
Se os projetos ainda dependem de flags legadas, como
--cpu
e--crosstool_top
, use-as com--platforms
:bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...
Isso tem alguns custos de manutenção. Você precisa verificar manualmente se as configurações correspondem. Mas isso deve funcionar na ausência de transições renegadas.
Crie mapeamentos de plataforma para oferecer suporte aos dois estilos, mapeando as configurações do estilo
--cpu
para as plataformas correspondentes e vice-versa.
Mapeamentos de plataforma
Os mapeamentos de plataforma são uma API temporária que permite a coexistência de lógicas baseadas em plataforma e legadas no mesmo build durante a janela de descontinuação do último.
Um mapeamento de plataforma é um mapa de uma platform()
para um
conjunto correspondente de sinalizações legadas ou vice-versa. Exemplo:
platforms:
# Maps "--platforms=//platforms:ios" to "--cpu=ios_x86_64 --apple_platform_type=ios".
//platforms:ios
--cpu=ios_x86_64
--apple_platform_type=ios
flags:
# Maps "--cpu=ios_x86_64 --apple_platform_type=ios" to "--platforms=//platforms:ios".
--cpu=ios_x86_64
--apple_platform_type=ios
//platforms:ios
# Maps "--cpu=darwin --apple_platform_type=macos" to "//platform:macos".
--cpu=darwin
--apple_platform_type=macos
//platforms:macos
O Bazel usa isso para garantir que todas as configurações, baseadas na plataforma e legado, sejam aplicadas de forma consistente em todo o build, incluindo transições.
Por padrão, o Bazel lê mapeamentos do arquivo platform_mappings
na
raiz do espaço de trabalho. Também é possível definir
--platform_mappings=//:my_custom_mapping
.
Clique aqui para ver os detalhes completos.
Perguntas
Para suporte geral e dúvidas sobre o cronograma de migração, entre em contato com bazel-discuss@googlegroups.com ou com os proprietários das regras apropriadas.
Para discussões sobre o design e a evolução das APIs de plataforma/conjunto de ferramentas, entre em contato com bazel-dev@googlegroups.com.