Migração para plataformas

Reportar um problema Ver a fonte Nightly · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

O Bazel tem suporte sofisticado para modelar plataformas e toolchains para builds de várias arquiteturas e cross-compilados.

Esta página resume o estado desse suporte.

Consulte também:

Status

C++

As regras do C++ usam plataformas para selecionar toolchains quando --incompatible_enable_cc_toolchain_resolution está definido.

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=...

Isso será ativado por padrão no Bazel 7.0 (#7260).

Para testar seu projeto em C++ com plataformas, consulte Migrar seu projeto e Configurar toolchains em C++.

Java

As regras do Java usam plataformas para selecionar toolchains.

Isso substitui as flags legadas --java_toolchain, --host_java_toolchain, --javabase e --host_javabase.

Consulte Java e Bazel para mais detalhes.

Android

As regras do Android usam plataformas para selecionar toolchains quando --incompatible_enable_android_toolchain_resolution está definido.

Isso significa que você pode configurar um projeto do Android com:

bazel build //:my_android_project --android_platforms=//:my_android_platform

em vez de usar flags legadas como --android_crosstool_top, --android_cpu e --fat_apk_cpu.

Isso será ativado por padrão no Bazel 7.0 (#16285).

Para testar seu projeto do Android com plataformas, consulte Migrar seu projeto.

Apple

As regras da Apple não são compatíveis com plataformas e ainda não têm suporte programado.

Você ainda pode usar APIs de plataforma com builds da Apple (por exemplo, ao criar com uma mistura de regras da Apple e C++ puro) com mapeamentos de plataforma.

Outros idiomas

Se você tem um conjunto de regras de idioma, consulte Migrar seu conjunto de regras para adicionar suporte.

Contexto

As plataformas e os toolchains foram introduzidos para padronizar como os projetos de software visam diferentes arquiteturas e fazem a compilação cruzada.

Isso foi inspirado na observação de que os mantenedores de idiomas já faziam isso de maneiras ad hoc e incompatíveis. Por exemplo, as regras do C++ usavam --cpu e --crosstool_top para declarar uma CPU e uma cadeia de ferramentas de destino. Nenhum deles modela corretamente uma "plataforma". Isso produzia builds estranhos e incorretos.

Java, Android e outras linguagens desenvolveram suas próprias flags para fins semelhantes, mas nenhuma delas interoperava entre si. Isso tornava as criações entre linguagens confusas e complicadas.

O Bazel é destinado a projetos grandes, multilíngues e multiplataforma. Isso exige um suporte mais fundamentado para esses conceitos, incluindo uma API padrão clara.

Necessidade de migração

Para fazer upgrade para a nova API, é necessário fazer duas coisas: lançar a API e atualizar a lógica de regra para usá-la.

A primeira foi concluída, mas a segunda ainda está em andamento. Isso consiste em garantir que plataformas e cadeias de ferramentas específicas do idioma sejam definidas, que a lógica de linguagem leia cadeias de ferramentas pela nova API em vez de flags antigas, como --crosstool_top, e que config_settings selecionem a nova API em vez de flags antigas.

Esse trabalho é simples, mas exige um esforço distinto para cada idioma, além de um aviso justo para que os proprietários de projetos testem as próximas mudanças.

Por isso, essa é uma migração contínua.

Meta

A migração será concluída quando todos os projetos forem criados com o formulário:

bazel build //:myproject --platforms=//:myplatform

Isso implica:

  1. As regras do seu projeto escolhem as cadeias de ferramentas certas para //:myplatform.
  2. As dependências do projeto escolhem as toolchains certas para //:myplatform.
  3. //:myplatform faz referência a declarações comuns de CPU, OS e outras propriedades genéricas e independentes de linguagem.
  4. Todos os select()s relevantes correspondem corretamente a //:myplatform.
  5. //:myplatform é definido em um lugar claro e acessível: no repositório do seu projeto, se a plataforma for exclusiva dele, ou em um lugar comum em que todos os projetos consumidores possam encontrá-lo.

As flags antigas, como --cpu, --crosstool_top e --fat_apk_cpu, serão descontinuadas e removidas assim que for seguro fazer isso.

Em última análise, essa será a única maneira de configurar arquiteturas.

Migrar seu projeto

Se você criar com linguagens que oferecem suporte a plataformas, a build já vai funcionar com uma invocação como:

bazel build //:myproject --platforms=//:myplatform

Consulte Status e a documentação da sua linguagem para mais detalhes.

Se um idioma exigir uma flag para ativar o suporte da plataforma, você também precisará definir essa flag. Consulte Status para mais detalhes.

Para que o projeto seja criado, verifique o seguinte:

  1. //:myplatform precisa existir. Em geral, é responsabilidade do proprietário do projeto definir as plataformas, já que projetos diferentes têm como destino máquinas diferentes. Consulte Plataformas padrão.

  2. As toolchains que você quer usar precisam existir. Se você estiver usando toolchains padrão, os proprietários de idiomas precisarão incluir instruções sobre como registrá-las. Se você estiver criando seus próprios conjuntos de ferramentas personalizados, registre-os no WORKSPACE ou com --extra_toolchains.

  3. select()s e transições de configuração precisam ser resolvidas corretamente. Consulte select() e Transições.

  4. Se o build misturar linguagens que oferecem e não oferecem suporte a plataformas, talvez seja necessário usar mapeamentos de plataforma para ajudar as linguagens legadas a funcionar com a nova API. Consulte Mapeamentos de plataforma para mais detalhes.

Se você ainda tiver problemas, entre em contato para receber suporte.

Plataformas padrão

Os proprietários de projetos precisam definir plataformas explícitas para descrever as arquiteturas que querem criar. Elas são acionadas com --platforms.

Quando --platforms não está definido, o Bazel usa um platform padrão que representa a máquina de build local. Ele é gerado automaticamente em @platforms//host (com alias @bazel_tools//tools:host_platform), então não é necessário defini-lo explicitamente. Ele mapeia o OS e o CPU da máquina local com constraint_values declarados em @platforms.

select()

Os projetos podem select() em constraint_value destinos, mas não em plataformas completas. Isso é intencional para que o select() seja compatível com a maior variedade possível de máquinas. Uma biblioteca com fontes específicas de ARM precisa ser compatível com todas as máquinas com tecnologia ARM, a menos que haja um motivo para ser mais específica.

Para selecionar em um ou mais constraint_values, use:

config_setting(
    name = "is_arm",
    constraint_values = [
        "@platforms//cpu:arm",
    ],
)

Isso é equivalente a selecionar tradicionalmente em --cpu:

config_setting(
    name = "is_arm",
    values = {
        "cpu": "arm",
    },
)

Confira mais detalhes aqui.

Os selects em --cpu, --crosstool_top etc. não entendem --platforms. Ao migrar seu projeto para plataformas, é necessário convertê-los para constraint_values ou usar mapeamentos de plataforma para oferecer suporte aos dois estilos durante a migração.

Transições

As transições do Starlark mudam flags em partes do seu gráfico de build. Se o projeto usar uma transição que defina --cpu, --crossstool_top ou outras flags legadas, as regras que leem --platforms não vão detectar 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 migração. window.

Migrar seu conjunto de regras

Se você tem um conjunto de regras e quer oferecer suporte a plataformas, faça o seguinte:

  1. Faça com que a lógica de regra resolva toolchains com a API toolchain. Consulte a API de cadeia de ferramentas (ctx.toolchains).

  2. Opcional: defina uma flag --incompatible_enable_platforms_for_my_language para que a lógica da regra resolva alternadamente as toolchains pela nova API ou flags antigas como --crosstool_top durante o teste de migração.

  3. Defina as propriedades relevantes que compõem os componentes da plataforma. Consulte Propriedades comuns da plataforma

  4. Defina toolchains padrão e deixe-as acessíveis aos usuários seguindo as instruções de registro da sua regra (detalhes).

  5. Verifique se select()s e transições de configuração são compatíveis com plataformas. Esse é o maior desafio. Isso é particularmente difícil para projetos multilíngues, que podem falhar se todos os idiomas não puderem ler --platforms.

Se você precisar combinar com regras que não oferecem suporte a plataformas, talvez precise de mapeamentos de plataforma para preencher a lacuna.

Propriedades comuns da plataforma

Propriedades comuns e multiplataforma, como OS e CPU, precisam ser declaradas em @platforms. Isso incentiva o compartilhamento, a padronização e a compatibilidade entre linguagens.

As propriedades exclusivas das suas regras precisam ser declaradas no repositório delas. Isso permite manter uma propriedade clara sobre os conceitos específicos de que suas regras são responsáveis.

Se as regras usarem SOs ou CPUs de uso personalizado, elas precisarão ser declaradas no repositório da regra em vez de @platforms.

Mapeamentos de plataforma

Mapeamentos de plataforma é uma API temporária que permite que a lógica compatível com a plataforma seja combinada com a lógica legada na mesma build. Essa é uma ferramenta simples destinada apenas a suavizar incompatibilidades com diferentes períodos de migração.

Um mapeamento de plataforma é um mapa de um platform() para um conjunto correspondente de flags legadas ou o contrário. 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_x86_64 --apple_platform_type=macos" to "//platform:macos".
  --cpu=darwin_x86_64
  --apple_platform_type=macos
    //platforms:macos

O Bazel usa isso para garantir que todas as configurações, baseadas em plataforma e legadas, sejam aplicadas de maneira 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.

Consulte o design de mapeamentos de plataforma para mais detalhes.

Revisão da API

Um platform é um conjunto de constraint_value segmentações:

platform(
    name = "myplatform",
    constraint_values = [
        "@platforms//os:linux",
        "@platforms//cpu:arm",
    ],
)

Um constraint_value é uma propriedade da máquina. 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",
)

Um toolchain é uma regra do Starlark. Os atributos dele 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 toolchains declaram os constraint_values das máquinas que podem segmentar (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 uma cadeia de ferramentas que pode ser executada na máquina de build e criar binários para //:myplatform. Isso é conhecido como resolução da cadeia de ferramentas.

O conjunto de toolchains disponíveis pode ser registrado no WORKSPACE com register_toolchains ou na linha de comando com --extra_toolchains.

Confira mais informações.

Perguntas

Para suporte geral e dúvidas sobre o cronograma de migração, entre em contato com bazel-discuss ou os proprietários das regras adequadas.

Para discussões sobre o design e a evolução das APIs da plataforma/cadeia de ferramentas, entre em contato com bazel-dev.

Consulte também