🎓 A1Learner
🔍
0 of 46 lessons completed

Zig Build Options

A build option is a named value given to zig build with a -D flag. This lesson reads a bool flag, a greeting word, and a number through build options.

A bool flag with a fallback

The build script reads a bool flag and falls back to false when no flag is given.

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,
    });
    const extra = b.option(bool, "extra", "Print an extra line") orelse false;
    const greeting = b.option([]const u8, "greeting", "Greeting word") orelse "Hello";
    const name = b.option([]const u8, "name", "Name to greet") orelse "World";
    const options = b.addOptions();
    options.addOption(bool, "extra", extra);
    options.addOption([]const u8, "greeting", greeting);
    options.addOption([]const u8, "name", name);
    exe.root_module.addOptions("config", options);
    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);
}

Flipping the flag on

Passing -Dextra=true flips the flag on, so the program takes the other branch.

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,
    });
    const extra = b.option(bool, "extra", "Print an extra line") orelse true;
    const greeting = b.option([]const u8, "greeting", "Greeting word") orelse "Hello";
    const name = b.option([]const u8, "name", "Name to greet") orelse "World";
    const options = b.addOptions();
    options.addOption(bool, "extra", extra);
    options.addOption([]const u8, "greeting", greeting);
    options.addOption([]const u8, "name", name);
    exe.root_module.addOptions("config", options);
    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);
}

String flags

String flags work the same way, with a word after the equals sign.

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,
    });
    const extra = b.option(bool, "extra", "Print an extra line") orelse false;
    const greeting = b.option([]const u8, "greeting", "Greeting word") orelse "Hi";
    const name = b.option([]const u8, "name", "Name to greet") orelse "Zig";
    const options = b.addOptions();
    options.addOption(bool, "extra", extra);
    options.addOption([]const u8, "greeting", greeting);
    options.addOption([]const u8, "name", name);
    exe.root_module.addOptions("config", options);
    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 = "counter",
        .root_source_file = b.path("src/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    const count = b.option(u32, "count", "How many lines to print") orelse 3;
    const options = b.addOptions();
    options.addOption(u32, "count", count);
    exe.root_module.addOptions("config", options);
    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 option: a build option is a named value given to zig build with a -D flag.
  • Default: a default is the value used when no flag is given.
  • Options module: an options module is a small module the build script fills with chosen values, which the program reads with @import.
  • A bool flag switches a feature on or off.
  • A string flag replaces a word in the program.
  • Flags are read when the build runs, so changing a flag rebuilds the program with the new value.

The build script reads a count flag and falls back to 3. The count travels into the program through the config module. The program prints one Tick line per count, numbered from 1. Running without a flag prints three lines, and a -Dcount flag would change that number.

Try it Yourself

Edit the code, then press Run.

Running is simulated

Exercise

Which flag turns the extra feature on?