Core Concepts

The build graph

A Zaza build file is a Zig program that adds steps to std.Build. Zig runs it, resolves the dependency graph, and executes only the steps whose inputs changed. There is no configure phase distinct from the build phase, and no generated Makefiles or Ninja files in between.

Step names follow four conventions:

PatternMeaning
<name>Build or stage the artifact
<name>-runExecute something real
<name>-reportInspect or validate an artifact the host cannot run
<name>-serveStart a long-running local server

build_lib/build_graph.zig holds a small standalone graph structure with topological sort, used by the tests to assert ordering behaviour independently of std.Build.

CppExample

CppExample is the C and C++ target type. It is a plain struct, so a target is data that can be inspected, serialised, and modified before it is built.

pub var example = cpp.CppExample.executable(.{
    .name = "my_app",
    .description = "demo",
    .source_files = &.{"src/main.cpp"},
    .public_include_dirs = &.{"include"},
    .public_defines = &.{"MY_API=1"},
    .public_link_libs = &.{"pthread"},
    .cpp_std = "17",
});

Five constructors cover the target kinds:

cpp.CppExample.executable(...)
cpp.CppExample.staticLibrary(...)
cpp.CppExample.sharedLibrary(...)
cpp.CppExample.objectLibrary(...)
cpp.CppExample.interfaceLibrary(...)

All five call CppExample.make(kind, options).

Fields split along the usual visibility lines. public_include_dirs, public_defines, and public_link_libs are meant to propagate to consumers. private_include_dirs, private_defines, and private_link_libs are not. Transitive propagation across dependency edges is partial today; see CMAKE_PARITY.md.

Generated sources are declared alongside a command that produces them:

.generated_source_files = &.{"zig-out/gen/generated.cpp"},
.custom_commands = &.{
    .{
        .name = "generate_generated_cpp",
        .argv = &.{"sh", "scripts/generate.sh", "zig-out/gen/generated.cpp"},
    },
},

Install and export fields produce a stable layout:

zig-out/include/<export_name>/...
zig-out/lib/...
zig-out/cmake/<export_name>/<export_name>Config.cmake
zig-out/share/zaza/<export_name>.json

The full field list is in SYNTAX_REFERENCE.md.

Presets

ZAZA_PRESET selects a named BuildConfig list from build_lib/presets.zig. Six are defined:

PresetEffect
debugmode = .Debug (the default)
releasemode = .Release
relwithdebinfomode = .RelWithDebInfo
minsizerelmode = .MinSizeRel
asan.Debug plus -fsanitize=address and ZAZA_ASAN=1
lto.Release plus want_lto and ZAZA_LTO=1

An unrecognised name silently falls back to debug.

ZAZA_EXAMPLES=preset-profiles ZAZA_PRESET=release zig build preset-profiles-run
preset: release
preset runtime ready

Presets apply only to the examples that opt in: cmake_combo, cmake_net, cmake_shim, and preset_profiles.

The package registry

registry/registry.json maps a short package name to a source URL and version.

zig run scripts/zaza.zig -- list
Available packages (7):
                  juce 7.0.9
                   fmt 10.2.1
                spdlog 1.14.1
                  zlib 1.3.1
               mbedtls 3.6.2
                  curl 8.6.0
         nlohmann_json 3.11.3

Fetching a package resolves its hash with zig fetch and writes the entry into build.zig.zon:

zig build zaza-fetch -- fmt

The rest of the CLI:

zaza fetch <name>    Fetch a package from the registry into build.zig.zon (alias: add)
zaza add <name>      Alias for fetch
zaza remove <name>   Remove a dependency from build.zig.zon (alias: rm)
zaza list            List all packages available in the registry (alias: ls)
zaza deps            List dependencies with source, lock state, and on-disk presence
zaza clean-deps      Remove deps/ and zig-out/deps (alias: clean)
zaza cache           Show the Zig cache directories and whether they are writable
zaza search <query>  Search packages by name
zaza init [name]     Scaffold a new Zaza project in the current directory

zaza deps reads build.zig.zon for the declared names and zaza.lock for what has been pinned, and checks deps/ for what is present on disk:

zig run scripts/zaza.zig -- deps
Dependencies (7):
  name             source     hash           on disk
  mbedtls          unlocked   -              no
  fmt              registry   1220abcdef0123 yes
  ...

fetch resolves the hash with zig fetch and records it in both build.zig.zon and zaza.lock, so a fetched dependency shows its source and hash here. unlocked means there is no zaza.lock entry pinning it yet.

zaza clean-deps removes the fetched sources in deps/ and their built outputs in zig-out/deps, so the next build re-fetches from the pinned hashes. zaza cache reports the global and local Zig cache directories and whether each is writable, which is the first thing to check when a build fails with a cache error:

zig run scripts/zaza.zig -- cache
Zig cache directories:
  global   /Users/you/.cache/zig  (writable)
  local    .zig-cache (default)  (writable)

The root build also resolves registry entries on your behalf. If an enabled example needs a package that is missing from build.zig.zon, the build adds it and stops with a message telling you to re-run. ZAZA_REGISTRY=0 disables that.

The CMake interop shim

Some libraries only build with CMake. Zaza models those as dependencies with type = .CMake, and the graph clones, configures, builds, and installs them:

.deps = &.{
    .{
        .name = "fmt",
        .url = "https://github.com/fmtlib/fmt.git",
        .git_ref = "10.2.1",
        .type = .CMake,
        .cmake_config = .{
            .install_prefix = "zig-out/deps",
            .install = true,
            .configure_args = &.{ "-DFMT_DOC=OFF", "-DFMT_TEST=OFF", "-DFMT_INSTALL=ON" },
        },
    },
},
.deps_build_system = .CMake,
.main_build_system = .Zig,

Sources land in deps/<name>/, build trees in deps/<name>/build/<Config>/, and installed output in zig-out/deps/. The final artifact is built by Zig and links against the installed archives.

Three examples of increasing difficulty:

ZAZA_EXAMPLES=cmake-shim ZAZA_SYSTEM_CMDS=1 zig build cmake-shim-run
{
    "awesome": true,
    "name": "C++ with Zig"
}
ZAZA_EXAMPLES=cmake-combo zig build cmake-combo-run
[2026-07-21 12:06:42.346] [info] hello from cmake_combo
ZAZA_EXAMPLES=cmake-net zig build cmake-net-run
cmake_net
curl: libcurl/8.6.0-DEV mbedTLS/3.6.2 zlib/1.3.1
zlib: 1.3.1
mbedtls: 3.6.2

The last one is the interesting case: curl is configured against the zlib and mbedtls that the same graph installed a moment earlier.

Interop runs the other way too. export_cmake = true writes a <name>Config.cmake into zig-out/cmake/, so a CMake project can consume a Zaza-built library.