Skip to content

Appendix E. Build System Reference

Zig builds programs with Zig code. The build script is named:

Zig builds programs with Zig code. The build script is named:

build.zig

Run it with:

zig build

A build script defines steps. A step may compile an executable, run tests, install an artifact, run a program, or perform another build action.

E.1 Minimal Build Script

const std = @import("std");

pub fn build(b: *std.Build) void {
    const exe = b.addExecutable(.{
        .name = "hello",
        .root_source_file = b.path("src/main.zig"),
        .target = b.standardTargetOptions(.{}),
        .optimize = b.standardOptimizeOption(.{}),
    });

    b.installArtifact(exe);
}

Project layout:

hello/
    build.zig
    src/
        main.zig

Build:

zig build

Run the installed executable:

./zig-out/bin/hello

E.2 The Build Function

Every build script exports a build function.

pub fn build(b: *std.Build) void {
    ...
}

The argument b is the build graph object. It creates compile steps, run steps, install steps, options, modules, and dependencies.

E.3 Target and Optimize Options

Most build scripts begin with the standard target and optimization options.

const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});

Use them in artifacts:

const exe = b.addExecutable(.{
    .name = "app",
    .root_source_file = b.path("src/main.zig"),
    .target = target,
    .optimize = optimize,
});

Then the user can choose:

zig build -Dtarget=x86_64-linux
zig build -Doptimize=ReleaseFast

Common optimize modes:

Debug
ReleaseSafe
ReleaseFast
ReleaseSmall

E.4 Executables

Create an executable:

const exe = b.addExecutable(.{
    .name = "app",
    .root_source_file = b.path("src/main.zig"),
    .target = target,
    .optimize = optimize,
});

Install it:

b.installArtifact(exe);

Add imports or link libraries before installing.

E.5 Libraries

Static library:

const lib = b.addStaticLibrary(.{
    .name = "mylib",
    .root_source_file = b.path("src/lib.zig"),
    .target = target,
    .optimize = optimize,
});

Shared library:

const lib = b.addSharedLibrary(.{
    .name = "mylib",
    .root_source_file = b.path("src/lib.zig"),
    .target = target,
    .optimize = optimize,
});

Install:

b.installArtifact(lib);

E.6 Modules

A module is an importable unit of Zig code.

const mod = b.createModule(.{
    .root_source_file = b.path("src/lib.zig"),
    .target = target,
    .optimize = optimize,
});

Import it into an executable:

exe.root_module.addImport("mylib", mod);

Then in Zig code:

const mylib = @import("mylib");

E.7 Tests

Create a test artifact:

const tests = b.addTest(.{
    .root_source_file = b.path("src/main.zig"),
    .target = target,
    .optimize = optimize,
});

Create a run step for it:

const run_tests = b.addRunArtifact(tests);

Expose it as a named build step:

const test_step = b.step("test", "Run tests");
test_step.dependOn(&run_tests.step);

Run:

zig build test

E.8 Run Steps

Run an executable from the build graph.

const run_cmd = b.addRunArtifact(exe);

Make it depend on installation if needed:

run_cmd.step.dependOn(b.getInstallStep());

Expose it:

const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);

Run:

zig build run

Pass arguments after --.

if (b.args) |args| {
    run_cmd.addArgs(args);
}

Command:

zig build run -- input.txt output.txt

E.9 Build Options

Define a boolean option:

const enable_log = b.option(
    bool,
    "log",
    "Enable logging",
) orelse false;

Create an options module:

const options = b.addOptions();
options.addOption(bool, "enable_log", enable_log);

Import it into the program:

exe.root_module.addOptions("build_options", options);

Use it:

const build_options = @import("build_options");

if (build_options.enable_log) {
    // logging code
}

Command:

zig build -Dlog=true

E.10 Dependencies

Fetch dependencies with zig fetch, then import them in build.zig.zon.

A build script reads a dependency by name.

const dep = b.dependency("example", .{
    .target = target,
    .optimize = optimize,
});

Import one of its modules:

exe.root_module.addImport(
    "example",
    dep.module("example"),
);

Then in source:

const example = @import("example");

E.11 Linking C

Link libc:

exe.linkLibC();

Add C source files:

exe.addCSourceFile(.{
    .file = b.path("src/add.c"),
    .flags = &.{ "-std=c99" },
});

Add include path:

exe.addIncludePath(b.path("include"));

Link a system library:

exe.linkSystemLibrary("m");

E.12 Installing Files

Install an artifact:

b.installArtifact(exe);

Install a file:

b.installFile("README.md", "share/app/README.md");

Install a directory:

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

E.13 Custom Steps

Create a named step:

const docs = b.step("docs", "Build documentation");

Make it depend on another step:

docs.dependOn(&some_other_step.step);

A custom step is useful when a project has several tasks:

zig build test
zig build docs
zig build run

E.14 Common Build Script

const std = @import("std");

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

    const exe = b.addExecutable(.{
        .name = "app",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    b.installArtifact(exe);

    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);

    const tests = b.addTest(.{
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });

    const run_tests = b.addRunArtifact(tests);

    const test_step = b.step("test", "Run tests");
    test_step.dependOn(&run_tests.step);
}

This build script supports:

zig build
zig build run
zig build test
zig build -Doptimize=ReleaseFast
zig build -Dtarget=aarch64-linux

A Zig build script is an ordinary Zig program. Keep it plain. Create artifacts, connect steps, expose the few commands the project needs.