Migração para plataformas

Informar um problema Ver código-fonte Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

O Bazel tem suporte sofisticado para modelagem de plataformas e toolchains para builds de várias arquiteturas e com compilação cruzada.

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 você pode configurar um projeto 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 Como migrar o projeto e Como configurar os conjuntos de ferramentas do C++.

Java

As regras Java usam plataformas para selecionar conjuntos de ferramentas.

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 cadeias de ferramentas 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 sinalizações 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 Como migrar seu projeto.

Apple

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

Ainda é possível usar APIs de plataforma com builds da Apple (por exemplo, ao criar com uma mistura de regras da Apple e C++) com mapeamentos de plataforma.

Outros idiomas

Se você tiver um conjunto de regras de idioma, consulte Como migrar seu conjunto de regras para adicionar suporte.

Contexto

Plataformas e 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 linguagem já estavam fazendo isso de maneira ad hoc e incompatível. Por exemplo, as regras do C++ usaram --cpu e --crosstool_top para declarar uma CPU de destino e um conjunto de ferramentas. Nenhum deles modela corretamente uma "plataforma". Isso produzia builds estranhos e incorretos.

Java, Android e outras linguagens evoluíram as próprias sinalizações para fins semelhantes, nenhuma das quais interoperou entre si. Isso tornou os builds em várias linguagens confusos e complicados.

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

Necessidade de migração

O upgrade para a nova API exige dois esforços: 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 toolchains específicos da linguagem sejam definidos, que a lógica da 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 requer um esforço distinto para cada idioma, além de uma boa aviso para que os proprietários do projeto testem as próximas mudanças.

Por isso, essa migração está em andamento.

Meta

Essa migração é concluída quando todos os projetos são 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 seu projeto escolhem as cadeias de ferramentas 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 local claro e acessível: no repositório do projeto, se a plataforma for exclusiva para o projeto, ou em algum lugar comum que todos os projetos que consomem possam encontrar.

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

Essa será a única maneira de configurar arquiteturas.

Como migrar seu projeto

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

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

Consulte Status e a documentação do idioma para saber mais detalhes.

Se um idioma 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, verifique o seguinte:

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

  2. As cadeias de ferramentas que você quer usar precisam existir. Se você estiver usando toolchains padrão, os proprietários da linguagem precisam incluir instruções sobre como fazer o registro. Se você estiver escrevendo seus próprios conjuntos de ferramentas personalizados, será necessário register no WORKSPACE ou com --extra_toolchains.

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

  4. Se o build misturar idiomas que oferecem e não oferecem suporte a plataformas, talvez seja necessário mapeamentos de plataforma para ajudar os idiomas legados 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 eles querem criar. Elas são acionadas 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 @platforms//host (com o alias @bazel_tools//tools:host_platform). Portanto, 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 de destino, mas não em plataformas completas. Isso é intencional para que select() ofereça suporte a máquinas o mais variado 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 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.

selects 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 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 migração. janela.

Migrando seu conjunto de regras

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

  1. Fazer com que a lógica de regras resolva os conjuntos de ferramentas com a API correspondente. Consulte API do conjunto de ferramentas (ctx.toolchains).

  2. Opcional: defina uma flag --incompatible_enable_platforms_for_my_language para que a lógica de regra resolva alternadamente as cadeias de ferramentas 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. Definir os conjuntos de ferramentas padrão e torná-los acessíveis aos usuários por meio das instruções de registro da regra (detalhes)

  5. Verifique se as select()s e as transições de configuração são compatíveis com as plataformas. 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ê precisar misturar com regras que não oferecem suporte a plataformas, talvez seja necessário usar mapeamentos de plataforma para preencher a lacuna.

Propriedades comuns da plataforma

As propriedades comuns da plataforma em vários idiomas, 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 regras precisam ser declaradas no repositório da regra. Isso permite que você mantenha a propriedade clara dos conceitos específicos pelos quais suas regras são responsáveis.

Se as regras usarem sistemas operacionais ou CPUs de uso personalizado, elas precisarão ser declaradas no repo da regra em comparação com @platforms.

Mapeamentos de plataforma

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

Um mapeamento de plataforma é um mapeamento de um platform() para um conjunto correspondente de flags legados 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_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 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.

Consulte o design dos mapeamentos de plataforma para mais detalhes.

Revisão da API

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

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",
)

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.

Os conjuntos de ferramentas declaram os constraint_values de máquinas em 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 um conjunto de ferramentas que pode ser executado 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.

Clique aqui para mais informações.

Perguntas

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

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

Consulte também