Bazel tiene compatibilidad sofisticada para modelar plataformas y cadenas de herramientas. Integrar esto con proyectos reales requiere una cooperación cuidadosa entre los propietarios del código, los encargados del mantenimiento de las reglas y los desarrolladores principales de Bazel.
En esta página, se resume el propósito de las plataformas y se muestra cómo compilar con ellas.
Resumen: Las APIs de la plataforma y la cadena de herramientas de Bazel están disponibles, pero no funcionarán en todas partes hasta que se actualicen todas las reglas de lenguaje, los select()
y otras referencias heredadas. Realizamos este proceso con frecuencia. Con el tiempo, todas las compilaciones se basarán en la plataforma.
Sigue leyendo para ver dónde se ajustan tus compilaciones.
Para obtener documentación más formal, consulta lo siguiente:
Fondo
Se introdujeron plataformas y cadenas de herramientas para estandarizar la forma en que los proyectos de software se dirigen a diferentes máquinas y se compilan con las herramientas de lenguaje adecuadas.
Esta es una incorporación relativamente reciente a Bazel. Se inspiró en la observación de que los encargados del mantenimiento de los idiomas ya lo hacían de formas incompatibles y ad hoc. Por ejemplo, las reglas de C++ usan --cpu
y --crosstool_top
para establecer la CPU objetivo y la cadena de herramientas de C++ de una compilación. Ninguno de estos modela correctamente una "plataforma". Los intentos históricos de hacerlo causaron compilaciones imprecisas y torpes.
Estas marcas tampoco controlan la compilación de Java, que desarrolló su propia interfaz independiente con --java_toolchain
.
Bazel está diseñado para proyectos grandes, multiplataforma y en varios lenguajes. Esto exige un respaldo más fundamentado para estos conceptos, incluidas APIs claras que fomenten la interoperabilidad del lenguaje y del proyecto. Para eso sirven estas nuevas APIs.
Migración
Las APIs de la plataforma y la cadena de herramientas solo funcionan cuando los proyectos las usan. Esto no es trivial, ya que la lógica de las reglas, las cadenas de herramientas, las dependencias y los select()
s de un proyecto deben admitirlos. Esto requiere una secuencia de migración cuidadosa para que todos los proyectos y sus dependencias funcionen correctamente.
Por ejemplo, las reglas de C++ de Bazel admiten plataformas. Pero las Reglas de Apple no lo hacen. Es posible que a tu proyecto de C++ no le interese Apple. Sin embargo, otras sí lo hacen, por lo que aún no es seguro habilitar globalmente las plataformas para todas las compilaciones de C++.
En el resto de esta página, se describe esta secuencia de migración y cómo y cuándo pueden adaptarse tus proyectos.
Objetivo
La migración de la plataforma de Bazel se completa cuando todos los proyectos se compilan con el siguiente formulario:
bazel build //:myproject --platforms=//:myplatform
Esto implica lo siguiente:
- Las reglas que usa tu proyecto pueden inferir cadenas de herramientas correctas a partir de
//:myplatform
. - Las reglas que usan las dependencias de tu proyecto pueden inferir cadenas de herramientas correctas a partir de
//:myplatform
. - Cualquiera de las dos: Los proyectos que dependen del tuyo admiten
//:myplatform
o tu proyecto admite las APIs heredadas (como--crosstool_top
). //:myplatform
hace referencia a [declaraciones comunes][Common Platform Declaration]{: .external} deCPU
,OS
y otros conceptos genéricos que admiten la compatibilidad automática entre proyectos.- Todos los proyectos relevantes de
select()
comprenden las propiedades de la máquina que implica//:myplatform
. //:myplatform
se define en un lugar claro y reutilizable: en el repo de tu proyecto si la plataforma es única para tu proyecto o, de lo contrario, en algún lugar donde todos los proyectos que puedan usar esta plataforma puedan encontrarla.
Las APIs anteriores se quitarán en cuanto se alcance este objetivo. Entonces, esta será la forma estándar en que los proyectos seleccionarán plataformas y cadenas de herramientas.
¿Debería usar plataformas?
Si solo quieres compilar un proyecto o realizar una compilación cruzada, debes seguir la documentación oficial del proyecto.
Si eres mantenedor de un proyecto, un idioma o una cadena de herramientas, con el tiempo querrás admitir las nuevas APIs. Si esperas a que se complete la migración global o habilitas la opción antes, dependerá de tus necesidades específicas de valor y costo:
Valor
- Puedes
select()
o elegir cadenas de herramientas en las propiedades exactas que te interesan en lugar de marcas codificadas, como--cpu
. Por ejemplo, varias CPU pueden admitir el mismo conjunto de instrucciones. - Compilaciones más correctas Si realizas una
select()
con--cpu
en el ejemplo anterior y, luego, agregas una CPU nueva que admite el mismo conjunto de instrucciones, laselect()
no reconoce la CPU nueva. Sin embargo, elselect()
en las plataformas sigue siendo preciso. - Experiencia del usuario más sencilla Todos los proyectos comprenden lo siguiente:
--platforms=//:myplatform
. No es necesario usar varias marcas específicas del idioma en la línea de comandos. - Diseño de lenguaje más simple. Todos los lenguajes comparten una API común para definir cadenas de herramientas, usar cadenas de herramientas y seleccionar la cadena de herramientas adecuada para una plataforma.
- Los destinos se pueden omitir en la fase de compilación y prueba si son incompatibles con la plataforma de destino.
Costos
- Es posible que los proyectos dependientes que aún no admiten plataformas no funcionen automáticamente con el tuyo.
- Para que funcionen, es posible que se requiera un mantenimiento temporal adicional.
- La coexistencia de APIs nuevas y heredadas requiere una orientación más cuidadosa para los usuarios y, así, evitar confusiones.
- Las definiciones canónicas de las propiedades comunes, como
OS
yCPU
, aún están en desarrollo y pueden requerir contribuciones iniciales adicionales. - Las definiciones canónicas para las cadenas de herramientas específicas del idioma aún están en desarrollo y pueden requerir contribuciones iniciales adicionales.
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_value
s 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
.
Consulta aquí para obtener más información.
Estado
La compatibilidad actual de la plataforma varía según el idioma. Todas las reglas principales de Bazel se están trasladando a las plataformas. Sin embargo, este proceso llevará tiempo. Esto se debe a tres motivos principales:
La lógica de la regla debe actualizarse para obtener información de la nueva API de toolchain (
ctx.toolchains
) y dejar de leer la configuración heredada, como--cpu
y--crosstool_top
. Esto es relativamente sencillo.Los mantenedores de la cadena de herramientas deben definir las cadenas de herramientas y hacer que los usuarios puedan acceder a ellas (en los repositorios de GitHub y las entradas de
WORKSPACE
). Esto es técnicamente sencillo, pero debe organizarse de forma inteligente para mantener una experiencia del usuario fácil.También son necesarias las definiciones de la plataforma (a menos que compiles para la misma máquina en la que se ejecuta Bazel). En general, los proyectos deben definir sus propias plataformas.
Los proyectos existentes deben migrarse. También se deben migrar los
select()
s y las transiciones. 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 diseñas un nuevo conjunto de reglas, debes admitir plataformas desde el principio. Esto hace que tus reglas sean compatibles automáticamente con otras reglas y proyectos, y su valor aumenta a medida que la API de la plataforma se vuelve más omnipresente.
Propiedades comunes de la plataforma
Las propiedades de la plataforma, como OS
y CPU
, que son comunes en todos los proyectos, se deben declarar en un lugar estándar y centralizado. Esto fomenta la compatibilidad entre proyectos y lenguajes.
Por ejemplo, si MyApp tiene un select()
en constraint_value
@myapp//cpus:arm
y SomeCommonLib tiene un select()
en @commonlib//constraints:arm
, estos activan sus modos de "activación" con criterios incompatibles.
Las propiedades comunes a nivel global se declaran en el repositorio @platforms
(por lo que la etiqueta canónica para el ejemplo anterior es @platforms//cpu:arm
). Las propiedades comunes a un idioma deben declararse en los repositorios de sus respectivos idiomas.
Plataformas predeterminadas
En general, los propietarios del proyecto deben definir plataformas explícitas para describir los tipos de máquinas para los 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 @local_config_platform//:host
, 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
.
C++
Las reglas de C++ de Bazel usan plataformas para seleccionar cadenas de herramientas cuando configuras --incompatible_enable_cc_toolchain_resolution
(#7260).
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=...
Si tu proyecto es puramente de C++ y no depende de proyectos que no son de C++, puedes usar plataformas de forma segura siempre y cuando tus select
s y transiciones sean compatibles. Consulta #7260 y Configuración de cadenas de herramientas de C++ para obtener más orientación.
Este modo no está habilitado de forma predeterminada. Esto se debe a que los proyectos de Apple aún configuran las dependencias de C++ con --cpu
y --crosstool_top
(ejemplo). Por lo tanto, esto depende de que las reglas de Apple migren a las plataformas.
Java
Las reglas de Java de Bazel usan plataformas.
Esto reemplaza las marcas heredadas --java_toolchain
, --host_java_toolchain
, --javabase
y --host_javabase
.
Para obtener información sobre cómo usar las marcas de configuración, consulta el manual de Bazel y Java. Para obtener más información, consulta el documento de diseño.
Si aún usas marcas heredadas, sigue el proceso de migración que se describe en el problema núm. 7849.
Android
Las reglas de Android de Bazel usan plataformas para seleccionar cadenas de herramientas cuando configuras --incompatible_enable_android_toolchain_resolution
.
Esta opción no está habilitada de forma predeterminada. Sin embargo, la migración está en proceso.
Apple
Las reglas de Apple de Bazel aún no admiten plataformas para seleccionar cadenas de herramientas de Apple.
Tampoco admiten dependencias de C++ habilitadas para la plataforma porque usan el --crosstool_top
heredado para establecer la cadena de herramientas de C++. Hasta que se complete la migración, puedes combinar proyectos de Apple con C++ habilitado para la plataforma con asignaciones de plataforma (ejemplo).
Otros idiomas
- Las reglas de Rust de Bazel son totalmente compatibles con las plataformas.
- Las reglas de Go de Bazel admiten por completo las plataformas (detalles).
Si diseñas reglas para un idioma nuevo, usa plataformas para seleccionar las cadenas de herramientas de tu idioma. Consulta la documentación de las cadenas de herramientas para obtener una buena guía.
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 select
s 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 el período de 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 el período de migración.
Cómo usar las plataformas hoy en día
Si solo quieres compilar o realizar una compilación cruzada de un proyecto, debes seguir la documentación oficial del proyecto. Los mantenedores de idiomas y proyectos son quienes determinan cómo y cuándo realizar la integración con las plataformas, y qué valor ofrece.
Si eres mantenedor de un proyecto, un idioma o una cadena de herramientas, y tu compilación no usa plataformas de forma predeterminada, tienes tres opciones (además de esperar la migración global):
Activa la marca "use platforms" para los idiomas de tu proyecto (si tienen una) y realiza las pruebas que necesites para ver si los proyectos que te interesan funcionan.
Si los proyectos que te interesan aún dependen de marcas heredadas, como
--cpu
y--crosstool_top
, úsalas junto con--platforms
:bazel build //:my_mixed_project --platforms==//:myplatform --cpu=... --crosstool_top=...
Esto tiene un costo de mantenimiento (debes asegurarte manualmente de que la configuración coincida). Sin embargo, esto debería funcionar en ausencia de transiciones no autorizadas.
Escribe asignaciones de plataformas para admitir ambos estilos asignando la configuración de estilo
--cpu
a las plataformas correspondientes y viceversa.
Asignaciones de plataformas
Platform mappings es una API temporal que permite que la lógica basada en la plataforma y la lógica heredada coexistan en la misma compilación durante el período de baja de la última.
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 --apple_platform_type=macos" to "//platform:macos".
--cpu=darwin
--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 aquí para obtener todos los detalles.
Preguntas
Si tienes preguntas generales o necesitas asistencia sobre el cronograma de migración, comunícate con bazel-discuss@googlegroups.com 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@googlegroups.com.