2 puntos por GN⁺ 2023-12-19 | 1 comentarios | Compartir por WhatsApp
  • gccrs es un proyecto iniciado en 2014 para implementar un compilador de Rust dentro de GCC; todavía está lejos de completarse, pero ha avanzado hacia la compilación de la biblioteca estándar y su inclusión en GCC 14
  • El proyecto tomó como objetivo Rust 1.49 en lugar de seguir el ritmo de las versiones más recientes de Rust, pero debido a dependencias internas de la biblioteca estándar, al final también tuvo que implementar funciones como const generics
  • La compilación de core y alloc sigue bloqueada por la resolución de nombres de macros, las macros decoradoras, los intrinsics del compilador de LLVM que no existen en GCC y la ausencia de un borrow checker
  • rustc_codegen_gcc es un enfoque más maduro que reutiliza partes de rustc y usa GCC para la generación de código en el backend; desde octubre de 2023 puede compilar Rust for Linux sin parches adicionales
  • gccrs tiene motivaciones claras como los plugins de seguridad de GCC, el análisis estático, las arquitecturas no compatibles con LLVM y Rust for Linux, pero su utilidad práctica aún es más limitada que la de rustc_codegen_gcc

Objetivo de gccrs y su situación actual

  • gccrs es un proyecto que busca implementar un compilador de Rust dentro de la GNU Compiler Collection (GCC)
  • Comenzó en 2014 y, según reportes del proyecto posteriores a la cobertura previa de LWN, ha mostrado avances
  • En 2022 apuntaba a ser incluido en GCC 13, pero no lo logró; según el informe mensual de noviembre de 2023, ahora apunta a GCC 14
    • GCC 14 se maneja como una versión con posible lanzamiento a mediados de 2024
  • En EuroRust 2023, en octubre de 2023, Arthur Cohen presentó “The road to compiling the standard library with gccrs”, donde explicó el trabajo para compilar la biblioteca estándar de Rust y por qué aún no puede compilarse

Por qué eligieron apuntar a Rust 1.49

  • gccrs tomó como objetivo Rust 1.49 en vez de seguir continuamente la versión más reciente de Rust
  • Rust 1.49 fue lanzado a finales de 2020 y es la última versión anterior al soporte de const generics, que pasó a estar disponible de forma general en Rust 1.50
  • El proyecto intentó evitar const generics, pero como ya se usaba internamente incluso en la biblioteca estándar de Rust 1.49, terminó siendo imposible ignorarlo
  • const generics ya fue implementado por completo y dejó de ser un obstáculo
  • gccrs no busca crear un superconjunto de Rust ni un lenguaje separado llamado “GNU Rust”
    • La meta es reproducir incluso la salida, los bugs y los comportamientos peculiares de rustc
    • Para ello usa tanto la suite de pruebas de Rust como la de GCC

Bloqueos en la compilación de la biblioteca estándar

  • La biblioteca estándar de Rust está compuesta por varios crates
  • gccrs está trabajando en el soporte para compilar los dos crates más importantes, core y alloc
    • core implementa funciones base de la biblioteca estándar, como tipos primitivos y macros
    • alloc se encarga de la asignación de memoria en el heap y de varios tipos de contenedores
  • Actualmente gccrs no puede compilar estos crates por la falta de las siguientes funciones
    • La resolución de nombres de macros no funciona correctamente
    • El soporte para macros decoradoras no está completo
    • No hay borrow checker, por lo que no puede verificarse correctamente la seguridad del código
    • Hay que implementar intrinsics del compilador de LLVM que no existen en GCC
  • La ausencia del borrow checker no impide compilar como tal, pero sí evita comprobar adecuadamente la seguridad del código Rust

Macros procedurales e integración con GCC

  • En GNU Tools Cauldron de septiembre de 2023, Pierre-Emmanuel Patry presentó los avances hacia la inclusión en GCC 14, con foco en el trabajo sobre macros
  • La implementación de macros procedurales (procedural macro) requiere cambios en el sistema de compilación de GCC
  • Las macros procedurales son macros funcionales que emiten un flujo de tokens, no texto fuente simple como las macros de C o C++
  • En Rust se implementan con el crate integrado proc_macro
  • Son difíciles de implementar, pero permiten funciones muy potentes
    • Decoradores #[attribute]
    • Decoradores #[derive()]
    • Generación de lenguajes específicos de dominio basada en evaluación en tiempo de compilación
  • Según la charla de GNU Cauldron, gccrs tenía más de 800 commits pendientes de upstream hacia GCC

Por qué quieren aprovechar el ecosistema GCC para Rust

  • Una de las principales motivaciones de gccrs es poder aprovechar los plugins de seguridad de GCC también en código Rust
  • GCC cuenta con varios plugins que ayudan con depuración, análisis estático y hardening, y todos operan sobre la representación intermedia de GCC
  • gccrs quiere permitir un flujo de trabajo en el que desarrolladores de Rust puedan reutilizar plugins existentes de GCC
  • Cohen dio como ejemplo que durante mucho tiempo los programadores de C han cometido errores como no cerrar descriptores de archivo, por lo que existen muchos plugins para detectar eso
  • El objetivo es poder usar plugins existentes de GCC y analizadores estáticos para detectar bugs en código Rust unsafe

Áreas donde ya se está usando parcialmente

  • Según Cohen, la comunidad homebrew de Sega Dreamcast ya está usando gccrs para crear juegos nuevos para la consola Dreamcast
  • El interés de esa comunidad se debe a que el backend LLVM de rustc no soporta la arquitectura Hitachi SH-4 de la consola, mientras que GCC sí
  • gccrs sigue incompleto, pero aun así resulta útil en este tipo de casos de uso embebidos
  • Ya es posible hacer análisis estático de código Rust unsafe usando plugins de GCC
  • En el proceso de desarrollo de gccrs quedaron expuestas funciones del lenguaje cuya especificación no estaba suficientemente definida, como Deref y la resolución de nombres de macros, y el proyecto también ha podido contribuir a ampliar la especificación de Rust
    • Rust todavía no tiene una especificación oficial, pero se está trabajando en ella según RFC 3355

Funciones clave que siguen en desarrollo

  • A gccrs todavía le faltan muchas funciones centrales de un compilador de Rust
  • Entre las principales funciones no implementadas o aún en desarrollo están
    • async/await
    • Intrinsics de LLVM que no existen en GCC
    • La macro format_args!() que usan macros de salida como println!()
    • El borrow checker que hace cumplir las reglas de referencias de Rust
  • La solución más prometedora para el borrow checker es el proyecto separado Polonius
  • Cohen dijo que es muy probable que gccrs integre Polonius en los próximos meses
  • Jakub Dupak ha logrado avances en este trabajo en los últimos meses
  • Polonius es una biblioteca que implementa un borrow checker semánticamente equivalente al borrow checker actual de rustc
    • Usa un algoritmo distinto para calcular la duración de las referencias
    • A largo plazo busca resolver limitaciones y casos borde del borrow checker actual de rustc
    • Si madura lo suficiente, es posible que rustc también adopte Polonius en el futuro

Por qué se necesita format_args!()

  • Según el informe mensual de gccrs de noviembre de 2023, ya comenzó el trabajo sobre la macro format_args!()
  • format_args!() es una macro auxiliar que construye los argumentos que se pasan a macros de formateo de cadenas
  • Esta función está relacionada con los traits Display y Debug
  • Se necesita para preparar los argumentos que se pasan a macros como format!() y println!()
  • Sin format_args!(), un programa Rust no puede generar salida con formato
  • Por eso es una función necesaria incluso antes de que gccrs pueda compilar un programa “Hello, World”
  • También se menciona como referencia un artículo de blog de Mara Bos que explica format_args!() en profundidad

Diferencias frente a rustc_codegen_gcc

  • rustc_codegen_gcc es otro proyecto de Rust basado en GCC, distinto de gccrs
  • Es más maduro que gccrs, pero su alcance es más limitado
  • No consiste en implementar por completo un compilador de Rust desde cero
  • Usa la biblioteca libgccjit para conectarse con la API del backend LLVM de rustc
  • Gran parte de la compilación la realiza rustc, y en etapas posteriores se utiliza GCC
  • Aunque el nombre libgccjit incluye JIT, rustc_codegen_gcc está orientado a compilación ahead-of-time
  • Su objetivo principal es permitir la generación de código Rust en plataformas que LLVM no soporta
  • En octubre de 2023, rustc_codegen_gcc ya podía compilar Rust for Linux sin parches adicionales
  • Durante el último año añadió soporte para SIMD y optimización en tiempo de enlazado
    • Ambas funciones habían sido señaladas antes como causa de fallos en las pruebas
  • En su charla de EuroRust, Cohen recomendó varias veces usar rustc_codegen_gcc por ahora en lugar de gccrs
  • rustc_codegen_gcc ya fue integrado upstream en el repositorio del lenguaje Rust

Rust for Linux y la brecha de versiones

  • Rust for Linux es una iniciativa para añadir soporte de Rust al kernel de Linux
  • Cohen mencionó el kernel de Linux como una motivación central del proyecto gccrs
    • Esto se debe a que muchas personas vinculadas al kernel prefieren que el kernel pueda compilarse usando únicamente la toolchain GNU
  • Actualmente el proyecto Rust for Linux documenta como métodos para compilar el código Rust del kernel a rustc o a rustc_codegen_gcc
  • El kernel también documenta versiones mínimas soportadas para varias herramientas de compilación
    • En el caso de rustc, no se maneja una versión mínima sino una versión que debe coincidir exactamente
    • La versión actualmente soportada de rustc es 1.73.0, lanzada en octubre de 2023
  • Entre Rust 1.49, que es el objetivo de gccrs, y Rust 1.73.0, que requiere Rust for Linux, existe una gran diferencia
  • El soporte para Rust for Linux es una meta explícita de gccrs, pero esa brecha de versiones hace que todavía esté bastante lejos

Evaluación general

  • El repositorio de gccrs tiene más de 3,000 commits desde el 1 de enero de 2023
  • Durante el último año, el proyecto ha mostrado avances considerables
  • Pero como el alcance de implementar un compilador completo de Rust desde cero es enorme, todavía no está en un estado utilizable para casi ningún propósito práctico
  • rustc_codegen_gcc ya fue fusionado en el repositorio upstream de Rust y se está usando de verdad en Rust for Linux
  • Aún no se ha llegado al punto de tener varias implementaciones independientes del compilador de Rust en uso amplio, pero se está más cerca de esa dirección

1 comentarios

 
GN⁺ 2023-12-19
Comentarios de Hacker News
  • Solo con lo que afirma el artículo, la motivación de gccrs se ve algo débil
    La preferencia por los plugins de seguridad de GCC o por el toolchain GNU en el kernel de Linux explica por qué alguien querría usar GCC como backend, pero no explica por qué hace falta un frontend duplicado
    Ojalá Rust no repita el error de C++, donde el desarrollo multiplataforma se complica por diferencias en switches entre compiladores, niveles de soporte del lenguaje y bugs específicos de cada plataforma
    Así que estaría bien que explicaran por qué gccrs es un mejor enfoque que rustc_codegen_gcc; este último parece poder lograr el mismo objetivo con mucho menos esfuerzo y riesgo

    • Tener otra implementación de Rust puede servir como auditoría para validar la especificación de Rust y reducir el comportamiento indefinido
      Si te topas con un bug del compilador en MSVC, puedes reportarlo y seguir trabajando cambiándote a GCC, pero en Rust hoy no existe esa opción
    • Rust ya está aprendiendo de los errores de C++
      Como se cita, un ejemplo es el cuidado de no querer convertirse en un superconjunto de Rust
      El problema de C/C++ surgió porque los proveedores de compiladores competían entre sí por ser “mejores”, y múltiples frontends suelen tener la ventaja de sacar a la luz muchos bugs e implementaciones incorrectas
    • No entiendo por qué esta pregunta sigue apareciendo
      No es que Rust sea sagrado en algún sentido y esté prohibido reescribir el frontend, y seguir haciendo bootstrap de Rust en arquitecturas nuevas continúa siendo doloroso
      En arquitecturas que LLVM no soporta, tampoco hay un compilador de Rust que funcione
      codegen_rust_gcc también tiene el mismo problema de bootstrap que el compilador actual de Rust, y hay que agregar soporte de arquitectura en varias partes de Rust, algo que sus mantenedores han sido reacios a hacer
      Así que si en un futuro cercano aparece un compilador de Rust utilizable de inmediato y eso permite volver a compilar bibliotecas escritas en Rust incluso en arquitecturas como Alpha sin demasiado dolor, sería muy bienvenido
    • Siguiendo esa lógica, habría que preguntarle a la comunidad de LLVM por qué no siguió usando DragonEgg y en cambio creó Clang, Clang++, libc++, etc.
      Ya existían GCC, G++, libstdc++, y el frontend C++ de EDG
      GCC, Clang, MSVC y otros compiladores se complementan entre sí, atienden distintos objetivos y mercados, y ayudan a que el lenguaje se fortalezca conforme a la especificación en lugar de depender de las características accidentales de una sola implementación
      El GNU Toolchain Project, el LLVM Project y el proyecto Rust han tenido problemas, así que es mejor no depender de un solo punto de falla, y la redundancia y la antifragilidad son aliadas
    • Cuando se dice que Rust debe aprender de los errores de C++ y C, me pregunto si eso significa aprender de los errores de los lenguajes más duraderos, influyentes y ampliamente distribuidos de la historia
      Me resulta confuso preferir ver mal los estándares de lenguaje y no decir “este código es C99/C++11”, sino “este código funciona en el binario/código fuente de rustc con hash SHA256 e49d560cd008344edf745b8052ef714b07595808898c835f17f962a10012f964
  • Rust necesita un estándar del lenguaje
    https://blog.m-ou.se/rust-standard/
    https://rust-lang.github.io/rfcs/3355-rust-spec.html
    https://github.com/rust-lang/rfcs/pull/3355
    Hay muchas organizaciones e industrias que no adoptarán Rust hasta que exista un estándar
    C, C++, C#, e incluso JavaScript (ECMAScript) tienen un estándar del lenguaje, así que no hay razón para que Rust no lo tenga
    C: https://www.iso.org/standard/74528.html
    C++: https://isocpp.org/std/the-standard
    C#: https://learn.microsoft.com/en-us/dotnet/csharp/language-ref...
    JavaScript / ECMAScript: https://ecma-international.org/publications-and-standards/st...

    • Ese RFC ya fue aprobado y, de hecho, ya empezó a avanzar
      El progreso ha sido decepcionantemente lento, pero el proyecto sigue vivo y es posible que el próximo año tome velocidad
      https://blog.rust-lang.org/inside-rust/2023/11/15/spec-visio...
    • La entrada del blog de Mara, es decir, el primer enlace, en realidad se inclina más por la postura de que Rust esencialmente no necesita un estándar, porque ya cuenta con mecanismos para agregar funcionalidades y mantener compatibilidad
    • Gracias a la especificación de Ferrocene, Rust puede usarse también en esas industrias
    • Go tiene una especificación realmente buena y múltiples implementaciones
      https://go.dev/ref/spec
    • Como respuesta a la idea de que muchas organizaciones e industrias no lo adoptarán sin un estándar, Rust está funcionando bien incluso sin esas organizaciones e industrias
      No veo por qué habría que cambiar algo que está funcionando
  • Me sorprende que haya tantas reacciones negativas a GCC-RS
    Considero que un lenguaje sin múltiples implementaciones es bastante pobre

    • Antes eso era casi una idea aceptada, sobre todo por C/C++, pero hoy es mucho más debatible
      El consenso en la comunidad de Rust parece ser que el enfoque actual —un solo compilador que por definición es el estándar, mucha documentación, una especificación mínima para industrias donde la seguridad es esencial y especificaciones para algunas subáreas de módulos— conserva la mayoría de las ventajas de tener varias implementaciones y evita sus desventajas
    • A largo plazo, el problema es la estabilidad de la sintaxis y evitar la inflación de funciones por extensiones/atributos
      En C eso se ha sufrido de verdad, y C++ ya está casi más allá de toda salvación por su complejidad absurda y extraña
      Sin eso, es difícil que aparezcan implementaciones alternativas realistas
    • Personalmente entiendo el valor de tener varias implementaciones, pero el problema es que se construya sobre GCC
      La toolchain de GNU es un desastre y no entiendo cómo se desarrolla realmente sobre ella
      No lo digo por ideología; literalmente no entiendo cómo se arma el entorno de desarrollo del propio GCC
      He tenido la mala suerte de hacer bootstrap unas cuantas veces, y fue de lo peor que he visto funcionar en software
  • Me gusta la parte sobre que la comunidad homebrew de Sega Dreamcast pueda crear juegos nuevos con gccrs, y que se pueda hacer análisis estático de código Rust unsafe con plugins de GCC
    El backend LLVM de rustc no soporta la arquitectura Hitachi SH-4 de la Dreamcast, pero GCC sí, así que incluso gccrs en estado incompleto sirve para este tipo de uso embebido

    • Esto es un poco engañoso
      Para eso no hace falta un frontend de GCC, basta con el backend de GCC
  • Ahora probablemente veremos soporte de Rust también en arquitecturas como Alpha, SuperH y VAX, que LLVM no soporta pero GCC sí

    • También entra mips64, cuyo soporte rustc abandonó recientemente después de no lograr conseguir financiamiento/recursos de Loongson
      https://github.com/rust-lang/compiler-team/issues/648
      El mayor problema de la forma de pensar al estilo LLVM es que usa el soporte de arquitecturas como una manera de sacar apoyo de las empresas de hardware, es decir, puestos de desarrolladores pagados
      GNU puede tener criterios de integración molestamente altos, pero una vez que algo entra y queda soportado, lo mantiene a largo plazo
      Es como la diferencia entre comprar y rentar: meter soporte en GCC cuesta mucho más tiempo de desarrollo, pero una vez dentro, se queda
    • Incluso en arquitecturas ya soportadas, parece que habrá opciones adicionales de configuración
      Por ejemplo, hace poco me enteré de que en RISC-V GCC soporta el objetivo RV32E, mientras que LLVM no
    • Quiero ver pronto código máquina de Rust saliendo para PDP-11
      La última vez que revisé, en GCC todavía funcionaba la compilación independiente de C
  • Por experiencia, me parece un gran error que gccrs intente replicar la salida de rustc, incluidos sus bugs y rarezas, en vez de crear un lenguaje especial “GNU Rust”
    Rust no tiene una especificación; hay documentos de referencia, pero explícitamente no son normativos
    Un lenguaje no documentado más allá de una única implementación de referencia tiene una debilidad a largo plazo
    El objetivo de asegurar que el código existente funcione en ambas implementaciones es razonable, pero prometer compatibilidad de bugs es una mala decisión porque fosiliza malas decisiones y errores
    Microsoft dedica mucho personal a corregir bugs de seguridad y confiabilidad sin dejar de ejecutar programas viejos, y Rust no necesita cargar con eso tan temprano en su vida
    Si quieres que el lenguaje evolucione, tienes que aceptar aseguramiento y control de calidad
    La calidad no se puede inyectar después con pruebas; hay que hacer que funcione bien desde la arquitectura y el diseño, y mediante procesos como revisiones de diseño y de código, de modo que aunque falle, falle en la dirección correcta
    Estándares fuertes como Common Lisp, C++ y FORTRAN aceptaron esa idea, y lenguajes débiles pero cercanos a un estándar de facto, como Python, también pueden ganar popularidad, pero que cambiar sea difícil se ve en la larga transición de Python 2 a 3 y en la poca cantidad de implementaciones

    • Si se encuentra un bug grande, supongo que se reporta upstream y se cambian ambas implementaciones
  • Me sumo tarde en esta parte del hilo, pero esto no necesariamente es algo bueno
    Las distribuciones no pueden seguir el ritmo de lenguajes que sacan versiones nuevas cada pocos meses, así que ya es difícil usar rustc o Go como paquetes de la distribución
    Ahora mismo, de forma sorprendente, hay sistemas donde GCC dejó de hacer falta y fue eliminado, y solo se mantienen Go y Rust upstream para actualizar software existente
    Hace unos meses, cuando actualicé Go por un CVE, fue una pesadilla ver que las apps basadas en Go habían guardado su propio entorno de Go en hasta cuatro lugares distintos

  • Linux ya se puede compilar con Clang si uno quiere, y usar una toolchain completamente basada en LLVM
    No parece que el esfuerzo duplicado de desarrollar y mantener esto por la “pureza” de GNU valga la pena

    • No es un tema de pureza, sino de opciones
      La comunidad ClangBuiltLinux argumentaba que Linux no debía depender de un solo compilador, pero cuando llegó Rust, bastantes de esas mismas personas de pronto empezaron a ver bien depender de uno solo
    • Creo que aquí hay un malentendido
      No se trata de atar el kernel exclusivamente a GNU, sino solo de permitir elegir una toolchain GNU pura