Migração para plataformas

O Bazel oferece suporte sofisticado para plataformas de modelagem e toolchains para builds de várias arquiteturas e compilados cruzados.

Esta página resume o estado desse suporte.

Consulte também:

Status

C++

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

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

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 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 Android com:

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

em vez de 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 Android com plataformas, consulte Migrar seu projeto.

Apple

As regras da Apple não oferecem suporte a plataformas e ainda não estão programadas para isso.

Ainda é possível 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 linguagem, consulte Migrar seu conjunto de regras para adicionar suporte.

Contexto

As plataformas e toolchains foram introduzidas para padronizar como os projetos de software segmentam diferentes arquiteturas e compilam cruzados.

Isso 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 de C++ usavam --cpu e --crosstool_top para declarar uma CPU e uma toolchain de destino. Nenhuma delas modela corretamente uma "plataforma". Isso produziu builds estranhos e incorretos.

Java, Android e outras linguagens desenvolveram suas próprias flags para fins semelhantes, nenhuma das quais interoperava entre si. Isso tornou os builds entre linguagens confusos e complicados.

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

Necessidade de migração

A atualização para a nova API exige dois esforços: liberar a API e atualizar a lógica de regras para usá-la.

O primeiro já foi feito, mas o segundo está em andamento. Isso consiste em garantir que plataformas e toolchains específicas da linguagem sejam definidas, que a lógica de linguagem leia toolchains pela nova API em vez de flags antigas como --crosstool_top e que config_settings sejam selecionados na nova API em vez de flags antigas.

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

É por isso que essa é uma migração contínua.

Meta

Essa 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 toolchains certas para //:myplatform.
  2. As dependências do seu 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 que todos os projetos consumidores possam encontrar.

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, o build já vai funcionar com uma invocação como:

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

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

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

Para que seu projeto seja criado, você precisa verificar o seguinte:

  1. //:myplatform precisa existir. Geralmente, é responsabilidade do proprietário do projeto definir plataformas, porque projetos diferentes segmentam máquinas diferentes. Consulte Plataformas padrão.

  2. As toolchains que você quer usar precisam existir. Se você estiver usando toolchains de estoque, os proprietários da linguagem precisarão incluir instruções sobre como registrá-las. Se você estiver escrevendo suas próprias toolchains personalizadas, precisará registrá-las no seu WORKSPACE ou com --extra_toolchains.

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

  4. Se o build mistura linguagens que oferecem e não oferecem suporte a plataformas, talvez você precise de mapeamentos de plataforma para ajudar as linguagens legadas a trabalhar com a nova API. Consulte Mapeamentos de plataforma para mais detalhes.

Se você ainda tiver problemas, entre em contato com o suporte.

Plataformas padrão

Os proprietários do projeto 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 como padrão uma 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 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 select() ofereça suporte ao maior número 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 um motivo para ser mais específico.

Para selecionar um ou mais constraint_values, 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",
    },
)

Mais detalhes aqui.

Os selects em --cpu, --crosstool_top etc. não entendem --platforms. Ao migrar seu projeto para plataformas, você precisa convertê-los em 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 as flags em partes do gráfico de build. Se o projeto usa uma transição que define --cpu, --crossstool_top ou outras flags legadas, as regras que leem --platforms não vão ver 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 durante a migração. janela.

Migrar seu conjunto de regras

Se você tem um conjunto de regras e quer oferecer suporte a plataformas, é necessário:

  1. Ter uma lógica de regra que resolva toolchains com a API de toolchain. Consulte a API de toolchain (ctx.toolchains).

  2. Opcional: defina uma flag --incompatible_enable_platforms_for_my_language para que a lógica de regra resolva toolchains alternadamente 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 disponibilize-as aos usuários pelas instruções de registro da regra (detalhes).

  5. Garanta que os select()s e as transições de configuração ofereçam suporte a plataformas. Esse é o maior desafio. É particularmente desafiador para projetos multilíngues (que podem falhar se todas as linguagens não puderem ler --platforms).

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

Propriedades comuns da plataforma

Propriedades de plataforma comuns e entre linguagens, 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 da regra. Isso permite que você mantenha a propriedade clara dos conceitos específicos de que suas regras são responsáveis.

Se as regras usam SOs ou CPUs de finalidade personalizada, elas precisam ser declaradas no repositório da regra em vez de @platforms.

Mapeamentos de plataforma

Os mapeamentos de plataforma são uma API temporária que permite que a lógica com reconhecimento de plataforma seja misturada com a lógica legada no mesmo build. Essa é uma ferramenta simples que só tem como objetivo suavizar incompatibilidades com diferentes prazos de migração.

Um mapeamento de plataforma é um mapa de um platform() para um conjunto correspondente de flags legadas ou o inverso. Por 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, inclusive nas 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.

Consulte o design de mapeamentos de plataforma para mais detalhes.

Análise da API

Um platform é uma coleção de destinos constraint_value:

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

Um constraint_value é uma propriedade da máquina. Os valores do mesmo "tipo" são agrupados em um comum constraint_setting:

constraint_setting(name = "os")
constraint_value(
    name = "linux",
    constraint_setting = ":os",
)
constraint_value(
    name = "mac",
    constraint_setting = ":os",
)

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

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 toolchain que pode ser executada na máquina de build e criar binários para //:myplatform. Isso é conhecido como resolução de toolchain.

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

Para mais informações, consulte este link.

Perguntas

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

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

Consulte também