Zig Build Scripts in Depth
A build script is a Zig file named build.zig that tells zig build what to make and how to run it. This lesson builds a first build script with a run step.
A first build script
This build script creates an executable, installs it, and adds a run step.
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "hello",
.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());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
Two programs, one script
One build script can build two programs and run the one the run step names.
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const hello = b.addExecutable(.{
.name = "hello",
.root_source_file = b.path("src/main.zig"),
.target = target,
.optimize = optimize,
});
const bye = b.addExecutable(.{
.name = "bye",
.root_source_file = b.path("src/bye.zig"),
.target = target,
.optimize = optimize,
});
b.installArtifact(hello);
b.installArtifact(bye);
const run_cmd = b.addRunArtifact(bye);
run_cmd.step.dependOn(b.getInstallStep());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
The program stays ordinary
The build script changes how a program is built, not what the program itself does.
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "hello",
.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());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
Example
const std = @import("std");
pub fn build(b: *std.Build) void {
const target = b.standardTargetOptions(.{});
const optimize = b.standardOptimizeOption(.{});
const exe = b.addExecutable(.{
.name = "hello",
.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());
const run_step = b.step("run", "Run the app");
run_step.dependOn(&run_cmd.step);
}
Key points
- Build script: a build script is a Zig file named build.zig that tells zig build what to make.
- Executable: an executable is a program file the computer can run.
- Install step: the install step is the built-in step that copies a built program into zig-out.
- Run step: a run step is a named step that runs a built program when you ask for it.
- The build function receives a pointer to the build state, and every piece of the build is added inside it.
- The run step is tied to the install step, so the program is built before it runs.
- Plain zig build runs the install step only and prints nothing.
The build script creates an executable named hello from src/main.zig and installs it. The run step runs that executable when zig build run is asked for. The program itself multiplies 6 by 7 and prints the result. The build script and the program stay in separate files, each doing one job.
Try it Yourself
Edit the code, then press Run.
Running is simulated
Exercise
Which call turns a built program into something the build can run?