# `zig build`

### `zig build`

Large programs are rarely built with a single compiler command.

A program may contain many source files. It may need tests, examples, generated files, libraries, or platform-specific options. Typing long command lines by hand quickly becomes tedious.

Zig solves this with a build system written in Zig itself.

Most Zig projects contain a file named `build.zig`. The `zig build` command reads this file and executes the build graph described inside it.

A small project might look like this:

```text
project/
├── build.zig
├── build.zig.zon
└── src/
    └── main.zig
```

The simplest useful `build.zig` file is short:

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

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

    b.installArtifact(exe);
}
```

Build the program:

```sh
zig build
```

Run the executable:

```sh
./zig-out/bin/hello
```

The command `zig build` does not directly compile source files itself. Instead, it executes the build description in `build.zig`.

The function:

```zig
pub fn build(b: *std.Build) void
```

is the entry point of the build system.

The parameter `b` is the build context. It provides functions for creating executables, libraries, tests, install steps, and custom commands.

This line creates an executable build step:

```zig
const exe = b.addExecutable(...)
```

The executable is named:

```zig
.name = "hello",
```

The source file is:

```zig
.root_source_file = b.path("src/main.zig"),
```

The compiler target comes from:

```zig
.target = b.standardTargetOptions(.{}),
```

This allows the user to select targets from the command line:

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

Optimization mode comes from:

```zig
.optimize = b.standardOptimizeOption(.{}),
```

This enables commands such as:

```sh
zig build -Doptimize=ReleaseFast
```

The final line:

```zig
b.installArtifact(exe);
```

adds an install step. By convention, installed files are written into `zig-out/`.

The build system is incremental. If a source file has not changed, Zig avoids rebuilding unnecessary parts of the project.

A build script is ordinary Zig code. Loops, conditions, helper functions, and compile-time computation can all be used naturally.

For example:

```zig
if (some_condition) {
    // add extra library
}
```

or:

```zig
for (targets) |target| {
    // build multiple executables
}
```

This is one of the major design choices of Zig's tooling. There is no separate build language. The language used to build Zig programs is Zig itself.

A project often defines additional build steps. For example:

```zig
const run_cmd = b.addRunArtifact(exe);

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

Now the program can be run with:

```sh
zig build run
```

Tests are commonly integrated the same way:

```zig
const tests = b.addTest(.{
    .root_module = b.createModule(.{
        .root_source_file = b.path("src/main.zig"),
    }),
});
```

and executed with:

```sh
zig build test
```

The build system is still evolving in Zig 0.16, but its overall direction is stable:

- Build descriptions are code.
- Cross compilation is built in.
- Dependencies are explicit.
- Build graphs are incremental.
- The standard toolchain handles compilation, linking, testing, formatting, and packaging together.

Exercise 15-1. Create a project with `build.zig` and one source file.

Exercise 15-2. Add a `run` step.

Exercise 15-3. Build the same program for another operating system.

Exercise 15-4. Add a test step and run it with `zig build test`.

