Migración a plataformas

Informar un problema Ver fuente Nightly · 7.4 . 7.3 · 7.2 · 7.1 · 7.0 · 6.5

Bazel tiene una compatibilidad sofisticada para modelar plataformas y cadenas de herramientas para compilaciones multiarquitectura y de compilación cruzada.

En esta página, se resume el estado de esta compatibilidad.

Consulta lo siguiente:

Estado

C++

Las reglas de C++ usan plataformas para seleccionar cadenas de herramientas cuando se configura --incompatible_enable_cc_toolchain_resolution.

Esto significa que puedes configurar un proyecto de C++ con lo siguiente:

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

en lugar de la heredada:

bazel build //:my_cpp_project` --cpu=... --crosstool_top=...  --compiler=...

Esta opción se habilitará de forma predeterminada en Bazel 7.0 (#7260).

Para probar tu proyecto de C++ con plataformas, consulta Cómo migrar tu proyecto y Cómo configurar cadenas de herramientas de C++.

Java

Las reglas de Java usan plataformas para seleccionar cadenas de herramientas.

Esto reemplaza las marcas heredadas --java_toolchain, --host_java_toolchain, --javabase y --host_javabase.

Consulta Java y Bazel para obtener más información.

Android

Las reglas de Android usan plataformas para seleccionar cadenas de herramientas cuando se configura --incompatible_enable_android_toolchain_resolution.

Esto significa que puedes configurar un proyecto de Android con lo siguiente:

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

en lugar de con marcas heredadas, como --android_crosstool_top, --android_cpu y --fat_apk_cpu.

Esta opción se habilitará de forma predeterminada en Bazel 7.0 (#16285).

Para probar tu proyecto de Android con plataformas, consulta Cómo migrar tu proyecto.

Apple

Las reglas de Apple no son compatibles con las plataformas y aún no están programadas para admitirlas.

Aún puedes usar las APIs de la plataforma con compilaciones de Apple (por ejemplo, cuando compilas con una combinación de reglas de Apple y C++) con asignaciones de plataformas.

Otros idiomas

  • Las reglas de Go son totalmente compatibles con las plataformas.
  • Las reglas de Rust son totalmente compatibles con las plataformas.

Si tienes un conjunto de reglas de idioma, consulta Cómo migrar tu conjunto de reglas para agregar compatibilidad.

Segundo plano

Se introdujeron las plataformas y las cadenas de herramientas para estandarizar la forma en que los proyectos de software se orientan a diferentes arquitecturas y realizan compilaciones cruzadas.

Esto se inspiró en la observación de que los mantenedores de lenguajes ya lo estaban haciendo de manera ad hoc e incompatible. Por ejemplo, las reglas de C++ usaban --cpu y --crosstool_top para declarar una CPU y una cadena de herramientas de destino. Ninguno de estos modelos representa correctamente una “plataforma”. Esto generó compilaciones incorrectas y poco prácticas.

Java, Android y otros lenguajes desarrollaron sus propias marcas con fines similares, ninguna de las cuales interoperó entre sí. Esto hacía que las compilaciones multilenguaje fueran desordenadas y complicadas.

Bazel está diseñado para proyectos grandes, multiplataforma y multilingües. Esto requiere una compatibilidad más sólida con estos conceptos, incluida una API estándar clara.

Necesidad de migración

La actualización a la nueva API requiere dos esfuerzos: lanzar la API y actualizar la lógica de reglas para usarla.

El primero está terminado, pero el segundo está en curso. Esto consiste en garantizar que se definan las plataformas y las cadenas de herramientas específicas del lenguaje, que la lógica del lenguaje lea las cadenas de herramientas a través de la nueva API en lugar de las marcas anteriores, como --crosstool_top, y que los config_setting seleccionen en la nueva API en lugar de las marcas anteriores.

Este trabajo es sencillo, pero requiere un esfuerzo distinto para cada idioma, además de una advertencia justa para que los propietarios del proyecto realicen pruebas en función de los próximos cambios.

Por este motivo, esta es una migración en curso.

Objetivo

Esta migración se completa cuando todos los proyectos se compilan con el formulario:

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

Esto implica lo siguiente:

  1. Las reglas de tu proyecto eligen las cadenas de herramientas correctas para //:myplatform.
  2. Las dependencias de tu proyecto eligen las cadenas de herramientas correctas para //:myplatform.
  3. //:myplatform hace referencia a declaraciones comunes de CPU, OS y otras propiedades genéricas independientes del lenguaje.
  4. Todos los select() relevantes coinciden correctamente con //:myplatform.
  5. //:myplatform se define en un lugar claro y accesible: en el repositorio de tu proyecto si la plataforma es exclusiva de tu proyecto, o en algún lugar común que todos los proyectos de consumo puedan encontrar.

Las marcas anteriores, como --cpu, --crosstool_top y --fat_apk_cpu, dejarán de estar disponibles y se quitarán en cuanto sea seguro hacerlo.

En última instancia, esta será la única forma de configurar las arquitecturas.

Cómo migrar tu proyecto

Si compilas con lenguajes que admiten plataformas, tu compilación ya debería funcionar con una invocación como la siguiente:

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

Consulta el Estado y la documentación de tu idioma para obtener detalles precisos.

Si un idioma requiere una marca para habilitar la compatibilidad con la plataforma, también debes establecer esa marca. Consulta Estado para obtener más información.

Para que se compile tu proyecto, debes verificar lo siguiente:

  1. //:myplatform debe existir. Por lo general, es responsabilidad del propietario del proyecto definir las plataformas, ya que los diferentes proyectos se orientan a máquinas diferentes. Consulta Plataformas predeterminadas.

  2. Las cadenas de herramientas que deseas usar deben existir. Si usas cadenas de herramientas estándar, los propietarios de los lenguajes deben incluir instrucciones para registrarlas. Si escribes tus propias cadenas de herramientas personalizadas, debes register en tu WORKSPACE o con --extra_toolchains.

  3. Los select() y las transiciones de configuración deben resolverse correctamente. Consulta select() y Transiciones.

  4. Si tu compilación combina idiomas que admiten plataformas y otros que no, es posible que necesites asignaciones de plataformas para ayudar a que los idiomas heredados funcionen con la nueva API. Consulta Asignaciones de plataformas para obtener más información.

Si los problemas persisten, comunícate con nosotros para obtener asistencia.

Plataformas predeterminadas

Los propietarios de proyectos deben definir plataformas explícitas para describir las arquitecturas para las que desean compilar. Luego, se activan con --platforms.

Cuando no se establece --platforms, Bazel usa de forma predeterminada un platform que representa la máquina de compilación local. Se genera automáticamente en @platforms//host (con el alias @bazel_tools//tools:host_platform), por lo que no es necesario definirlo de forma explícita. Asigna el OS y el CPU de la máquina local con los constraint_value declarados en @platforms.

select()

Los proyectos pueden select() en objetivos constraint_value, pero no en plataformas completas. Esto es intencional para que select() admita la mayor variedad posible de máquinas. Una biblioteca con fuentes específicas de ARM debería admitir todas las máquinas con ARM, a menos que haya motivos para ser más específicos.

Para seleccionar uno o más constraint_value, usa lo siguiente:

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

Esto equivale a seleccionar de forma tradicional en --cpu:

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

Obtén más información aquí.

Los select en --cpu, --crosstool_top, etc. no entienden --platforms. Cuando migres tu proyecto a plataformas, debes convertirlo a constraint_values o usar asignaciones de plataformas para admitir ambos estilos durante la migración.

Transiciones

Las transiciones de Starlark cambian las marcas en partes de tu gráfico de compilación. Si tu proyecto usa una transición que establece --cpu, --crossstool_top o alguna otra marca heredada, las reglas que leen --platforms no verán estos cambios.

Cuando migres tu proyecto a plataformas, debes convertir cambios como return { "//command_line_option:cpu": "arm" } a return { "//command_line_option:platforms": "//:my_arm_platform" } o usar asignaciones de plataformas para admitir ambos estilos durante la migración.

Cómo migrar tu conjunto de reglas

Si tienes un conjunto de reglas y deseas admitir plataformas, debes hacer lo siguiente:

  1. Haz que la lógica de reglas resuelva las cadenas de herramientas con la API de toolchain. Consulta la API de la cadena de herramientas (ctx.toolchains).

  2. Opcional: Define una marca --incompatible_enable_platforms_for_my_language para que la lógica de reglas resuelva de forma alterna las cadenas de herramientas a través de la API nueva o las marcas anteriores, como --crosstool_top, durante las pruebas de migración.

  3. Define las propiedades relevantes que conforman los componentes de la plataforma. Consulta Propiedades comunes de la plataforma.

  4. Define cadenas de herramientas estándar y haz que sean accesibles para los usuarios a través de las instrucciones de registro de tu regla (detalles).

  5. Asegúrate de que las select() y las transiciones de configuración admitan plataformas. Este es el desafío más grande. Es particularmente desafiante para los proyectos multilingües (que pueden fallar si todos los idiomas no pueden leer --platforms).

Si necesitas combinar reglas que no admiten plataformas, es posible que necesites asignaciones de plataformas para cerrar la brecha.

Propiedades comunes de la plataforma

Las propiedades comunes de la plataforma multilenguaje, como OS y CPU, deben declararse en @platforms. Esto fomenta el uso compartido, la estandarización y la compatibilidad entre idiomas.

Las propiedades únicas de tus reglas deben declararse en el repositorio de la regla. Esto te permite mantener una propiedad clara sobre los conceptos específicos de los que son responsables tus reglas.

Si tus reglas usan SO o CPUs de propósito personalizado, deben declararse en el repositorio de tu regla en lugar de @platforms.

Asignaciones de plataformas

Las asignaciones de plataformas son una API temporal que permite que la lógica compatible con la plataforma se combine con la lógica heredada en la misma compilación. Esta es una herramienta directa que solo tiene como objetivo suavizar las incompatibilidades con diferentes plazos de migración.

Una asignación de plataforma es un mapa de un platform() a un conjunto correspondiente de marcas heredadas o viceversa. Por ejemplo:

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

Bazel usa esto para garantizar que todos los parámetros de configuración, tanto basados en la plataforma como heredados, se apliquen de forma coherente durante la compilación, incluso a través de transiciones.

De forma predeterminada, Bazel lee las asignaciones del archivo platform_mappings en la raíz de tu lugar de trabajo. También puedes configurar --platform_mappings=//:my_custom_mapping.

Consulta el diseño de asignaciones de plataformas para obtener más información.

Revisión de la API

Un platform es una colección de objetivos constraint_value:

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

Un constraint_value es una propiedad de la máquina. Los valores del mismo “tipo” se agrupan en un constraint_setting común:

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

Un toolchain es una regla de Starlark. Sus atributos declaran las herramientas de un lenguaje (como compiler = "//mytoolchain:custom_gcc"). Sus proveedores pasan esta información a las reglas que deben compilarse con estas herramientas.

Las cadenas de herramientas declaran los constraint_value de las máquinas a las que pueden orientarse (target_compatible_with = ["@platforms//os:linux"]) y las máquinas en las que pueden ejecutarse (exec_compatible_with = ["@platforms//os:mac"]).

Cuando compilas $ bazel build //:myproject --platforms=//:myplatform, Bazel selecciona automáticamente una cadena de herramientas que se puede ejecutar en la máquina de compilación y compila objetos binarios para //:myplatform. Esto se conoce como resolución de cadena de herramientas.

El conjunto de cadenas de herramientas disponibles se puede registrar en WORKSPACE con register_toolchains o en la línea de comandos con --extra_toolchains.

Para obtener más información, consulta este artículo.

Preguntas

Si necesitas asistencia general y tienes preguntas sobre el cronograma de migración, comunícate con bazel-discuss o con los propietarios de las reglas correspondientes.

Para hablar sobre el diseño y la evolución de las APIs de la plataforma o la cadena de herramientas, comunícate con bazel-dev.

Consulta también