Ele tem um suporte sofisticado para a modelagem de plataformas e conjuntos de ferramentas. Essa integração com projetos reais requer uma cooperação cuidadosa entre os proprietários de código, os mantenedores de regras e os desenvolvedores principais do Bazel.
Esta página resume o propósito das plataformas e mostra como criá-las.
tl;dr::as APIs de plataforma e conjunto de ferramentas do Bazel estão disponíveis, mas não vão funcionar
em todo lugar até que todas as regras de linguagem, select()
s e outras referências legadas
sejam atualizadas. Esse trabalho é constante. Em algum momento, todos os builds serão baseados em plataforma.
Leia abaixo para ver onde se encaixam nos seus builds.
Para documentação mais formal, consulte:
Contexto
As plataformas e os conjuntos de ferramentas foram introduzidos para padronizar a maneira como os projetos de software são direcionados a máquinas diferentes e são criados com as ferramentas de linguagem certas.
Essa é uma adição relativamente recente ao Bazel. Ela foi
inspirada
pela observação de que os mantenedores de idioma já faziam 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 do C++. Nenhuma dessas opções modela corretamente
uma "plataforma". Tentativas históricas 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
.
Ele é destinado a projetos grandes, em vários idiomas e em várias plataformas. Isso exige um suporte mais baseado em princípios para esses conceitos, incluindo APIs claras que incentivam a interoperabilidade entre a linguagem e o projeto. É para isso que essas novas APIs servem.
Migração
As APIs de plataforma e conjunto de ferramentas só funcionam quando são usadas pelos projetos. Isso
não é trivial, porque a lógica de regras, os conjuntos de ferramentas, as dependências e os
select()
s de um projeto precisam oferecer suporte a eles. Isso exige uma sequência de migração cuidadosa
para manter todos os projetos e as dependências deles funcionando corretamente.
Por exemplo, as regras C++ do Bazel são compatíveis com plataformas. Mas as Regras da Apple não. Seu projeto em C++ pode não se importar com a Apple. Mas outros talvez. Portanto, ainda não é seguro ativar plataformas globalmente 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 que o projeto usa podem inferir os conjuntos de ferramentas corretos de
//:myplatform
. - As regras usadas pelas dependências do projeto podem inferir os conjuntos de ferramentas corretos
a partir de
//:myplatform
. - Ou os projetos que dependem do seu oferecem suporte a
//:myplatform
ou seu projeto oferece suporte a APIs legadas (como--crosstool_top
). //:myplatform
faz referência a [declarações comuns][Common Platform Promotion]{: .external} deCPU
,OS
e outros conceitos genéricos que aceitam a compatibilidade automática entre projetos.- Os
select()
s de todos os projetos relevantes entendem as propriedades de máquina implícitas por//:myplatform
. //:myplatform
é definido em um lugar claro e reutilizável: no repositório do seu projeto, se a plataforma for exclusiva dele. Caso contrário, todos os projetos que usam essa plataforma podem encontrar.
As APIs antigas vão ser removidas assim que essa meta for atingida. Essa será a maneira padrão que os projetos selecionam plataformas e conjuntos de ferramentas.
Devo usar plataformas?
Se você quiser apenas criar ou fazer a compilação cruzada de um projeto, siga a documentação oficial dele.
Se você gerencia projetos, linguagens ou conjuntos de ferramentas, talvez queira oferecer suporte às novas APIs. Esperar até que a migração global seja concluída ou ativar antecipadamente depende das suas necessidades específicas de valor / custo:
Valor
- É possível usar
select()
ou escolher conjuntos de ferramentas nas propriedades exatas que são importantes para você, em vez de sinalizações codificadas como--cpu
. Por exemplo, várias CPUs podem oferecer suporte ao mesmo conjunto de instruções. - Builds mais corretos. Se você usar
select()
com--cpu
no exemplo acima e adicionar uma nova CPU que ofereça suporte ao mesmo conjunto de instruções, oselect()
não reconhecerá a nova CPU. No entanto, aselect()
nas plataformas continua precisa. - Experiência do usuário mais simples. Todos os projetos entendem:
--platforms=//:myplatform
. Não é necessário ter várias sinalizações específicas de linguagem na linha de comando. - Design de linguagem mais simples. Todas as linguagens têm uma API comum para definir e usar conjuntos de ferramentas, além de selecionar o conjunto correto para uma plataforma.
- Os destinos podem ser ignorados na fase de criação e teste caso sejam incompatíveis com a plataforma de destino.
Custos
- É possível que os projetos dependentes que ainda não oferecem suporte a plataformas não funcionem automaticamente com o seu.
- Para fazê-los funcionar, pode ser que você precise fazer uma manutenção temporária adicional.
- A coexistência de APIs novas e legadas requer uma orientação mais cuidadosa do usuário para evitar confusão.
- As definições canônicas para propriedades comuns, como
OS
eCPU
, ainda estão em evolução e podem exigir contribuições iniciais extras. - As definições canônicas para conjuntos de ferramentas específicos da linguagem ainda estão em evolução e podem exigir contribuições iniciais extras.
Revisão da API
Um platform
é uma coleção de
constraint_value
destinos:
platform(
name = "myplatform",
constraint_values = [
"@platforms//os:linux",
"@platforms//cpu:arm",
],
)
Um 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 do Starlark. Os
atributos dela 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.
Os conjuntos de ferramentas declaram os constraint_value
s das máquinas que podem
direcionar
(target_compatible_with = ["@platforms//os:linux"]
) e as máquinas em que as ferramentas podem
ser executadas
(exec_compatible_with = ["@platforms//os:mac"]
).
Ao compilar $ bazel build //:myproject --platforms=//:myplatform
, o Bazel
seleciona automaticamente um conjunto de ferramentas que pode ser executado na máquina e
binários de build para //:myplatform
. Isso é conhecido como resolução do conjunto de ferramentas.
O conjunto de conjuntos de ferramentas disponíveis pode ser registrado em WORKSPACE
com
register_toolchains
ou na
linha de comando com --extra_toolchains
.
Clique aqui para saber mais.
Status
A compatibilidade atual com a plataforma varia de acordo com o idioma. Todas as regras principais do Bazel sejam migradas para plataformas. Mas esse processo é demorado. Isso se deve a três motivos principais:
A lógica de regras precisa ser atualizada para receber informações de ferramenta da nova API de conjunto de ferramentas (
ctx.toolchains
) e parar de ler configurações legadas, como--cpu
e--crosstool_top
. Isso é relativamente simples.Os mantenedores de conjunto de ferramentas precisam definir os 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 maneira inteligente para manter uma experiência do usuário fácil.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.
Os projetos existentes precisam ser migrados.
select()
s e transições também precisam ser migradas. Esse é o maior desafio. Isso é particularmente desafiador para projetos com vários idiomas, que pode falhar se todos os idiomas não puderem ler--platforms
.
Se você estiver criando um novo conjunto de regras, precisará oferecer suporte às plataformas desde o início. Isso torna suas regras automaticamente compatíveis com outras regras e projetos, aumentando o valor à medida que a API da plataforma se torna mais onipresente.
Propriedades comuns da plataforma
As propriedades de plataforma como OS
e CPU
, que são comuns em todos os projetos, precisam ser declaradas em um local padrão 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
, isso vai acionar os modos "arm" com critérios
incompatíveis.
As propriedades globalmente comuns são declaradas no repositório
@platforms
(de modo que o rótulo canônico do exemplo acima é @platforms//cpu:arm
).
As propriedades comuns em idiomas precisam ser declaradas nos repositórios dos respectivos
idiomas.
Plataformas padrão
Geralmente, os proprietários de projetos precisam definir plataformas explícitas para descrever os tipos de máquinas em que querem criar. Em seguida, eles são acionados com
--platforms
.
Quando --platforms
não está definido, o Bazel assume como padrão uma platform
que representa a
máquina de build local. Ele é gerado automaticamente em @local_config_platform//:host
,
portanto, não é necessário defini-lo explicitamente. Ele mapeia os OS
e os CPU
da máquina local com constraint_value
s declarados em
@platforms
.
C++
As regras C++ do Bazel usam plataformas para selecionar conjuntos de ferramentas quando você define
--incompatible_enable_cc_toolchain_resolution
(#7260, link em inglês).
Isso significa que você pode 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 o 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. Para mais orientações, consulte
#7260 e
Como configurar conjuntos de ferramentas C++.
Esse modo não é ativado por padrão. Isso ocorre porque os projetos da Apple ainda
configuram dependências C++ com --cpu
e --crosstool_top
(exemplo). Isso depende da migração das regras da Apple 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 sinalizações de configuração, consulte o manual Bazel e Java (link em inglês). 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 Android do Bazel usam plataformas para selecionar conjuntos de ferramentas quando você define
--incompatible_enable_android_toolchain_resolution
.
Esse recurso não é ativado por padrão. Mas a migração está no caminho certo.
Apple
As regras da Apple do Bazel ainda não são compatíveis com plataformas para selecionar conjuntos de ferramentas da Apple.
Elas também não são compatíveis com dependências C++ ativadas para a plataforma, porque usam o
--crosstool_top
legado para definir o conjunto de ferramentas do C++. Até que isso seja migrado, é possível misturar projetos da Apple com C++ compatível com plataforma usando mapeamentos
de plataforma
(exemplo).
Outros idiomas
- As regras do Rust do Bazel são totalmente compatíveis com plataformas.
- As regras Go do Bazel oferecem suporte total a plataformas (detalhes).
Se você estiver criando regras para uma nova linguagem, use plataformas para selecionar os conjuntos de ferramentas dela. Consulte a documentação dos conjuntos de ferramentas para ver um bom tutorial.
select()
Os projetos podem select()
em
constraint_value
destinos, mas não em plataformas
completas. Isso é intencional para que select()
s ofereça suporte à maior variedade
possível de máquinas. Uma biblioteca com fontes específicas de ARM
precisa oferecer suporte a
todas as máquinas com tecnologia ARM
, a menos que haja motivo para ser mais específica.
Para selecionar um ou mais constraint_value
s, use:
config_setting(
name = "is_arm",
constraint_values = [
"@platforms//cpu:arm",
],
)
Isso é equivalente a selecionar tradicionalmente no --cpu
:
config_setting(
name = "is_arm",
values = {
"cpu": "arm",
},
)
Confira mais detalhes neste link.
select
s em --cpu
, --crosstool_top
etc. não entendem --platforms
. Ao
migrar o projeto para plataformas, você precisa convertê-los em
constraint_values
ou usar mapeamentos de plataforma para oferecer suporte
a ambos os estilos por meio da janela de migração.
Transições
As transições do Starlark mudam
as sinalizações para partes do gráfico de build. Se o projeto usar uma transição que
defina --cpu
, --crossstool_top
ou outras sinalizações legadas, as regras que leem
--platforms
não verão essas mudanças.
Ao migrar seu projeto para plataformas, você precisa converter mudanças como
return { "//command_line_option:cpu": "arm" }
em return {
"//command_line_option:platforms": "//:my_arm_platform" }
ou usar mapeamentos
de plataforma para oferecer suporte aos dois estilos pela janela
de migração.
Como usar as plataformas atualmente
Se você quiser apenas criar ou fazer a compilação cruzada de um projeto, siga a documentação oficial dele. Cabe à linguagem e aos mantenedores do projeto determinar como e quando integrar-se às plataformas e que valor isso oferece.
Se você for um mantenedor de projeto, linguagem ou conjunto de ferramentas e sua versão não usa plataformas por padrão, você terá três opções (além de aguardar a migração global):
Ative a sinalização "usar plataformas" para os idiomas do seu projeto (se tiverem uma) e faça os testes necessários para ver se os projetos importantes para você funcionam.
Se os projetos importantes para você ainda dependerem 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, e 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 configurações de estilo
--cpu
para plataformas correspondentes e vice-versa.
Mapeamentos de plataforma
Os mapeamentos de plataforma são uma API temporária que permite que as lógicas com tecnologia de plataforma e legadas coexistam no mesmo build durante a janela de descontinuação da última.
Um mapeamento de plataforma é um mapa de uma platform()
para um
conjunto correspondente de sinalizações legadas ou o inverso. 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
Ele usa isso para garantir que todas as configurações, tanto baseadas em plataforma quanto legadas, sejam aplicadas de forma consistente em todo o build, inclusive em transições.
Por padrão, o Bazel lê mapeamentos do arquivo platform_mappings
na raiz do seu espaço de trabalho. Você também pode definir
--platform_mappings=//:my_custom_mapping
.
Clique aqui para ver detalhes completos.
Dúvidas
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.