2 pontos por GN⁺ 2023-12-19 | 1 comentários | Compartilhar no WhatsApp
  • gccrs é um projeto iniciado em 2014 para implementar um compilador Rust dentro do GCC; ainda está longe de ficar pronto, mas avançou em direção à compilação da biblioteca padrão e à inclusão no GCC 14
  • O projeto adotou Rust 1.49 como meta em vez de acompanhar o Rust mais recente em rápida mudança, mas por causa de dependências internas da biblioteca padrão acabou tendo de implementar recursos como const generics
  • A compilação de core e alloc ainda está bloqueada por resolução de nomes de macros, macros decoradoras, intrinsics de compilador do LLVM que não existem no GCC e pela ausência de um borrow checker
  • rustc_codegen_gcc é uma abordagem mais madura que reutiliza partes do rustc e usa o GCC como backend de geração de código; em outubro de 2023 já conseguia compilar Rust for Linux sem patches adicionais
  • O gccrs tem motivações claras, como plugins de segurança do GCC, análise estática, arquiteturas sem suporte do LLVM e Rust for Linux, mas sua utilidade prática ainda é mais limitada que a do rustc_codegen_gcc

Objetivos do gccrs e situação atual

  • gccrs é um projeto para implementar um compilador Rust dentro do GNU Compiler Collection (GCC)
  • Começou em 2014 e, segundo um relatório do projeto após uma cobertura anterior da LWN, houve progresso
  • Em 2022, a meta era entrar no GCC 13, mas isso não foi alcançado; no relatório mensal de novembro de 2023, a meta passou a ser a inclusão no GCC 14
    • O GCC 14 é tratado como uma versão com possibilidade de lançamento em meados de 2024
  • Na EuroRust 2023, em outubro de 2023, Arthur Cohen apresentou “The road to compiling the standard library with gccrs”, explicando o trabalho para compilar a biblioteca padrão do Rust e por que isso ainda não foi possível

Por que mirar no Rust 1.49

  • O gccrs optou por mirar no Rust 1.49 em vez de tentar acompanhar continuamente a versão mais recente do Rust
  • O Rust 1.49 foi lançado no fim de 2020 e é a última versão anterior ao suporte a const generics, disponibilizado para uso geral no Rust 1.50
  • O projeto tentou evitar const generics, mas esse recurso já era usado internamente na biblioteca padrão do Rust 1.49, então acabou sendo impossível ignorá-lo
  • const generics foi implementado por completo depois disso e não é mais um obstáculo
  • O gccrs não quer criar um superconjunto de Rust nem uma linguagem separada chamada “GNU Rust”
    • O objetivo é reproduzir até a saída, os bugs e os comportamentos peculiares do rustc
    • Para isso, usa tanto a suíte de testes do Rust quanto a do GCC

O que ainda bloqueia a compilação da biblioteca padrão

  • A biblioteca padrão do Rust é composta por vários crates
  • O gccrs está trabalhando no suporte à compilação dos dois crates mais importantes, core e alloc
    • core implementa recursos fundamentais da biblioteca padrão, como tipos primitivos e macros
    • alloc lida com alocação de memória no heap e vários tipos de contêiner
  • Hoje o gccrs ainda não consegue compilar esses crates por falta dos recursos abaixo
    • O comportamento da resolução de nomes de macros ainda não está correto
    • O suporte a macros decoradoras não está completo
    • Não há borrow checker, então a segurança do código não pode ser verificada corretamente
    • É preciso implementar intrinsics de compilador do LLVM que não existem no GCC
  • A ausência do borrow checker não impede a compilação em si, mas impede a verificação adequada de segurança do código Rust

Macros procedurais e integração com o GCC

  • No GNU Tools Cauldron de setembro de 2023, Pierre-Emmanuel Patry apresentou o progresso rumo à inclusão no GCC 14, com foco no trabalho com macros
  • A forma de implementar macros procedurais (procedural macro) exige mudanças no sistema de build do GCC
  • Em vez de gerar apenas texto-fonte simples como macros de C ou C++, macros procedurais são macros funcionais que emitem streams de tokens
  • Em Rust, são implementadas pelo crate embutido proc_macro
  • Macros procedurais são difíceis de implementar, mas permitem recursos poderosos
    • Decoradores #[attribute]
    • Decoradores #[derive()]
    • Criação de linguagens específicas de domínio com avaliação em tempo de compilação
  • Segundo a apresentação no GNU Cauldron, o gccrs tinha mais de 800 commits que ainda precisavam ser enviados para upstream no GCC

Por que aproveitar o ecossistema do GCC para Rust

  • Uma das principais motivações do gccrs é usar os plugins de segurança do GCC também em código Rust
  • O GCC tem vários plugins que ajudam em depuração, análise estática e hardening, e eles operam sobre a representação intermediária do GCC
  • O gccrs quer permitir um fluxo de trabalho em que desenvolvedores Rust reutilizem plugins já existentes do GCC
  • Cohen deu como exemplo que programadores C há muito tempo cometem erros como esquecer de fechar descritores de arquivo, então existem muitos plugins para detectar isso
  • O objetivo é aproveitar plugins e analisadores estáticos já existentes do GCC para encontrar bugs em código Rust unsafe

Áreas em que ele já é usado parcialmente

  • Segundo Cohen, a comunidade homebrew do Sega Dreamcast está usando o gccrs para criar novos jogos para o console Dreamcast
  • O motivo do interesse é que o backend LLVM do rustc não oferece suporte à arquitetura Hitachi SH-4 do console, enquanto o GCC oferece
  • O gccrs ainda está incompleto, mas já ajuda nesse tipo de caso de uso embarcado
  • Também já é possível fazer análise estática de código Rust unsafe usando plugins do GCC
  • No processo de desenvolvimento do gccrs, surgiram recursos da linguagem cuja especificação ainda não estava suficientemente definida, como Deref e resolução de nomes de macros, e o projeto pôde contribuir para a elaboração da especificação do Rust
    • Atualmente o Rust não tem uma especificação oficial, mas o trabalho está em andamento conforme o RFC 3355

Recursos centrais ainda em desenvolvimento

  • O gccrs ainda não tem muitos recursos essenciais de um compilador Rust
  • Entre os principais recursos ainda não implementados ou em desenvolvimento estão
    • async/await
    • Intrinsics do LLVM que não existem no GCC
    • A macro format_args!() usada por macros de saída como println!()
    • O borrow checker, que aplica as regras de referências do Rust
  • A solução mais promissora para o borrow checker é o projeto separado Polonius
  • Cohen disse que é muito provável que o gccrs integre o Polonius em alguns meses
  • Jakub Dupak fez progresso nesse trabalho nos últimos meses
  • O Polonius é atualmente uma biblioteca que implementa um borrow checker semanticamente equivalente ao do rustc
    • Usa um algoritmo diferente para calcular o tempo de vida das referências
    • No longo prazo, o objetivo é resolver limitações e corner cases do borrow checker atual do rustc
    • Quando amadurecer, é possível que o rustc também adote o Polonius no futuro

Por que format_args!() é necessário

  • Segundo o relatório mensal do gccrs de novembro de 2023, o trabalho na macro format_args!() foi iniciado
  • format_args!() é uma macro auxiliar que monta os argumentos passados às macros de formatação de strings
  • Esse recurso está ligado aos traits Display e Debug
  • Ele é necessário para preparar os argumentos entregues a macros como format!() e println!()
  • Sem format_args!(), programas Rust não conseguem produzir saída formatada
  • Portanto, esse recurso já é necessário antes mesmo de o gccrs conseguir compilar um programa “Hello, World”
  • Como explicação aprofundada de format_args!(), também é citado um post de blog de Mara Bos

Diferença em relação ao rustc_codegen_gcc

  • rustc_codegen_gcc é outro projeto Rust baseado em GCC, diferente do gccrs
  • Ele é mais maduro que o gccrs, mas tem escopo mais limitado
  • Não segue a abordagem de implementar um compilador Rust completo do zero
  • Usa a biblioteca libgccjit para se conectar à API do backend LLVM do rustc
  • Grande parte da compilação é feita pelo rustc, e o GCC entra nas etapas posteriores
  • Embora libgccjit tenha “JIT” no nome, o rustc_codegen_gcc tem como objetivo a compilação ahead-of-time
  • O principal objetivo é permitir a geração de código Rust em plataformas sem suporte do LLVM
  • Em outubro de 2023, o rustc_codegen_gcc já conseguia compilar Rust for Linux sem patches adicionais
  • No último ano, o projeto adicionou suporte a SIMD e otimização em tempo de link
    • Esses dois recursos haviam sido apontados anteriormente como causa de falhas nos testes
  • Na apresentação da EuroRust, Cohen recomendou várias vezes usar rustc_codegen_gcc por enquanto, em vez do gccrs
  • O rustc_codegen_gcc já entrou no repositório upstream da linguagem Rust

Rust for Linux e a diferença de versões

  • Rust for Linux é uma iniciativa para adicionar suporte a Rust ao kernel Linux
  • Cohen apontou o kernel Linux como uma motivação central do projeto gccrs
    • Isso porque muitas pessoas ligadas ao kernel preferem que ele possa ser compilado apenas com a toolchain GNU
  • Atualmente, o projeto Rust for Linux documenta como formas de compilar o código Rust do kernel o rustc ou o rustc_codegen_gcc
  • O kernel também documenta versões mínimas suportadas para várias ferramentas de build
    • O rustc não é tratado como versão mínima, mas como uma versão que precisa corresponder exatamente
    • A versão de rustc atualmente suportada é a 1.73.0, lançada em outubro de 2023
  • Há uma grande diferença entre o Rust 1.49 que o gccrs tem como alvo e o Rust 1.73.0 exigido pelo Rust for Linux
  • O suporte ao Rust for Linux é um objetivo declarado do gccrs, mas essa diferença de versões mostra que ele ainda está bem distante

Avaliação geral

  • O repositório do gccrs tem mais de 3.000 commits desde 1º de janeiro de 2023
  • No último ano, o projeto mostrou progresso considerável
  • Mas, como o escopo de implementar um compilador Rust completo do zero é enorme, ele ainda não está em um estado utilizável para quase qualquer finalidade prática
  • O rustc_codegen_gcc já foi integrado ao repositório upstream do Rust e está em uso real no Rust for Linux
  • Ainda não chegamos ao ponto em que a linguagem Rust tem várias implementações independentes de compilador, mas estamos nos aproximando dessa direção

1 comentários

 
GN⁺ 2023-12-19
Opiniões do Hacker News
  • Só pelas afirmações do texto, a motivação do gccrs parece um tanto fraca
    Plugins de segurança do GCC ou a preferência da comunidade do kernel Linux pela toolchain GNU explicam por que alguém gostaria de usar o GCC como backend, mas não explicam por que é necessário um frontend duplicado
    Espero que Rust não repita o erro do C++, em que o desenvolvimento multiplataforma fica difícil por causa de diferenças entre opções de compiladores, níveis de suporte à linguagem e bugs específicos de plataforma
    Por isso seria bom explicar por que o gccrs é uma abordagem melhor que rustc_codegen_gcc; esta última parece capaz de atingir o mesmo objetivo com muito menos esforço e risco

    • Ter mais uma implementação de Rust pode servir como uma auditoria para validar a especificação da linguagem e reduzir comportamentos indefinidos
      Se você encontra um bug de compilador no MSVC, pode reportá-lo e depois mudar para o GCC para continuar trabalhando, mas em Rust hoje não existe essa opção
    • Rust já está aprendendo com os erros do C++
      Como foi citado, o cuidado para não se tornar um superset de Rust é um exemplo disso
      O problema de C/C++ surgiu porque fornecedores de compiladores competiam entre si para serem “melhores”, e múltiplos frontends geralmente têm a vantagem de revelar muitos bugs e implementações incorretas
    • Não entendo por que essa pergunta continua aparecendo
      Rust não é sagrado em nenhum sentido que proíba uma reescrita do frontend, e fazer bootstrap de Rust em novas arquiteturas ainda é doloroso
      Em arquiteturas não suportadas pelo LLVM, também não há um compilador Rust funcional
      codegen_rust_gcc tem o mesmo problema de bootstrap do compilador Rust existente, e seria preciso adicionar suporte de arquitetura em várias partes de Rust, algo que os mantenedores de Rust têm evitado
      Então, se em um futuro próximo houver um compilador Rust utilizável de imediato, permitindo voltar a compilar bibliotecas reescritas em Rust em arquiteturas como Alpha sem grande sofrimento, isso seria muito bem-vindo
    • Por essa lógica, dá para perguntar por que a comunidade LLVM não continuou usando o DragonEgg e criou Clang, Clang++, libc++ etc.
      Já existiam GCC, G++, libstdc++, o frontend C++ da EDG
      GCC, Clang, MSVC e outros compiladores se complementam, atendem a objetivos e mercados diferentes, e ajudam a tornar a linguagem robusta conforme a especificação, em vez de depender de características acidentais de uma única implementação
      O GNU Toolchain Project, o LLVM Project e o projeto Rust já tiveram problemas, então é melhor não depender de um ponto único de falha; redundância e antifragilidade são nossas amigas
    • Quando dizem que Rust deve aprender com os erros de C++ e C, será que querem dizer aprender com os erros das linguagens mais duradouras, influentes e amplamente distribuídas da história?
      É confuso ver alguém encarar padrões de linguagem como algo ruim e preferir dizer “este código funciona no binário/fonte do rustc com hash SHA256 e49d560cd008344edf745b8052ef714b07595808898c835f17f962a10012f964” em vez de “este código é C99/C++11”
  • Rust precisa de um padrão de linguagem
    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
    Há muitas organizações e indústrias que não vão adotar Rust até que exista um padrão
    C, C++, C# e até JavaScript (ECMAScript) têm padrões de linguagem; não há motivo para Rust não ter
    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...

    • Esse RFC já foi aprovado e, na prática, o trabalho começou
      O progresso é frustrantemente lento, mas o projeto está vivo, e há chance de ganhar velocidade no ano que vem
      https://blog.rust-lang.org/inside-rust/2023/11/15/spec-visio...
    • O post do blog da Mara, ou seja, o primeiro link, está mais para a posição de que Rust essencialmente não precisa de um padrão, já que já tem meios de adicionar funcionalidades e manter compatibilidade
    • Graças à especificação Ferrocene, Rust pode ser usado também nessas indústrias
    • Go tem uma especificação realmente bem-feita e várias implementações
      https://go.dev/ref/spec
    • Como contraponto à afirmação de que muitas organizações e indústrias não vão adotá-lo sem um padrão: Rust está indo bem mesmo sem essas organizações e indústrias
      Não vejo por que mudar algo que funciona bem
  • É surpreendente haver tanta reação negativa ao GCC-RS
    Acho que uma linguagem fica bem pobre se não tiver múltiplas implementações

    • Antigamente isso era senso comum, especialmente por causa de C/C++, mas hoje é algo muito mais controverso
      O consenso da comunidade Rust parece ser que o modelo atual — um único compilador que é o padrão por definição, muita documentação, uma especificação mínima para uso industrial crítico em segurança e especificações de alguns subdomínios de módulos — traz a maior parte das vantagens de múltiplas implementações evitando as desvantagens
    • No longo prazo, o problema é a estabilidade da sintaxe e impedir a explosão de funcionalidades causada por extensões/atributos
      Isso acontece de fato em C, e C++ já está quase sem salvação por causa de uma complexidade absurda e esquisita
      Sem isso, é difícil surgir uma implementação alternativa realista
    • Pessoalmente, entendo o valor de múltiplas implementações, mas o problema é construí-la em cima do GCC
      O toolchain GNU é uma bagunça, e eu realmente não sei como alguém desenvolve sobre ele
      Não é uma questão ideológica; literalmente não entendo como configurar o ambiente de desenvolvimento do próprio GCC
      Tive o azar de fazer bootstrap algumas vezes, e foi a coisa com pior comportamento que já vi em software
  • Gosto da parte em que a comunidade homebrew do Sega Dreamcast cria jogos novos com gccrs, e em que dá para fazer análise estática de código Rust unsafe com plugins do GCC
    A arquitetura Hitachi SH-4 do Dreamcast não é suportada pelo backend LLVM do rustc, mas é suportada pelo GCC, então mesmo o gccrs inacabado ajuda nesse tipo de uso embarcado

    • Isso é um pouco enganoso
      Para isso, não é necessário um frontend GCC; basta o backend GCC
  • Agora talvez vejamos suporte a Rust também em arquiteturas como Alpha, SuperH e VAX, que o LLVM não suporta e o GCC suporta

    • Isso também inclui mips64, cujo suporte o rustc abandonou recentemente depois de tentar, sem sucesso, obter financiamento/recursos da Loongson
      https://github.com/rust-lang/compiler-team/issues/648
      O maior problema da mentalidade do LLVM é usar suporte a arquiteturas como meio de extrair apoio de empresas de hardware, isto é, vagas de desenvolvedores pagos
      O GNU pode ter critérios irritantemente altos para mesclar mudanças, mas, uma vez que algo entra e passa a ser suportado, ele é mantido no longo prazo
      É como a diferença entre comprar e alugar; leva muito mais tempo de desenvolvimento para colocar suporte no GCC, mas, uma vez que entra, permanece
    • Também deve surgir mais opções de configuração para arquiteturas já suportadas
      Por exemplo, soube recentemente que, em RISC-V, o GCC suporta o alvo RV32E, mas o LLVM não
    • Quero muito ver logo código de máquina PDP-11 gerado a partir de Rust
      Da última vez que verifiquei, a compilação C standalone ainda funcionava no GCC
  • Pela minha experiência, é um grande erro o gccrs não criar uma linguagem especial chamada “GNU Rust” e tentar replicar a saída do rustc, inclusive seus bugs e peculiaridades
    Rust não tem uma especificação; há documentação de referência, mas ela explicitamente não é normativa
    Uma linguagem não documentada, exceto por uma única implementação de referência, tem uma fraqueza de longo prazo
    O objetivo de garantir que código existente funcione nas duas implementações é razoável, mas, se prometerem até compatibilidade com bugs, acabarão fossilizando decisões ruins e bugs
    A Microsoft emprega muita gente para manter programas antigos funcionando ao mesmo tempo em que corrige bugs de segurança e confiabilidade, mas Rust não precisa assumir esse fardo tão cedo em seu ciclo de vida
    Se quiser evoluir a linguagem, é preciso aceitar garantia e controle de qualidade
    Qualidade não pode ser injetada depois com testes; é preciso fazê-la funcionar corretamente, e, mesmo quando falhar, falhar na direção certa, por meio de processos como arquitetura e design, revisão de design e de código
    Padrões fortes como Common Lisp, C++ e FORTRAN aceitaram essa crença, e linguagens fracas, quase como padrões de fato, como Python, também podem se tornar populares, mas sua dificuldade de mudança aparece na longa transição do Python 2 para o 3 e no pequeno número de implementações

    • Se encontrarem um bug grande, parece bastar reportá-lo ao upstream e mudar as duas implementações
  • Estou comentando tarde nesta thread, mas isso talvez não seja necessariamente uma coisa boa
    As distribuições já têm dificuldade de usar rustc ou Go como pacotes da própria distro porque não conseguem acompanhar linguagens que lançam versões novas a cada poucos meses
    Hoje, surpreendentemente, há sistemas que removeram o GCC por ele não ser mais necessário e mantêm apenas Go e Rust upstream para atualizar softwares existentes
    Alguns meses atrás, quando atualizei Go por causa de um CVE, foi um pesadelo ver que apps baseados em Go guardavam seus próprios ambientes Go em quatro lugares diferentes

  • Se quiser, o Linux já pode ser compilado com Clang e usar um toolchain inteiramente baseado em LLVM
    Esse esforço duplicado de desenvolver e manter isso pela “pureza” GNU não parece valer a pena

    • Não é uma questão de pureza, é uma questão de opções
      A comunidade ClangBuiltLinux argumentou que o Linux não deveria depender de um único compilador, mas, quando Rust chegou, muitos dessas mesmas pessoas de repente passaram a achar que um único compilador tudo bem
    • Parece haver um mal-entendido aqui
      Não se trata de prender o kernel exclusivamente ao GNU, mas apenas de permitir a escolha de um toolchain GNU puro