crustc: convertendo todo o rustc para C
(github.com/FractalFir)crustcé uma demo que converte todo orustc 1.98.0-nightly (c712ea946 2026-06-16)em 46 milhões de linhas de código C, e ao compilar comGCCemakegera 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
cillyconsulta 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
cillyainda 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 orustc 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
GCCemake, 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ãorustc 1.98.0-nightly - O compilador Rust gerado consegue compilar código e construir
core,allocestd - 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 chamadacilly- A toolchain completa
cillytem como objetivo compilar código Rust do usuário para C ajustado a qualquer alvo - Este repositório foi montado para mostrar o
cillycompilando 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_clre várias tentativas privadas, ocillyé 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
- Um exemplo é
- O
cillytenta 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
- Essas suposições são documentadas e, quando possível, recebem asserts como
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
cillypara Arm64 não pode simplesmente ser executado em riscv32 - Mas é possível gerar separadamente um C do
cillypara riscv32
- O C gerado pelo
- O C gerado para o
rustcneste 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 umrustccomum - Em algumas plataformas, o
rustcescolhe 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
- Na maioria das plataformas, o
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
cillyenvolve orustce 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-nonee os argumentos/usr/bin/sdcc,-mz180,--std-c89e-c
Transparência de rede e compilador C remoto
- O
cillytem 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
rustcem uma plataforma comum como Linux e deixar ocillyse comunicar pela rede - O autor compilou com sucesso um pequeno programa Rust para uma VM x86 com Plan 9 enquanto executava o
rustcem 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
nmmostra o símbolorust_begin_unwind
- A saída do ambiente Plan 9 é
Geração de makefile
- O
cillypode 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
- A string do kernel é
- 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 -j20comLLVM_LIB_DIRapontando para o caminho delibLLVM.so.22.1-rust-1.98.0-nightly CFLAGSfunciona, 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
- A medição foi
- 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_PATHcom 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 erroerror[E0463]: can't find crate for std - Para construir a biblioteca padrão, é preciso consultar
BUILDING_STD.md
- Sem
- Um bug conhecido faz o
crustctravar 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
cillyainda 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
cillyainda não ter sido publicada é que bugs ligados a otimização ainda estão sendo investigados
1 comentários
Opiniões no Lobste.rs
Parece bem estranho que as cadeias de build tradicionais em C com
configurefuncionem, 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
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
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
crustcnão faria isso. Isso porque o compilador convertido também suporta apenas os mesmos alvos de compilação do compilador originalPoré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
rustcjá tem amplo suporte a alvos, e isso deve aumentar com o backendgccAs 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
crustcé apenas um exemplo do quecilly, uma toolchain que transforma Rust em C, consegue fazerA toolchain completa
cillycompila 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 mesmorustcpara C