Migración a plataformas

Informar un problema Ver código fuente Nocturno · 8.4 · 8.3 · 8.2 · 8.1 · 8.0 · 7.6

Bazel tiene una compatibilidad sofisticada para modelar plataformas y cadenas de herramientas para compilaciones de varias arquitecturas y compilaciones cruzadas.

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 establece --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 estará habilitada de forma predeterminada en Bazel 7.0 (#7260).

Para probar tu proyecto de C++ con plataformas, consulta Migrating Your Project y Configuring C++ toolchains.

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

Android

Las reglas de Android usan plataformas para seleccionar cadenas de herramientas cuando se establece --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 estará habilitada de forma predeterminada en Bazel 7.0 (#16285).

Para probar tu proyecto de Android con plataformas, consulta Migración de tu proyecto.

Apple

Las reglas de Apple no admiten plataformas y aún no se programó su compatibilidad.

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

Otros idiomas

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

Fondo

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

Esto se inspiró en la observación de que los mantenedores de idiomas ya lo hacían de formas incompatibles y ad hoc. 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 modela correctamente una "plataforma". Esto generó compilaciones incómodas y incorrectas.

Java, Android y otros lenguajes desarrollaron sus propias marcas con fines similares, pero ninguna interoperaba con las demás. Esto hizo que las compilaciones en varios idiomas fueran confusas y complicadas.

Bazel está diseñado para proyectos grandes, multiplataforma y en varios lenguajes. Esto exige un respaldo más fundamentado para 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 las reglas para usarla.

La primera ya se completó, pero la segunda está en curso. Esto consiste en garantizar que se definan las plataformas y las cadenas de herramientas específicas del idioma, que la lógica del idioma lea las cadenas de herramientas a través de la nueva API en lugar de las marcas antiguas como --crosstool_top y que los config_settings seleccionen la nueva API en lugar de las marcas antiguas.

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 relación con los próximos cambios.

Por eso, 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 adecuadas para //:myplatform.
  2. Las dependencias de tu proyecto eligen las cadenas de herramientas adecuadas para //:myplatform.
  3. //:myplatform hace referencia a declaraciones comunes de CPU, OS y otras propiedades genéricas independientes del idioma.
  4. Todos los select()s pertinentes coinciden correctamente con //:myplatform.
  5. //:myplatform se define en un lugar claro y accesible: en el repo de tu proyecto si la plataforma es exclusiva de tu proyecto, o en algún lugar común donde todos los proyectos que consumen puedan encontrarlo.

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

Migra 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 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 dirigen a diferentes máquinas. Consulta Plataformas predeterminadas.

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

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

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

Si los problemas persisten, comunícate con el equipo de asistencia.

Plataformas predeterminadas

Los propietarios del proyecto 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. Esto 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 constraint_value destinos, 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 debe admitir todas las máquinas potenciadas por ARM, a menos que haya un motivo 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 tradicionalmente en --cpu:

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

Obtén más detalles aquí.

Los selects en --cpu, --crosstool_top, etcétera, no entienden --platforms. Cuando migres tu proyecto a las 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 las partes inferiores de tu gráfico de compilación. Si tu proyecto usa una transición que establece --cpu, --crossstool_top o cualquier otra marca heredada, las reglas que leen --platforms no verán estos cambios.

Cuando migres tu proyecto a las plataformas, debes convertir los 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. window.

Migra tu conjunto de reglas

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

  1. Haz que la lógica de la regla 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 la regla resuelva de forma alternativa las cadenas de herramientas a través de la nueva API o marcas antiguas, como --crosstool_top, durante las pruebas de migración.

  3. Define las propiedades pertinentes que componen los componentes de la plataforma. Consulta Propiedades comunes de la plataforma.

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

  5. Asegúrate de que las plataformas admitan las select()s y las transiciones de configuración. Este es el mayor desafío. Esto es especialmente difícil para los proyectos en varios idiomas (que pueden fallar si todos los idiomas no pueden leer --platforms).

Si necesitas combinar con 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 en todos los idiomas, como OS y CPU, se deben declarar en @platforms. Esto fomenta el uso compartido, la estandarización y la compatibilidad entre idiomas.

Las propiedades exclusivas de tus reglas se deben declarar en el repositorio de reglas. Esto te permite mantener una propiedad clara sobre los conceptos específicos de los que se encargan tus reglas.

Si tus reglas usan SO o CPU personalizados, estos deben declararse en el repositorio de tu regla en lugar de en @platforms.

Asignaciones de plataformas

Platform mappings es 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 simple que solo se usa para suavizar las incompatibilidades con diferentes períodos 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 los basados en la plataforma como los heredados, se apliquen de manera coherente durante toda la compilación, incluso a través de las transiciones.

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

Consulta el diseño de asignaciones de plataformas para obtener más detalles.

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 necesitan compilar con estas herramientas.

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

Cuando compila $ 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 archivos binarios para //:myplatform. Esto se conoce como resolución de la 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, haz clic aquí.

Preguntas

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

Para debatir 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