Internals da Compilação Incremental do Zig

O novo sistema de compilação incremental do Zig visa tornar recompilações após pequenas mudanças de código quase instantâneas ao cachear IR de grão fino e aplicar patches em binários no lugar, embora atualmente mire builds de debug e backends self-hosted sem otimizações pesadas. Os comentaristas comparam esse modelo com Rust, C, Java e Fil-C, debatendo como design de linguagem, pipelines de compilação e recursos como generics, macros e borrow checking afetam tanto os tempos de compilação quanto as garantias de segurança de memória. A discussão também aborda estratégias alternativas, como linking dinâmico de muitas bibliotecas compartilhadas pequenas, e quanto complexidade ou custo em runtime é aceitável na busca por iteração mais rápida e código de baixo nível mais seguro.

Compilação incremental no Zig

  • O modo incremental atual funciona apenas com os backends self-hosted do Zig (não LLVM), principalmente x86_64, e por enquanto é efetivamente “só debug”.
  • Plano futuro: adicionar passes de otimização aos backends self-hosted e, eventualmente, suportar algum tipo de builds de release, mas otimizações entre funções (por exemplo, inlining) entram fundamentalmente em conflito com esse modelo e continuarão limitadas.
  • O design da linguagem Zig foi ajustado ao longo do tempo (às vezes de forma controversa) especificamente para tornar a compilação incremental de grão fino e a análise semântica viáveis.

Compilação de C e dependência do LLVM

  • A recompilação incremental aplica-se apenas às fontes Zig em projetos mistos Zig/C; C é compilado via LLVM e não é cacheado com a mesma granularidade.
  • Existe um compilador de C baseado em Zig (Aro/arocc) usado para translate-c (tradução de headers), mas ainda não como um backend geral de C. Os planos de longo prazo para compilação de C ainda estão sendo desenhados.

Por que um único binário grande e linking incremental

  • Alguns questionaram por que o Zig aplica patches em um grande binário de debug em vez de compor muitas bibliotecas compartilhadas pequenas.
  • Respostas:
    • O Zig usa um modelo de unidade de compilação única; arquivos separados são organização, não fronteiras de compilação, então a maior parte do trabalho incremental (parse, análise semântica) ainda é necessária de qualquer forma.
    • Dividir em muitas bibliotecas compartilhadas na maior parte apenas deslocaria o trabalho do linker estático para o loader dinâmico, prejudicando o startup em runtime; experimentos medidos com centenas a milhares de bibliotecas compartilhadas mostram overhead perceptível.
    • O linking incremental é reconhecido como complexo, mas é considerado o melhor compromisso; preocupações com corrupção devem ser tratadas com separação de cache, detecção de corrupção e cancelamento seguro.

Rust, outros compiladores e tempos de compilação

  • Várias comparações com Rust:
    • Rust já tem compilação incremental, mas sofre com a complexidade da linguagem (macros, proc macros, resolução de nomes, generics monomorfizados) e com o modelo tradicional de “compilar bibliotecas depois fazer link”.
    • Há trabalho em andamento em Rust para melhorar o comportamento incremental (por exemplo, queries mais granulares, “relink don’t rebuild”), mas rearquitetar é difícil.
    • Alguns argumentam que muitas linguagens ainda desperdiçam trabalho ao compilar bibliotecas inteiras mesmo quando apenas uma pequena parte é usada; o modelo dirigido por demanda do Zig é visto como mais limpo.

Segurança de memória vs tradeoffs de linguagem (Rust, Zig, Java, Fil-C)

  • Um lado trata “segurança de memória por padrão, com escape hatches explícitos” (estilo Rust/Java) como base; outro argumenta que o que importa é o subconjunto seguro útil e o tradeoff total (complexidade, desempenho, velocidade de iteração).
  • O Zig é visto como uma melhoria em relação ao C (notadamente ferramentas de segurança espacial), mas ainda “unsafe by default”; alguns consideram isso aceitável dadas suas metas e vantagens de tooling, outros veem a falta de segurança total de memória como um impeditivo.
  • O debate estendido compara Rust, Zig, Java, C, ATS e Fil-C:
    • Divergências sobre o que “linguagem com segurança de memória” deveria significar, se a posição do Rust é “o mínimo esperado”, e quanto valor limites explícitos entre safe/unsafe oferecem.
    • Fil-C é discutido como uma variante experimental de C usando capabilities e um runtime para prevenir muitas classes de exploração. Defensores destacam garantias mais fortes; críticos apontam overhead de runtime, dependência de trapping em vez de provas em tempo de compilação, limitações de plataforma e implementação imatura.
    • Vários participantes enfatizam que diferentes projetos e equipes escolherão racionalmente pontos diferentes no espectro segurança–complexidade–desempenho.

Hello World e ergonomia

  • O “hello world” oficial do Zig é visto por alguns como verboso em comparação com exemplos no estilo C.
  • Defesas:
    • Ele é “mais correto”: handles explícitos de IO, tratamento explícito de erros e integração com o modelo de IO do Zig.
    • Variantes mais simples existem (por exemplo, std.debug.print para stderr) para demonstrações rápidas; o exemplo verboso intencionalmente expõe preocupações do mundo real em vez de escondê-las.