The Zig Build System

36.1 A Basic build.zig (0.15 Style)

The build graph is made of steps (compile, run, install, write files, custom). zig build --help lists steps and options.

The build runner itself is a Zig program compiled from build.zig.

const std = @import("std");

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});        // -Dtarget=...
    const optimize = b.standardOptimizeOption(.{});     // -Doptimize=...

    // Library module (reusable / importable)
    const lib_mod = b.addModule("mylib", .{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
    });

    // Executable
    const exe = b.addExecutable(.{
        .name = "myapp",
        .root_module = b.createModule(.{
            .root_source_file = b.path("src/main.zig"),
            .target = target,
            .optimize = optimize,
            .imports = &.{.{ .name = "mylib", .module = lib_mod }},
        }),
    });
    b.installArtifact(exe);                             // zig-out/bin/myapp

    // `zig build run -- args`
    const run_cmd = b.addRunArtifact(exe);
    run_cmd.step.dependOn(b.getInstallStep());
    if (b.args) |args| run_cmd.addArgs(args);
    const run_step = b.step("run", "Run the app");
    run_step.dependOn(&run_cmd.step);

    // `zig build test`
    const lib_tests = b.addTest(.{ .root_module = lib_mod });
    const exe_tests = b.addTest(.{ .root_module = exe.root_modul
…

36.2 Build Options

const enable_logging = b.option(bool, "logging", "Enable logging") orelse false;
const version = b.option([]const u8, "version", "App version") orelse "dev";

const options = b.addOptions();
options.addOption(bool, "logging", enable_logging);
options.addOption([]const u8, "version", version);
exe.root_module.addOptions("build_options", options);
// in code
const build_options = @import("build_options");
if (build_options.logging) std.log.info("version {s}", .{build_options.version});
zig build -Dlogging=true -Dversion=1.2.3

36.3 Libraries and C Sources

const lib = b.addLibrary(.{
    .name = "mylib",
    .linkage = .static,                       // or .dynamic
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/root.zig"),
        .target = target,
        .optimize = optimize,
    }),
});
b.installArtifact(lib);

exe.root_module.addCSourceFiles(.{
    .files = &.{ "vendor/sqlite3.c", "src/helper.c" },
    .flags = &.{ "-std=c99", "-O2", "-DSQLITE_THREADSAFE=1" },
});
exe.root_module.addIncludePath(b.path("vendor"));
exe.root_module.link_libc = true;             // or exe.linkLibC()
exe.root_module.linkSystemLibrary("z", .{});  // system zlib (pkg-config when available)
exe.root_module.linkLibrary(lib);
exe.root_module.addCMacro("DEBUG", "1");

36.4 Generated Files, Custom Steps and Install

const gen = b.addWriteFiles();
const generated = gen.add("version.zig", "pub const v = \"1.0\";\n");
exe.root_module.addAnonymousImport("version", .{ .root_source_file = generated });

const tool = b.addExecutable(.{ .name = "codegen", .root_module = b.createModule(.{
    .root_source_file = b.path("tools/codegen.zig"), .target = b.graph.host,
}) });
const run_tool = b.addRunArtifact(tool);
run_tool.addFileArg(b.path("schema.json"));
const out = run_tool.addOutputFileArg("schema.zig");   // a generated file used as a module
exe.root_module.addAnonymousImport("schema", .{ .root_source_file = out });

b.installFile("README.md", "share/README.md");
b.installDirectory(.{ .source_dir = b.path("assets"), .install_dir = .prefix, .install_subdir = "assets" });

const fmt_step = b.addFmt(.{ .paths = &.{ "src", "build.zig" }, .check = true });
b.step("fmt", "Check formatting").dependOn(&fmt_step.step);

const docs = b.addInstallDirectory(.{
    .source_dir = lib.getEmittedDocs(),
    .install_dir = .prefix,
    .install_subdir = "docs",
});
b.step("docs", "Generate docs").dependOn(&docs.step);

36.5 Useful zig build Flags

zig build --summary all              # step tree summary
zig build -Dtarget=aarch64-linux-musl -Doptimize=ReleaseSmall
zig build --watch                    # rebuild on file changes
zig build --watch -fincremental      # incremental compilation (experimental, much faster rebuilds)
zig build --prefix /usr/local install
zig build -j4                        # parallelism
zig build --verbose                  # show commands
zig build --fetch                    # fetch dependencies only
zig build --release=fast             # respect the project's preferred release mode