1 pontos por GN⁺ 3 시간 전 | 1 comentários | Compartilhar no WhatsApp
  • crustc é uma demo que converte todo o rustc 1.98.0-nightly (c712ea946 2026-06-16) em 46 milhões de linhas de código C, e ao compilar com GCC e make gera um compilador Rust funcional
  • A ferramenta-base cilly é um backend de compilador Rust que compila Rust para C, e este repositório é o showcase mais chamativo de um compilador compilando a si próprio
  • O cilly consulta o layout de tipos, tamanho, alinhamento, codificação de caracteres, formatos de inteiros etc. do compilador C e da plataforma de destino por meio de programas witness, gerando código C que aquele compilador C específico consegue aceitar
  • O principal objetivo é viabilizar o uso de Rust em hardware antigo ou incomum que não tem suporte de LLVM/GCC, mas possui compilador C, incluindo transparência de rede para se comunicar com um compilador C remoto via TCP
  • No momento, o C gerado tem como alvo ARM64 Linux, a ISA da estação de trabalho do autor, e toda a toolchain cilly ainda não está pronta para uso público, além de bugs de otimização ainda estarem sendo investigados

Demo de conversão do rustc para C

  • crustc é um repositório que converte o rustc 1.98.0-nightly (c712ea946 2026-06-16) em 46 milhões de linhas de código C
  • Esse código C pode ser compilado com GCC e make, e o resultado do build é um compilador Rust funcional
  • O exemplo de execução define o caminho da biblioteca LLVM e depois roda ./rustc/rustc --version, exibindo a mesma versão rustc 1.98.0-nightly
  • O compilador Rust gerado consegue compilar código e construir core, alloc e std
  • Além do código C, o projeto inclui alguns wrappers C++ do LLVM
    • O Rust usa C++ para expor algumas funcionalidades do LLVM
    • Esses wrappers dependem da versão do LLVM e são incômodos de compilar isoladamente, então são fornecidos pré-compilados

O papel do cilly

  • crustc é uma demo/teaser da nova toolchain de compilação Rust-para-C chamada cilly
  • A toolchain completa cilly tem como objetivo compilar código Rust do usuário para C ajustado a qualquer alvo
  • Este repositório foi montado para mostrar o cilly compilando o próprio compilador
  • cilly é uma biblioteca Rust e também um backend de compilador Rust, ou seja, compila Rust para C em forma de plugin
  • O autor afirma que vem trabalhando há 3 anos em compilar Rust para C e que, após tentativas públicas como rustc_codegen_clr e várias tentativas privadas, o cilly é a 14ª tentativa

Como o código é gerado para se adequar ao compilador C

  • A principal característica do cilly é que ele se adapta ao compilador C
  • Ele pode gerar programas witness para verificar o que um compilador e uma plataforma específicos suportam
    • Um exemplo é _Thread_local int KEYWORD_TLS_SUPPORTED;, que só compila se aquele compilador C suportar _Thread_local
  • O cilly tenta gerar código C que um compilador C específico consiga aceitar
  • Layout de tipos, tamanho, alinhamento, codificação de caracteres e formatos de inteiros são itens consultados
    • Na codificação de caracteres, ele verifica se é ASCII
    • Nos formatos de inteiros, ele verifica se é two's complement
  • Sempre que possível, usa fallbacks
  • Ele tenta evitar suposições fora do ANSI C e também tem contornos para comportamentos ligados a padrões modernos de C, como strict aliasing
  • Em casos raros, pode ser necessária uma suposição razoável, como o round-trip (void*)(uintptr_t)(ptr)
    • Essas suposições são documentadas e, quando possível, recebem asserts como CHAR_BIT = 8

Código C por alvo e restrições de ABI

  • O código C gerado pelo cilly é específico por compilador
    • O C gerado pelo cilly para Arm64 não pode simplesmente ser executado em riscv32
    • Mas é possível gerar separadamente um C do cilly para riscv32
  • O C gerado para o rustc neste repositório tem como alvo ARM64 Linux, por causa da ISA da estação de trabalho do autor
  • O código gerado pelo cilly é em geral compatível em ABI com o código compilado por um rustc comum
  • Em algumas plataformas, o rustc escolhe ABIs que não podem ser expressas em C, o que dificulta compatibilidade total
  • No Arm64, há uma restrição por causa do ponteiro de retorno de struct, o sret
    • Na maioria das plataformas, o sret é passado no mesmo registrador do primeiro argumento, permitindo usar o primeiro argumento como ponteiro de saída
    • No Arm64, o ponteiro sret é passado em outro registrador
    • O autor explica que o compilador C nativo precisaria escolher return-by-sret para structs pequenas, mas normalmente não faz isso para structs pequenas com menos de 16 bytes

Suporte a alvos antigos ou incomuns

  • Um dos principais objetivos deste projeto é permitir o uso de Rust em hardware antigo ou incomum que não tem suporte de LLVM/GCC, mas suporta C
  • Quando algum projeto migra de Rust para C, ou quando surge uma alternativa em Rust para um projeto em C, a falta de suporte a esses alvos pode ser apontada como desvantagem do Rust
  • O cilly envolve o rustc e o compilador C, convertendo o código Rust para C em tempo real
  • Do ponto de vista do usuário, isso fica mais próximo de definir qual compilador C usar para um alvo específico
  • O exemplo de configuração usa o triple sdcc_z180-unknown-none e os argumentos /usr/bin/sdcc, -mz180, --std-c89 e -c

Transparência de rede e compilador C remoto

  • O cilly tem transparência de rede e pode se comunicar com um compilador C via TCP
  • Se necessário, isso pode ser expandido para meios de comunicação ainda mais exóticos, como UART
  • Essa abordagem serve para resolver o paradoxo de bootstrap em plataformas que não têm um compilador C cruzado
  • É possível compilar e executar um pequeno servidor C no SO de destino, rodar o rustc em uma plataforma comum como Linux e deixar o cilly se comunicar pela rede
  • O autor compilou com sucesso um pequeno programa Rust para uma VM x86 com Plan 9 enquanto executava o rustc em Arm64 Linux
    • A saída do ambiente Plan 9 é gnot osversion 2000 cputype 386
    • O resultado de executar /tmp/hello_plan9 é Hello, world!
    • A saída de nm mostra o símbolo rust_begin_unwind

Geração de makefile

  • O cilly pode opcionalmente inserir marcadores dentro dos arquivos-objeto e salvar a IR em um diretório de cache
  • Depois, ele pode ler esses marcadores e separar funções e globais de acordo com o local onde foram definidas
  • Com base nisso, gera um diretório com makefile, permitindo compilar Rust usando apenas o compilador C e make

Condições de build e execução

  • O sistema usado no build da demo é um ARM64 Linux baseado em Ubuntu
    • A string do kernel é Linux spark-2773 6.17.0-1021-nvidia ... aarch64
  • As informações do compilador C usado são GCC 13.3.0 e Ubuntu LLD 18.1.3
  • Para compilar, é necessária a biblioteca LLVM correta, e a forma mais fácil é instalar aquela nightly com rustup install nightly-2026-06-16
  • O comando de build roda make -j20 com LLVM_LIB_DIR apontando para o caminho de libLLVM.so.22.1-rust-1.98.0-nightly
  • CFLAGS funciona, mas algumas flags podem deixar a compilação mais lenta
  • Otimização não é recomendada
    • A demo ainda é bruta, e a otimização pode causar problemas
    • Nessa escala, a otimização também leva muito tempo
  • Sem otimização, no computador do autor o build termina em poucos minutos
    • A medição foi 937.98s user, 123.77s system, 1352% cpu, 1:18.48 total
  • Com otimização ativada, a maior parte do código passa rápido, mas alguns arquivos Rust grandes podem travar o processo

Testes e problemas conhecidos

  • O teste de build é feito definindo LD_LIBRARY_PATH com a biblioteca LLVM nightly e ./rustc_driver, e então executando ./rustc/rustc --version
  • Para compilar programas comuns, é preciso construir std
    • Sem std, ocorre o erro error[E0463]: can't find crate for std
    • Para construir a biblioteca padrão, é preciso consultar BUILDING_STD.md
  • Um bug conhecido faz o crustc travar quando é executado no diretório em que foi compilado, ou seja, a raiz do repositório, por causa de um problema estranho de normalização de caminho
  • Em outros locais, ele funciona normalmente

Estado de publicação do cilly

  • O cilly ainda não está pronto para uso público
  • O autor afirma que pretende publicá-lo o mais rápido possível
  • Entre os motivos do atraso estão trabalho, uma tese universitária e uma lesão na mão
  • Um dos motivos de toda a toolchain cilly ainda não ter sido publicada é que bugs ligados a otimização ainda estão sendo investigados

1 comentários

 
GN⁺ 3 시간 전
Opiniões no Lobste.rs
  • É interessante que ele gere um programa-testemunha para verificar o que determinado compilador e plataforma suportam
    Parece bem estranho que as cadeias de build tradicionais em C com configure funcionem, em geral, desse jeito, mas faz sentido que este compilador, ou transpilador, siga esse padrão
    “14ª tentativa: cilly” — é uma persistência impressionante, e dá até inveja dessa tenacidade
  • Para comparação, há uma versão do compilador Zig inteiro convertida para C, que faz parte do procedimento normal de build a partir do código-fonte
    Ela tem 4,6 milhões de linhas, quase exatamente uma ordem de grandeza menor que este projeto. O código C gerado varia conforme o alvo, mas não conforme o compilador
  • Não sou programador de sistemas, mas fico curioso se um projeto como este poderia influenciar a escolha entre usar Rust ou Zig
    Entre as vantagens do Zig estão o suporte a vários alvos de compilação cruzada, uma toolchain auto-hospedada e a dependência opcional do LLVM; a promessa de compilar Rust para C em plataformas raras também parece um sinal mirando o lado do Zig
    • Só usar crustc não faria isso. Isso porque o compilador convertido também suporta apenas os mesmos alvos de compilação do compilador original
      Porém, é possível converter outros projetos Rust para C e executá-los e compilá-los em alvos que só dão suporte a C
      Ainda assim, não convém superestimar o impacto. É mais uma solução um pouco trabalhosa para um problema bem de nicho. O rustc já tem amplo suporte a alvos, e isso deve aumentar com o backend gcc
      As ferramentas de compilação cruzada do Zig são ótimas, mas têm mais a ver com aumentar a conveniência, especialmente na parte de C, que é mais complicada que Zig ou Rust; o significado de dar suporte a mais alvos é relativamente menor
      No fim, o suporte a alvos de Zig e Rust já é bem parecido, então dificilmente será um fator decisivo, e há diferenças muito mais importantes entre as duas linguagens
  • É legal, mas no fim não fica limitado às capacidades do LLVM?
    • Não vejo por que deveria ficar. crustc é apenas um exemplo do que cilly, uma toolchain que transforma Rust em C, consegue fazer
      A toolchain completa cilly compila o código Rust do usuário para C para alvos arbitrários. Acho que este repositório é a demonstração mais vistosa, por isso mostra o compilador compilando a si mesmo
  • Vale a pena ver também o mrustc(https://github.com/thepowersgang/mrustc). É um compilador Rust escrito em C++, que transpila para C e depois passa para o GCC, então também consegue converter o rustc para C