Examples are small programs kept inside the project.
They show how the code is meant to be used. They also check that public APIs still compile.
A common layout is:
project/
├── build.zig
├── src/
│ └── root.zig
└── examples/
├── hello.zig
└── copy.zigAn example is an ordinary Zig program:
const std = @import("std");
const mylib = @import("mylib");
pub fn main() !void {
std.debug.print("{s}\n", .{mylib.message()});
}The build file creates an executable for it:
const example = b.addExecutable(.{
.name = "hello-example",
.root_module = b.createModule(.{
.root_source_file = b.path("examples/hello.zig"),
.target = target,
.optimize = optimize,
}),
});If the example imports the project library, attach the module:
const lib_mod = b.createModule(.{
.root_source_file = b.path("src/root.zig"),
.target = target,
.optimize = optimize,
});
example.root_module.addImport("mylib", lib_mod);Now examples/hello.zig can use:
const mylib = @import("mylib");Add a named step:
const examples_step = b.step("examples", "Build examples");
examples_step.dependOn(&example.step);Run it:
zig build examplesFor several examples, use a helper function or a loop:
const example_names = [_][]const u8{
"hello",
"copy",
};
const examples_step = b.step("examples", "Build examples");
for (example_names) |name| {
const path = b.fmt("examples/{s}.zig", .{name});
const exe = b.addExecutable(.{
.name = b.fmt("{s}-example", .{name}),
.root_module = b.createModule(.{
.root_source_file = b.path(path),
.target = target,
.optimize = optimize,
}),
});
exe.root_module.addImport("mylib", lib_mod);
examples_step.dependOn(&exe.step);
}Examples should stay short. Each one should show one use case.
Good examples have names like:
hello
copy-file
parse-json
serve-httpBad examples have names like:
test1
demo2
misc
stuffAn example can also have a run step:
const run_example = b.addRunArtifact(example);
const run_example_step = b.step("run-example", "Run hello example");
run_example_step.dependOn(&run_example.step);Then:
zig build run-examplebuilds and runs it.
For many examples, it is usually enough to build them. Running them may require files, ports, network access, or command-line arguments. Keep automatic example steps deterministic.
Examples are not a substitute for tests. Tests check exact behavior. Examples show intended use.
A good project usually has both.
Exercise 15-21. Create an examples/hello.zig file.
Exercise 15-22. Add an examples build step.
Exercise 15-23. Make the example import a module from src/root.zig.
Exercise 15-24. Add a second example and build both with one command.