ziglang/zig
Incremental compilation
Purpose
Zig's compilation pipeline is incremental by design: ZIR is cached per file, Sema results are cached per declaration with explicit dependency sets, and codegen / link only re-run on invalidated decls. The user-visible feature is zig build --watch — file edits cause only the affected work to be redone.
Components
| Piece | File | Role |
|---|---|---|
| ZIR cache | lib/std/zig/Zir.zig, lib/std/Build/Cache.zig |
ZIR is content-addressed and stored on disk. |
| Decl dependency graph | src/Zcu.zig |
Each analyzed decl records what it depends on (types, values, other decls). |
| Sema | src/Sema.zig |
Re-runs only invalidated decls, reusing the InternPool. |
| InternPool | src/InternPool.zig |
Stable identity for types and values across runs (within a process). |
| Codegen | src/codegen/* |
Re-emits per-decl artifacts; the linker stitches them in. |
| Linker | src/link/* |
Supports per-decl Atom updates so the binary doesn't need to be re-linked from scratch. |
| Watch | lib/std/Build/Watch.zig |
OS-level file watcher (kqueue/inotify/Windows). |
| Debug server | src/IncrementalDebugServer.zig |
Long-lived compiler process that serves rebuild requests. |
| Harness | tools/incr-check.zig |
Test fixture driver (~38 KB). |
Flow
sequenceDiagram
participant User
participant Watch as std.Build.Watch
participant Build as build_runner
participant Zig as zig (Compilation)
participant Pool as InternPool
User->>Watch: edit foo.zig
Watch->>Build: notify (file changed)
Build->>Zig: recompile request
Zig->>Zig: re-run AstGen on foo.zig
Zig->>Pool: invalidate decls dependent on foo.zig
Zig->>Zig: re-run Sema on invalidated decls only
Zig->>Zig: codegen for changed Sema results
Zig->>Zig: linker patches affected Atoms
Zig-->>User: updated binaryWhat gets invalidated
Zcu tracks for each decl:
- Source dependencies — which files the decl reads from (header includes,
@embedFile,@cImport). - Decl dependencies — which other decls it references (callees, types it uses, fields it reads).
- Comptime dependencies — comptime values it captured.
When a file changes, AstGen regenerates ZIR; Sema walks the dependency graph and marks every transitive dependent dirty; only those are re-analyzed.
Per-decl atoms in the linker
Each in-tree linker (src/link/Elf.zig, src/link/MachO.zig, etc.) operates on Atoms — a single decl's emitted code/data. When codegen produces a new Atom for an existing decl, the linker patches it in place rather than rewriting the whole binary. src/link/Elf/Atom.zig and src/link/MachO/Atom.zig are the canonical examples.
Debug server
src/IncrementalDebugServer.zig (~17 KB) is a long-lived zig process that accepts recompile requests over a socket. Editor tooling and the build runner can keep one alive across many rebuilds, sidestepping process startup cost. Together with watch mode this is the foundation of the "edit-and-continue"-style workflow.
Test harness
tools/incr-check.zig runs a fixture: an initial source plus a sequence of edits and expected results. After each edit the harness asks the compiler to incrementally rebuild and asserts that the result matches a clean build. Used by zig build test-incremental and by test/incremental/.
Entry points for modification
- New thing to depend on: add it to the
Zcudependency tracking insrc/Zcu.zig. - New invalidation source: wire it through
lib/std/Build/Watch.zig. - New per-decl linker support: the
AtomAPI in the relevantsrc/link/<format>/Atom.zig.
See Compiler for the broader pipeline and Build system for the watch-mode entry points.
Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.