# Idiomatic way of using Zig build system with multiple binaries

**URL:** <https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086>\
**Category:** Help\
**Tags:** build-system\
**Created:** [September 21, 2024, 4:53pm UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086 "2024-09-21T16:53:08Z")\
**Posts on this page:** 10\
**Page:** 1

<div class="post-metadata">

**Author:** ![mitjafelicijan](https://ziggit.dev/user_avatar/ziggit.dev/mitjafelicijan/32/1949_2.png) [@mitjafelicijan](https://ziggit.dev/u/mitjafelicijan)\
**Post date:** [September 21, 2024, 4:53pm UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/1 "2024-09-21T16:53:08Z")

</div>

Hi all.

I have been diving deeper into Zig build system, so I don’t have to use Makefiles anymore.

I have read the official guide and the system seems quite powerful, but I do have one question when it comes to multiple binaries and how to compile just one binary and not everything.

In my testing project, I have two programs (`build.zig` looks like this).

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const runtime = b.addExecutable(.{
        .name = "runtime",
        .root_source_file = b.path("runtime/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(runtime);

    const sandbox = b.addExecutable(.{
        .name = "sandbox",
        .root_source_file = b.path("sandbox/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(sandbox);
}

```

I can of course build both of them with `zig build`. What I am wondering is, what is the best way to compile just one of them. Something like `zig build sandbox`.

Is there a common way to achieve this, maybe a pattern, I don’t know.

Thank you in advance!

---

<div class="post-metadata">

**Author:** ![dimdin](https://ziggit.dev/user_avatar/ziggit.dev/dimdin/32/1457_2.png) [@dimdin](https://ziggit.dev/u/dimdin)\
**Post date:** [September 21, 2024, 5:33pm UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/2 "2024-09-21T17:33:32Z")

</div>

You need to add two steps (build targets):

```zig
    const runtime_step = b.step("runtime", "Build runtime");
    const sandbox_step = b.step("sandbox", "Build sandbox");

```

These steps are listed, with their name and description, when running: `zig build -l`

* * *

EDIT: added calls to addInstallArtifact that copies the executable to `zig-out/bin`

```zig
const install_runtime = b.addInstallArtifact(runtime, .{});
const install_sandbox = b.addInstallArtifact(sandbox, .{});

```

* * *

Finally you need to add the step dependencies:

```zig
    runtime_step.dependOn(&install_runtime.step);
    sandbox_step.dependOn(&install_sandbox.step);

```

* * *

Then you can build:

- `runtime` by running `zig build runtime`,
- `sandbox` by running `zig build sandbox`,
- both by running `zig build runtime sandbox`,
- both (via the default install step) by running `zig build`.

* * *

See also: [Build System Tricks](https://ziggit.dev/t/build-system-tricks/3531)

---

<div class="post-metadata">

**Author:** ![mitjafelicijan](https://ziggit.dev/user_avatar/ziggit.dev/mitjafelicijan/32/1949_2.png) [@mitjafelicijan](https://ziggit.dev/u/mitjafelicijan)\
**Post date:** [September 21, 2024, 11:32pm UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/3 "2024-09-21T23:32:26Z")

</div>

This does not build the binary for me. Doing `zig build` builds both of them, and the steps are listed when I do `zig build -l`.

```zig
$ zig build -l
  install (default) Copy build artifacts to prefix path
  uninstall Remove build artifacts from prefix path
  runtime Build runtime
  sandbox Build sandbox

```

My code after I added the suggested solution looks like:

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    const runtime = b.addExecutable(.{
        .name = "runtime",
        .root_source_file = b.path("runtime/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(runtime);

    const sandbox = b.addExecutable(.{
        .name = "sandbox",
        .root_source_file = b.path("sandbox/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(sandbox);

    const runtime_step = b.step("runtime", "Build runtime");
    const sandbox_step = b.step("sandbox", "Build sandbox");

    runtime_step.dependOn(&runtime.step);
    sandbox_step.dependOn(&sandbox.step);
}

```

I have tried deleting `zig-out` folder and then also recreating en empty `zig-out/bin` folder just to test if maybe that would be a problem, and no dice.

If I do `zig build runtime` or `zig build sandbox` nothing happens. No errors are displayed.

I also checked the status of last command which was `zig build runtime` and I got:

```zig
$ echo $?
0

```

Am I missing something?

---

<div class="post-metadata">

**Author:** ![mocompute](https://ziggit.dev/user_avatar/ziggit.dev/mocompute/32/3226_2.png) [@mocompute](https://ziggit.dev/u/mocompute)\
**Post date:** [September 22, 2024, 1:36am UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/4 "2024-09-22T01:36:52Z")

</div>

It can be quite difficult to understand what’s happening under the hood. Try using the `--summary all` or `new` options to get an output of what’s actually been built versus retrieved from cache.

---

<div class="post-metadata">

**Author:** ![mocompute](https://ziggit.dev/user_avatar/ziggit.dev/mocompute/32/3226_2.png) [@mocompute](https://ziggit.dev/u/mocompute)\
**Post date:** [September 22, 2024, 1:39am UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/5 "2024-09-22T01:39:16Z")

</div>

> [@mitjafelicijan](#):
>
> If I do `zig build runtime` or `zig build sandbox` nothing happens. No errors are displayed.

This usually means the artifacts were cached and their inputs were unchanged, so no rebuild happened. Use the `--summary` option to see what zig build actually did.

---

<div class="post-metadata">

**Author:** ![mitjafelicijan](https://ziggit.dev/user_avatar/ziggit.dev/mitjafelicijan/32/1949_2.png) [@mitjafelicijan](https://ziggit.dev/u/mitjafelicijan)\
**Post date:** [September 22, 2024, 3:39am UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/6 "2024-09-22T03:39:48Z")

</div>

I was indeed being cached, and I have managed to fix it with providing a new cache directory with:

```zig
$ zig build sandbox --summary all --cache-dir ./zig-cache
Build Summary: 2/2 steps succeeded
sandbox success
└─ zig build-exe sandbox Debug native success 969ms MaxRSS:189M

```

Note: even when I changed the source file, it was still treating it like nothing changed. When I provided a custom cache directory, it started working.

I guess because I did `zig build` before adding new executables, it somehow got confused. I am using version 0.14.

This is ok now, and I will continue providing `--cache-dir` just to be sure.

---

<div class="post-metadata">

**Author:** ![ianprime0509](https://ziggit.dev/user_avatar/ziggit.dev/ianprime0509/32/1226_2.png) [@ianprime0509](https://ziggit.dev/u/ianprime0509)\
**Post date:** [September 22, 2024, 3:46am UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/7 "2024-09-22T03:46:50Z")

</div>

The issue with this version is that `b.addExecutable` only builds the executable (artifact), but doesn’t do anything with it. To get the executable to appear in `zig-out/bin`, you additionally need an install step:

```zig
const install_runtime = b.addInstallArtifact(runtime, .{});
runtime_step.dependOn(&install_runtime.step);

```

This is actually what `b.installArtifact(runtime)` is doing under the hood for the default “install” step. The entire implementation of `installArtifact` is

```zig
pub fn installArtifact(b: *Build, artifact: *Step.Compile) void {
    b.getInstallStep().dependOn(&b.addInstallArtifact(artifact, .{}).step);
}

```

That is, it’s just creating an install step for the artifact and adding it as a dependency of the “install” step. By creating your own install steps, you can add them selectively as dependencies of other steps, as you’re looking to do here.

---

<div class="post-metadata">

**Author:** ![mitjafelicijan](https://ziggit.dev/user_avatar/ziggit.dev/mitjafelicijan/32/1949_2.png) [@mitjafelicijan](https://ziggit.dev/u/mitjafelicijan)\
**Post date:** [September 22, 2024, 3:55am UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/8 "2024-09-22T03:55:00Z")

</div>

@ianprime0509 you are correct, Install artifact was indeed missing. Now it’s working without me providing any other arguments.

This is what I have now, and it’s been working. I’m pasting it here if somebody will also wonder about this.

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

pub fn build(b: *std.Build) void {
    const target = b.standardTargetOptions(.{});
    const optimize = b.standardOptimizeOption(.{});

    // Runtime.
    const runtime = b.addExecutable(.{
        .name = "runtime",
        .root_source_file = b.path("runtime/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(runtime);

    const runtime_step = b.step("runtime", "Build runtime");
    runtime_step.dependOn(&runtime.step);

    const install_runtime = b.addInstallArtifact(runtime, .{});
    runtime_step.dependOn(&install_runtime.step);

    // Sandbox.
    const sandbox = b.addExecutable(.{
        .name = "sandbox",
        .root_source_file = b.path("sandbox/main.zig"),
        .target = target,
        .optimize = optimize,
    });
    b.installArtifact(sandbox);

    const sandbox_step = b.step("sandbox", "Build sandbox");
    sandbox_step.dependOn(&sandbox.step);

    const install_sandbox = b.addInstallArtifact(sandbox, .{});
    sandbox_step.dependOn(&install_sandbox.step);
}

```

I can now build each one of the seperately or all together with the following commands.

```sh
# all together
$ zig build --summary all

# just runtime
$ zig build runtime --summary all

# just sandbox
$ zig build sandbox --summary all

```

---

<div class="post-metadata">

**Author:** ![ianprime0509](https://ziggit.dev/user_avatar/ziggit.dev/ianprime0509/32/1226_2.png) [@ianprime0509](https://ziggit.dev/u/ianprime0509)\
**Post date:** [September 22, 2024, 4:04am UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/9 "2024-09-22T04:04:49Z")

</div>

Just to add on to this, you also no longer need the explicit `runtime_step.dependOn(&runtime.step)`, since `runtime` is already a dependency of `install_runtime` (to install any artifact, it needs to be built first), and hence transitively of `runtime_step` (due to `runtime_step.dependOn(&install_runtime.step)`). The resulting build graph will end up looking like

```plaintext
runtime_step <- install_runtime <- runtime

```

---

<div class="post-metadata">

**Author:** ![dee0xeed](https://ziggit.dev/letter_avatar_proxy/v4/letter/d/3ab097/32.png) [@dee0xeed](https://ziggit.dev/u/dee0xeed)\
**Post date:** [September 22, 2024, 2:50pm UTC](https://ziggit.dev/t/idiomatic-way-of-using-zig-build-system-with-multiple-binaries/6086/10 "2024-09-22T14:50:30Z")

</div>

[related topic](https://ziggit.dev/t/how-to-produce-more-than-one-executable-in-a-single-build-zig/5554)
