# Build Options

### Build Options

A build option is a value passed to `build.zig` from the command line.

Build options let one build file describe several related builds. The user chooses the variant without editing source code.

The usual form is:

```sh
zig build -Dname=value
```

For example:

```sh
zig build -Dtrace=true
```

Inside `build.zig`, the option is read with `b.option`:

```zig
const trace = b.option(bool, "trace", "Enable trace output") orelse false;
```

The first argument is the type. The second is the option name. The third is the help text. If the user does not pass the option, `b.option` returns `null`, so the expression uses `orelse false`.

The option now appears in:

```sh
zig build --help
```

A build option may be a boolean:

```zig
const trace = b.option(bool, "trace", "Enable trace output") orelse false;
```

It may be an integer:

```zig
const port = b.option(u16, "port", "Default server port") orelse 8080;
```

It may be a string:

```zig
const mode = b.option([]const u8, "mode", "Program mode") orelse "normal";
```

The command line supplies them in the same style:

```sh
zig build -Dtrace=true -Dport=9000 -Dmode=debug
```

An option can change how the program is built:

```zig
if (trace) {
    exe.root_module.addCMacro("TRACE", "1");
}
```

More often, the option is passed into Zig source code as a compile-time configuration module.

```zig
const options = b.addOptions();

options.addOption(bool, "trace", trace);
options.addOption(u16, "port", port);
options.addOption([]const u8, "mode", mode);

exe.root_module.addOptions("config", options);
```

The source file imports the generated module:

```zig
const std = @import("std");
const config = @import("config");

pub fn main() void {
    std.debug.print("port: {d}\n", .{config.port});

    if (config.trace) {
        std.debug.print("trace enabled\n", .{});
    }
}
```

Build and run:

```sh
zig build run -Dtrace=true -Dport=9000
```

The program sees the values at compile time.

This matters. Since the values are compile-time constants, the compiler can remove dead branches.

```zig
if (config.trace) {
    expensiveTraceCode();
}
```

When `trace` is false, the branch can disappear from the generated program.

The standard build options work the same way, but are provided by the build system.

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

They add common options such as:

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

Do not invent a custom option when a standard one already exists. Use standard target and optimize options unless the project has a strong reason not to.

Options should have stable names. Once users and scripts depend on an option, renaming it breaks builds.

Good option names are short and specific:

```text
trace
tls
sqlite
port
backend
log-level
```

Bad option names are vague:

```text
flag
thing
extra
mode2
```

A build option should control one decision. If an option controls several unrelated things, split it.

Build options are part of the interface of the project. Treat them with the same care as command-line flags in the program itself.

Exercise 15-13. Add a boolean option named `trace`.

Exercise 15-14. Add an integer option named `port`.

Exercise 15-15. Pass both options into source code through a generated `config` module.

Exercise 15-16. Use the `trace` option to compile out a logging branch.

