Open-Source Wikis

/

Zig

/

Zig

/

Architecture

ziglang/zig

Architecture

The Zig compiler is a multi-stage pipeline that turns Zig source into machine code or object files. The same pipeline is shared by zig build-exe, zig build-lib, zig build-obj, zig test, and zig run. The high-level invariant is: every module passes through tokenization → AST → ZIR → AIR → backend, with comptime evaluation happening inside semantic analysis.

graph TD
  src["Zig source"] --> Tok["Tokenizer (lib/std/zig/tokenizer.zig)"]
  Tok --> Parse["Parser (lib/std/zig/Parse.zig)"]
  Parse --> Ast["std.zig.Ast"]
  Ast --> AstGen["AstGen (lib/std/zig/AstGen.zig)"]
  AstGen --> Zir["ZIR (lib/std/zig/Zir.zig)"]
  Zir --> Sema["Sema (src/Sema.zig)"]
  Sema --> InternPool["InternPool (src/InternPool.zig)"]
  Sema --> Air["AIR (src/Air.zig)"]
  Air --> CG["codegen (src/codegen.zig + src/codegen/*)"]
  CG --> Link["link (src/link.zig + src/link/*)"]
  Link --> Out["Executable / object / library"]

Stages

1. Driver — src/main.zig

mainArgs in src/main.zig parses the CLI, builds a Compilation.Config, and constructs a Compilation for the requested artifact. The CLI also handles non-build commands (fmt, ast-check, init, fetch, targets, etc.) directly.

2. Package resolution — src/Package.zig

A Package.Manifest describes the root module of the project. The package manager (src/Package/Fetch.zig, src/Package/Manifest.zig) resolves dependencies declared in build.zig.zon, downloads tarballs into the global cache, verifies hashes, and produces the dependency graph that Compilation consumes.

3. Compilation orchestrator — src/Compilation.zig

This is the largest single file in the compiler (≈344 KB). It owns:

  • The ThreadPool and work queues.
  • The Cache (lib/std/Build/Cache.zig) used to skip work between runs.
  • The list of Modules to analyze, the Zcu (Zig Compilation Unit) that holds analyzed declarations, and the link.File that owns the output.
  • The pipeline itself: parse → AstGen → analyze → codegen → emit.

Watch-mode and the incremental debug server (src/IncrementalDebugServer.zig) re-run only the work units affected by file edits.

4. Frontend (parse + AstGen) — lib/std/zig/

Tokenization (tokenizer.zig), parsing (Parse.zig), and AST shape (Ast.zig) all live in the standard library so user programs can run them too. AstGen.zig lowers an AST into ZIR (Zig Intermediate Representation), a flat untyped IR designed for cheap diffing and incremental compilation. ZIR is documented in Zir.zig.

5. Semantic analysis — src/Sema.zig

Sema.zig (≈1.6 MB, the largest single file in the codebase) walks ZIR, executes comptime code, performs type checking, and emits AIR (Analyzed IR — src/Air.zig). Several heavy responsibilities split into siblings:

  • src/Zcu.zig — module graph, declarations, source locations, error rendering.
  • src/InternPool.zig — interned types, values, and strings shared by Sema and codegen (≈513 KB).
  • src/Sema/arith.zig, src/Sema/bitcast.zig, src/Sema/comptime_ptr_access.zig, src/Sema/LowerZon.zig — focused subroutines for arithmetic, bitcast, comptime pointer reads/writes, and ZON lowering.
  • src/Type.zig, src/Value.zig, src/mutable_value.zig — the type/value model.

6. Backends — src/codegen.zig + src/codegen/*

Each backend consumes AIR and emits machine code or another IR.

  • src/codegen/llvm.zig — the LLVM backend (the "release" path, ≈580 KB single file plus support modules).
  • src/codegen/x86_64/CodeGen.zig — the self-hosted x86_64 backend (≈10.4 MB single Zig file; the largest hand-written backend).
  • src/codegen/aarch64/, src/codegen/riscv64/, src/codegen/sparc64/, src/codegen/wasm/, src/codegen/spirv/, src/codegen/arm/, src/codegen/mips/ — additional self-hosted backends in varying degrees of completeness.
  • src/codegen/c.zig — the C backend, which can re-emit Zig as portable C.

src/register_manager.zig is the shared register allocator used by the hand-written backends.

Each output format has its own linker that consumes the per-object output of codegen and produces the final binary:

  • src/link/Elf.zig (and src/link/Elf/) — ELF.
  • src/link/MachO.zig (and src/link/MachO/) — Mach-O.
  • src/link/Coff.zig — COFF/PE (Windows).
  • src/link/Wasm.zig (and src/link/Wasm/) — WebAssembly.
  • src/link/SpirV.zig (and src/link/SpirV/) — SPIR-V (GPU).
  • src/link/C.zig — output as C source.
  • src/link/Lld.zig — LLD fallback used when -fuse-lld is selected (typically with the LLVM backend).
  • src/link/Dwarf.zig, src/link/Elf2.zig — debug info and a newer ELF linker, respectively.

8. Bundled tools and runtime

When zig is also acting as a C/C++ toolchain, several other libraries ship in the binary:

  • lib/compiler_rt/ — soft-float, integer division, atomic helpers, etc.
  • lib/libcxx/, lib/libcxxabi/, lib/libunwind/, lib/libtsan/ — the C++ runtime sources LLVM expects.
  • lib/libc/{glibc,musl,mingw,wasi,darwin,freebsd,netbsd}/ — bundled libc sources or stubs for cross-compilation.
  • lib/include/ — clang resource headers.

How comptime and incremental compilation interact

A central design point is that Sema runs as a fixed-point evaluator over ZIR and produces AIR for everything that is reachable. ZIR is intentionally cheap to regenerate from the AST; AIR is invalidated only when the analysis result it depends on changes. The Zcu keeps an explicit dependency graph so that file edits, when caught by lib/std/Build/Watch.zig, cause only the affected declarations to be re-analyzed and re-codegen'd — that is the foundation for zig build --watch and the incremental debug server (src/IncrementalDebugServer.zig, tools/incr-check.zig).

What runs where

graph LR
  subgraph CLI ["zig (binary)"]
    Main["src/main.zig"]
  end
  subgraph Stdlib ["lib/std (also used by user programs)"]
    AstGenS["zig.AstGen + Ast"]
    BuildS["std.Build (zig build)"]
    Cache["std.Build.Cache"]
  end
  subgraph CompilerLib ["lib/compiler (shipped tools)"]
    Aro["aro (C frontend)"]
    Resinator["resinator (rc.exe)"]
    BuildRunner["build_runner"]
    TestRunner["test_runner"]
    Objcopy["objcopy"]
    StdDocs["std-docs"]
    Reduce["reduce"]
    TranslateC["translate-c"]
  end
  Main --> AstGenS
  Main --> BuildRunner
  Main --> Cache
  Main --> Aro
  Main --> Resinator
  Main --> Objcopy
  Main --> Reduce
  Main --> TranslateC
  Main --> TestRunner
  Main --> StdDocs

Key files at a glance

File Lines / size Role
src/Sema.zig ~1.6 MB Semantic analysis and comptime evaluation.
src/InternPool.zig ~513 KB Interned types/values/strings.
src/codegen/x86_64/CodeGen.zig ~10.4 MB Hand-written x86_64 backend.
src/codegen/llvm.zig ~580 KB LLVM backend.
src/main.zig ~350 KB CLI dispatch.
src/Compilation.zig ~344 KB Compilation pipeline driver.
src/Zcu.zig ~212 KB Module graph, errors.
src/link/MachO.zig ~196 KB Mach-O linker.
src/link/Elf.zig ~159 KB ELF linker.
src/link/Wasm.zig ~167 KB Wasm linker.
lib/std/zig/AstGen.zig ~576 KB AST → ZIR.
lib/std/zig/Zir.zig ~210 KB ZIR encoding/decoding.
lib/std/Build.zig ~101 KB std.Build API.

See by the numbers for more.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Architecture – Zig wiki | Factory