# Build Steps

### Build Steps

A build file describes steps.

A step is one action in the build graph. It may compile a program, install a file, run a command, generate source, or group other steps under a name.

The default build has an install step. This is why a simple project can be built with:

```sh
zig build
```

The command runs the default step, and that step depends on the artifacts that must be installed.

You can create your own step:

```zig
const check_step = b.step("check", "Check that the project builds");
```

The first string is the command name. The second string is the help text shown by:

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

A named step does nothing by itself. It becomes useful when other steps are attached to it.

```zig
check_step.dependOn(&exe.step);
```

Now this command builds the executable, but does not install it:

```sh
zig build check
```

The important operation is `dependOn`.

```zig
a.dependOn(b);
```

This means: before step `a` is complete, step `b` must be complete.

Build steps form a graph. The graph may branch and join.

For example, a project may have one step that runs tests and another that builds examples:

```zig
const test_step = b.step("test", "Run tests");
test_step.dependOn(&test_cmd.step);

const examples_step = b.step("examples", "Build examples");
examples_step.dependOn(&example_exe.step);
```

A third step may depend on both:

```zig
const ci_step = b.step("ci", "Run checks used by CI");
ci_step.dependOn(test_step);
ci_step.dependOn(examples_step);
```

Now:

```sh
zig build ci
```

runs the test step and the examples step.

A run step executes a compiled artifact:

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

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

Arguments can be passed to the program:

```zig
if (b.args) |args| {
    run_cmd.addArgs(args);
}
```

Then everything after `--` is passed to the program:

```sh
zig build run -- input.txt output.txt
```

A system command can also be a step:

```zig
const fmt_cmd = b.addSystemCommand(&.{
    "zig",
    "fmt",
    "src",
});
```

Attach it to a named step:

```zig
const fmt_step = b.step("fmt", "Format source files");
fmt_step.dependOn(&fmt_cmd.step);
```

Now:

```sh
zig build fmt
```

runs the formatter.

Use system commands carefully. They depend on programs being present on the host machine. Prefer Zig build operations when the build system provides them.

A generated file is also represented by steps. A command produces a file. Another step uses that file.

```zig
const gen = b.addSystemCommand(&.{
    "python3",
    "tools/gen.py",
});

const generated = gen.addOutputFileArg("table.zig");
```

The generated path can be used as an input to a module:

```zig
const mod = b.createModule(.{
    .root_source_file = generated,
    .target = target,
    .optimize = optimize,
});
```

The dependency is now recorded. If the module needs the generated file, the generator runs first.

Build steps should be small. Each step should have one clear job.

Good steps are named after actions:

```text
run
test
check
fmt
docs
examples
bench
ci
```

Avoid hiding unrelated work behind one vague step. A user should be able to ask the build system for exactly the action needed.

A build graph also documents the project. It says which artifacts exist, how they are made, and which commands are part of normal development.

Exercise 15-9. Add a `check` step that compiles the executable without installing it.

Exercise 15-10. Add a `fmt` step that formats the source directory.

Exercise 15-11. Add a `ci` step that depends on `check`, `fmt`, and `test`.

Exercise 15-12. Add argument forwarding to a `run` step.

