Skip to content

Repository files navigation

CI Contributors Forks Stargazers Issues MIT License


Zaza

A Zig-driven build system for modern C, C++, Zig, Rust, CMake-interop, and WebAssembly workflows.
Read the wiki »

View Examples · Report Bug · Request Feature

Table of Contents
  1. About The Project
  2. Getting Started
  3. Usage
  4. Example Highlights
  5. Replacing CMake
  6. WebAssembly
  7. Fast builds
  8. Tests and benchmarks
  9. Roadmap
  10. Contributing
  11. License
  12. Contact
  13. Acknowledgments

About The Project

Zaza makes new native projects feel simpler than CMake without giving up serious target graphs, package flows, generated code, cross-compilation, or browser-adjacent outputs.

Why Zaza:

  • Zig build graph as the control plane instead of a separate DSL
  • First-class mixed-language workflows: C, C++, and Zig in one repo
  • Real examples for generated sources, shared plugins, packaging, presets, CMake interop, and wasm
  • One verified matrix command for the entire example surface

Status: Zaza is usable and heavily example-driven, but it is not pretending to have a final polished API yet. The verified example matrix is runnable with zig build example-matrix.

Start here: docs/WIKI.md is the single-page overview. It covers the problem Zaza solves, how it compares to CMake, a five-minute quickstart, the core concepts, every environment variable, the example matrix, the WebAssembly workflows, and troubleshooting.

(back to top)

Built With

  • Zig
  • C / C++
  • CMake (interop layer)
  • WebAssembly

(back to top)

Getting Started

Prerequisites

  • Zig 0.14.1, 0.15.2 or 0.16.0. All three are tested in CI.
  • Optional: cmake and git for the CMake interop and JUCE examples, cargo for the Rust example, node for the WebAssembly examples.
  • Optional: direnv for repo-local cache setup.

Installation

Zaza ships a build.zig.zon and is indexed by the Zig package trackers. Fetch it with the package manager:

zig fetch --save git+https://github.com/godofecht/zaza

Or clone and run the setup, which is the usual flow since build files import build_lib/zaza.zig directly:

git clone https://github.com/godofecht/zaza.git
cd zaza
./setup.sh

setup.sh reports your Zig version, warns if it is outside the tested range, creates the machine-local ./zig wrapper if it is missing, lists which optional examples your machine cannot run, and then runs the test suite. It is safe to run repeatedly. Use ZIG=/path/to/zig ./setup.sh to check a specific supported lane, for example a zigup-installed 0.14.1, 0.15.2, or 0.16.0 binary. The setup uses a Zig-version-specific cache directory by default, so changing lanes does not reuse a stale build runner from another Zig release.

Toolchain
  ok  zig 0.15.2 (/opt/homebrew/bin/zig)
...
Build Summary: 43/43 steps succeeded; 87/87 tests passed

To verify the rest of the surface:

zig build example-matrix

(back to top)

Usage

Useful first commands:

zig build run-hello-zaza
zig build package-consumer-run
zig build mixed-stack-run
zig build wasm-web-demo-smoke
zig build wasm-web-demo-serve

If a target needs external tools such as git or cmake, enable them explicitly:

ZAZA_SYSTEM_CMDS=1 zig build cmake-shim

Naming conventions:

Pattern Meaning
<name> Build or stage the artifact
<name>-run Execute something real
<name>-report Inspect or validate an artifact
<name>-serve Start a local server

Minimal build.zig example:

const std = @import("std");
const zaza = @import("build_lib/zaza.zig");

pub fn build(b: *std.Build) !void {
    const exe = try zaza.Target.executable(.{
        .name = "my_app",
        .source_files = &.{"src/main.cpp"},
        .public_include_dirs = &.{"include"},
        .public_defines = &.{"MY_APP=1"},
        .cpp_std = "17",
    }).build(b);

    const run_cmd = b.addRunArtifact(exe);
    const run_step = b.step("run", "Run my_app");
    run_step.dependOn(&run_cmd.step);
}

build_lib/zaza.zig is the stable entry module: import it once and reach the supported types and functions through it. zaza.Target is the C and C++ target type; zaza.CppExample is kept as an alias so existing build files keep working. The full surface is in docs/API.md, and the field list is in the Syntax Reference.

(back to top)

Packages

Zaza tracks C and C++ dependencies in registry/registry.json and fetches them into build.zig.zon. Discover and inspect them from the CLI:

zig run scripts/zaza.zig -- list                # every package, with descriptions
zig run scripts/zaza.zig -- search audio        # ranked across name, keywords, description
zig run scripts/zaza.zig -- info juce           # full metadata for one package
zig run scripts/zaza.zig -- fetch fmt           # add it to build.zig.zon

search scores each package across its name, keywords, and description, so search http finds curl even though the name does not contain the word. Each registry entry carries a description, keywords, repo, homepage, and license.

(back to top)

Example Highlights

Workflow Command
Mixed Zig + C++ zig build run-hello-zaza
Package producer / consumer zig build package-consumer-run
Mixed C + C++ + Zig zig build mixed-stack-run
Interface + object + static graph zig build interface-object-graph-run
Shared plugin loading zig build shared-plugin-run
Cross-compile artifact report zig build cross-compile-cli-report
C++20 modules zig build cxx20-modules-run
WASI artifact validation zig build wasm-wasi-report
Host-loaded wasm exports zig build wasm-exports-run
Browser wasm demo zig build wasm-web-demo-smoke

Every example has its own README with prerequisites and an exact command. The index is examples/README.md. Per-example diagrams and syntax notes live in docs/EXAMPLES.md.

Plugin, bundle, and resource layouts can stage outputs with artifact_copies, file_copies, or the lower-level zaza.addArtifactCopies and zaza.addFileCopies helpers. The shared plugin example copies the dynamic library into zig-out/share/shared_plugin/plugins/ before the host loads it; the resources example stages a runtime asset under zig-out/share.

(back to top)

Replacing CMake

The intent is not to mimic CMake syntax one-for-one. The intent is to cover the workflows people actually need when starting new projects.

CMake concept Zaza shape
CMakeLists.txt build.zig
add_executable() executable target / CppExample{ .kind = .executable }
add_library(STATIC ...) CppExample{ .kind = .static_library }
target_include_directories() include-dir fields on the target
target_compile_definitions() public_defines / private_defines / config defines
add_custom_command() custom_commands
add_custom_command(TARGET ... POST_BUILD copy ...) artifact_copies, file_copies, and copy helpers
install() / export() install/export fields and Zaza package metadata
find_package() consumer flow package producer / consumer example

See docs/CMAKE_PARITY.md and docs/ROADMAP.md for the full parity framing.

(back to top)

WebAssembly

Zaza has concrete wasm workflows:

zig build wasm-wasi-report
zig build wasm-exports-run
zig build wasm-web-demo
zig build wasm-web-demo-smoke
zig build wasm-web-demo-serve

wasm-web-demo-serve stages and serves a browser harness at http://127.0.0.1:8000.

(back to top)

Fast builds

A zig build no-op is startup-bound: the build script compiles and runs on every invocation. zaza-drive is a native build driver that skips that. It reads a manifest, checks source and recorded-header timestamps, and rebuilds only what changed. Same 16 translation unit project, same machine, same compiler in every lane:

phase zaza-drive ninja zig build
no-op rebuild 2.3 ms 3.3 ms 69.7 ms
incremental rebuild 110.4 ms 121.4 ms 106.1 ms

zig build drive-native writes a manifest that uses the system compiler, which starts about twice as fast as the zig c++ wrapper. That cuts the incremental rebuild from 127 ms to 47 ms, about 2.7x. It is an iteration path: the system compiler differs from Zig's bundled one, so release and cross builds still go through zig build or the faithful zig build drive.

The numbers are measured, reproducible with tools/zaza-drive/bench.sh. Details and the honest tradeoff are in tools/zaza-drive/README.md and benchmarks/README.md.

(back to top)

Tests and benchmarks

A test or a benchmark is an executable plus a list of run cases, where each case is data: a label, arguments, an environment, and a working directory. The API in build_lib/test_suite.zig turns that list into the run steps for you.

_ = try test_suite.addTest(b, target, .{
    .name = "test-workflows",
    .target = demo,                      // a CppExample
    .cases = &.{
        .{ .label = "unit", .args = &.{"unit"} },
        .{ .label = "integration", .args = &.{"integration"} },
    },
});

This gives test-workflows, test-workflows-run, and a step per case, and hooks the cases onto zig build test. addBench is the same shape with release defaults: it stays off test, prints its timings, and forwards zig build bench-suite-run -- --reps 9 to the process. Full detail is in docs/WIKI.md; the two examples are examples/test_workflows and examples/bench_suite.

(back to top)

Roadmap

  • Mixed C/C++/Zig target graphs
  • Package producer/consumer workflow
  • WebAssembly (WASI, host embedding, browser)
  • CMake interop layer
  • Verified example matrix
  • Polished public API: the build_lib/zaza.zig facade and docs/API.md
  • Registry and package discovery: ranked search, zaza info, richer metadata
  • IDE integration: azazel's VS Code extension and LSP for project.cue

See the open issues for a full list of proposed features (and known issues). See docs/ROADMAP.md for the detailed roadmap.

(back to top)

Contributing

Contributions are what make the open source community such an amazing place to learn, inspire, and create. Any contributions you make are greatly appreciated.

The current contribution bar is:

./setup.sh              # runs ZAZA_EXAMPLES=none zig build test --summary all
zig build example-matrix

Run ./setup.sh on 0.14.1, 0.15.2 and 0.16.0 if your change touches build files or Zig sources. The suite should report 43/43 steps succeeded; 87/87 tests passed on each.

If you have a suggestion that would make this better, please fork the repo and create a pull request. You can also simply open an issue with the tag "enhancement". Don't forget to give the project a star! Thanks again!

  1. Fork the Project
  2. Create your Feature Branch (git checkout -b feature/AmazingFeature)
  3. Commit your Changes (git commit -m 'Add some AmazingFeature')
  4. Push to the Branch (git push origin feature/AmazingFeature)
  5. Open a Pull Request

See CONTRIBUTING.md for the full repo workflow details.

(back to top)

Top contributors:

contrib.rocks image

License

Distributed under the MIT License. See LICENSE for more information.

(back to top)

Contact

Abhishek Shivakumar - security@zaza.build

Project Link: https://github.com/godofecht/zaza

(back to top)

Acknowledgments

  • Zig - the language and build system that makes this possible
  • Best-README-Template - README template
  • All contributors and the open source community

(back to top)

Repository Layout

Path Purpose
build.zig Root build graph
build_lib Reusable build helpers
examples Example projects and workflows
corpus External upstream repos rebuilt through Zaza, with native-build comparisons
tests Zig-side test coverage
registry Lightweight registry metadata
wiki Static docs site
docs Documentation
setup.sh Toolchain check, wrapper creation, and test run

Published at godofecht.github.io/zaza.

Documentation map

Document Covers
docs/WIKI.md Single-page overview: quickstart, concepts, env vars, troubleshooting
examples/README.md Every example, its command, and its purpose
docs/EXAMPLES.md Per-example diagrams and syntax focus
docs/SYNTAX_REFERENCE.md Full field and command surface
docs/CMAKE_PARITY.md Feature-by-feature parity status
docs/ROADMAP.md What is being built next

(back to top)

About

A Zig-driven build system for modern C, C++, Zig, CMake-interop, and WebAssembly workflows.

Topics

Resources

Code of conduct

Contributing

Security policy

Stars

2 stars

Watchers

1 watching

Forks

Releases

Packages

Used by

Contributors

Languages