1

cgm-zig: o fork do Zig que nasceu no lixão — e compila o que o original não compilava

"Tenha fé, porque até no lixão nasce flor."
— Mano Brown, Racionais MC's, Vida Loka Pt. 1 (2002)

Esse verso é o mote deste projeto, e no final do post explico por quê — literalmente, não como metáfora de LinkedIn. Antes, a parte técnica.

O problema

Eu compilo um projeto hiper-modular grande: ~1.800 módulos nomeados / ~2.300 arquivos analisados como uma única unidade de compilação. O Zig 0.16.0 original nunca compilou esse projeto: depois de mais de 2 horas, todas as vezes, morria com um SIGSEGV silencioso — o binário de release é ReleaseFast/stripped, então a falha não diz nem onde foi o problema.

O diagnóstico (reproduzido de forma controlada sete vezes, em dois builds independentes com o mesmo final de backtrace):

  • O InternPool do frontend usa um sentinela u32 0xFFFFFFFF ("none") que, num certo caminho de exaustão, é dereferenciado como índice vivo numa tabela de elementos de 8 bytes — o endereço da falha decompõe exatamente como base + 0xFFFFFFFF * 8.
  • Invariante com cache quente/frio, stack de 8 MiB/ilimitada, backend self-hosted/LLVM, incremental ligado/desligado.
  • Duas issues upstream superficialmente parecidas foram reproduzidas localmente e descartadas por um discriminador — não era nenhuma delas.

Ou seja: não é "seu projeto é grande demais, paciência". É um estouro de espaço de índices que o compilador não nomeia.

O que o fork muda (e o que cada mudança tem de evidência)

O fork é o 0.16.0 importado do tarball oficial (sha256 conferível no primeiro commit) mais uma série de patches localizados. A tabela completa — arquivo, commit, status e efeito observado de cada linha — está no README, seção "What differs from upstream Zig 0.16.0" (21 linhas). Os destaques:

1. A falha silenciosa vira recusa nomeada.

  • Exaustão do espaço de índices por thread do InternPoolpanic nomeado com remédio impresso, em vez de SIGSEGV mudo.
  • CaptureValue alargado: índice de 30 → 31 bits — todos os tetos publicados dobram.
  • O binário promovido é ReleaseSafe: quando algo quebra, quebra dizendo o próprio nome.

2. Threading consciente da topologia.

  • std.Thread.Topology: núcleos físicos e irmãos SMT, com máscara de afinidade.
  • A contagem de workers foi separada da contagem de partições do InternPool (eram acopladas).
  • Ordenação edges-first dos passos de compilação (em camadas, por profundidade de dependência).
  • -j agora alcança os compiladores filhos — a máquina é compartilhada em vez de entregar N cópias dela.
  • Um pool de tids faminto completa ou recusa — nunca trava (era uma classe de travamento reproduzível; virou uma linha de teste do harness).

3. Diagnóstico que fala.

  • file exists in multiple modules agora nomeia o arquivo duplamente possuído.
  • -femit-module-graph: o compilador emite o grafo de módulos resolvido em JSON.
  • --time-report-json: o relatório de tempo legível por script (e recusa --listen pelo nome em vez de gravar nada silenciosamente).
  • ast-check ciente de imports (--module-graph), com modo batch e denominadores honestos.

Os números (medidos, não prometidos)

Antes (0.16.0 de fábrica)Depois (cgm-zig promovido)
Nunca terminou — falhava depois de 2+ horas, todas as vezes, sem dizer ondeCompilação completa do mesmo workload em menos de 45 minutos
SIGSEGV silenciosoPanic nomeado com remédio
Seis builds completos consecutivos, zero OOM (~18,5 GB de RSS por job)

E a honestidade que a comunidade merece: o harness de verificação do próprio fork registra 22 linhas verdes / 2 vermelhas — as duas vermelhas são flags que já vêm desligadas por padrão (--analysis-order=layered e --child-jobs=share, que regrediram ~6,5% nos nossos números e por isso não são o default), e o README marca explicitamente o que ainda não foi medido. Nada de benchmark de marketing.

Por que um fork, e não PRs pro Zig?

Porque a política de contribuição do projeto Zig (2026) não aceita nenhum conteúdo gerado, editado, ou sequer depurado com assistência de IA (LLM) — a avaliação pública da liderança é que contribuição assistida por IA é "invariavelmente lixo" ("invariably garbage"). Este fork foi diagnosticado e escrito em parceria com IA, com engenharia verificável em cada commit: reproduções controladas, controles negativos, um harness com 38 linhas auto-registradas. Então ele não é oferecido ao upstream — respeitamos a porta fechada — e vive como fork MIT, com o LICENSE e o README originais preservados intactos. Base 0.16.0; a política de versão só acompanha o upstream quando ele promover uma stable (que hoje, aliás, vive no Codeberg — o espelho do GitHub está congelado desde 2025).

O mote

Eu moro na Cidade Estrutural, DF — a comunidade que cresceu do lado do que foi, até fechar em 2018, um dos maiores lixões a céu aberto do planeta. Quem trabalhou naquele lixão, os catadores, alimentou família achando valor no que todo mundo jogou fora. Cidade sem lixeiro adoece — e, sinceramente, fede muito e fede rápido.

Quando um projeto declara uma categoria inteira de contribuição como "lixo" e tranca a porta, ele esquece o que toda cidade aprende do jeito difícil: quem pega o lixo, separa, e acha o que presta não está abaixo da cidade — é o que mantém a cidade viva. Este repositório faz esse trabalho por um compilador: pegamos o que chamaram de lixo, separamos, e devolvemos a parte que cura a doença.

"Tenha fé, porque até no lixão nasce flor."

E o Mano Brown não diz que a flor cresce lá. Ele diz que nasce — no único lugar onde nada deveria nascer. Esse é o ponto inteiro, do verso e do repositório.

Façam bom uso

  • Release (toolchain x86_64-linux pronto, tar.xz + sha256): github.com/danielcamposramos/cgm-zig/releases — tag 0.16.0+cgm.046d6833
  • A tabela do que muda: README, seção What differs from upstream Zig 0.16.0
  • A história completa (com a cadeia de crédito humano+IA): PROVENANCE.md
  • Instalação: extrai e aponta o symlink — ln -sfn <dir>/bin/zig ~/.local/bin/zig. Rollback: o tarball 0.16.0 oficial do ziglang.org.

Issues e contribuições são bem-vindas — inclusive as assistidas por IA, que aqui são tratadas do único jeito que a verdadeira engenharia conhece: pelo mérito verificável do diff (CONTRIBUTING-AI.md explica o rito). Se você tem um projeto Zig grande que o 0.16.0 não aguenta, me conta o que acontece com ele no fork...

PS: Após as mudanças, agora não somente o projeto compila, mas compila em 46 minutos.

Carregando publicação patrocinada...