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

BUILD files & Starlark

zut workspaces are described in BUILD files written in Starlark — the same Python-like configuration dialect used by Bazel and Buck2. zut implements its own Starlark front-end (lexer, parser, evaluator) in Zig.

Targets, rules, packages

  • A package is a directory with a BUILD file.
  • A target is a named instance of a rule declared in that BUILD file.
  • A label addresses a target: //pkg:name (or //:name at the root).
load("@builtin//:rust.bzl", "rust_binary")

rust_binary(           # the rule
    name = "hello",    # → label //:hello
    crate_root = "src/main.rs",
    srcs = ["src/main.rs"],
    edition = "2021",
    out = "hello",
)

load() and .bzl modules

Reusable definitions (rules, macros, constants) live in .bzl files and are imported with load():

load("//rules:my_rules.bzl", "my_rule")        # a workspace .bzl
load("@builtin//:rust.bzl", "rust_binary", lib = "rust_library")  # built-in, with rename
  • //rules:my_rules.bzl — a .bzl in your workspace.
  • @builtin//:rust.bzl — a module from the built-in prelude that ships inside the zut binary.

load() symbols can be renamed (lib = "rust_library") to avoid clashes.

The Starlark dialect

zut supports the core of Starlark: def functions, if/for, lists, dicts, strings (with .format(), slicing), comprehensions, struct(...), and the build-specific builtins below. It is deterministic by design — no clocks, no randomness, no I/O from Starlark itself; side effects happen only through declared actions.

Build-specific builtins you’ll use inside rule implementations:

BuiltinPurpose
rule(implementation, attrs)define a rule
attrs.string(), attrs.label(), …declare a rule’s attributes
provider(...) / DefaultInfo(...)define/return providers
ctx.actions.declare_file(name)declare an output file
ctx.actions.run(executable, arguments, inputs, outputs, env)register an action
crate_tree("<name> <ver>", mount)graft a fetched crates.io source Tree

Cross-package dependencies are resolved lazily: zut loads a dependency’s BUILD only when a target actually needs it.

Next: rules & providers.