Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Your first build

A zut workspace is a directory tree with BUILD files. Each BUILD file declares targets; a target is an instance of a rule (like rust_binary) with some attributes.

A minimal example

Let’s build a Rust binary that links a Zig static library. Create this layout:

myproject/
  BUILD
  src/main.rs
  greet.zig

greet.zig — a tiny C-ABI function:

export fn zut_add(a: i32, b: i32) callconv(.c) i32 {
    return a + b;
}

src/main.rs — calls into it:

extern "C" { fn zut_add(a: i32, b: i32) -> i32; }

fn main() {
    println!("2 + 3 = {}", unsafe { zut_add(2, 3) });
}

BUILD — wire them together using the built-in prelude:

load("@builtin//:rust.bzl", "rust_binary")
load("@builtin//:zig.bzl", "zig_library")

zig_library(
    name = "greet",
    src = "greet.zig",
    libname = "greet",
)

rust_binary(
    name = "hello",
    crate_root = "src/main.rs",
    srcs = ["src/main.rs"],
    edition = "2021",
    out = "hello",
    native_deps = [":greet"],
)

Build it

$ zut build //:hello
zut build //:hello
  sandbox: namespace (recursive ro host, net+pid isolated)
  toolchain: rust[1.xx] zig[0.16.0]
  jobs: 8
  libgreet.a                   [zig]  built
  hello                        [rustc]  built
  -> zut-out/hello
  done — 2 built, 0 cached

$ ./zut-out/hello
2 + 3 = 5

The label //:hello means “the target named hello in the BUILD file at the workspace root”. A target in a subdirectory foo/bar is //foo/bar:name.

Incrementality in action

Run the same command again, unchanged:

$ zut build //:hello
  ...
  up to date — 2 action(s), all cached

Nothing rebuilds: zut hashed the action inputs, found the outputs already in its content-addressed store, and served them. Now touch only the Rust source and rebuild — only the rustc action re-runs; the Zig library is still a cache hit, because its inputs didn’t change.

Build state lives under .zut/ in your workspace (the CAS, the action cache, and a work directory). Delete .zut/ to start cold; it is safe to .gitignore.

Next: import crates.io dependencies.