Skip to content

Appendix B — Worked examples

Appendix B. Worked examples (informative)

Informative. This appendix presents worked Cookfile examples, each annotated with the sections of the Standard it exercises. Examples are non-binding; they illustrate the normative rules defined in chapters 2–7 and Appendix A.

B.1. Multi-output cook step (from cli/e2e-fixtures/multi-output/Cookfile)

recipe generate
    gather "src/*.rs"
    cook "staging/out.js" "staging/out.wasm" {
        ./fake-generator.sh
        mkdir -p staging
        cp pkg/out.js staging/out.js
        cp pkg/out.wasm staging/out.wasm
    }

Exercises: § 6.1 (explicit header), § 8.2 (gather), § 8.5 (multi-output cook with { ... } shell block), App. A.3, App. A.4.

B.2. Chore with cross-recipe dependency (from cli/e2e-fixtures/cross-recipe-deps/Cookfile)

recipe tools: colorize wordcount reverse

chore play: tools
    mkdir -p .cook/scratch
    printf 'colorize\nwordcount\nreverse\n' | fzf --prompt='tool> ' > .cook/scratch/tool
    find data -type f | fzf --prompt='file> ' --preview='cat {}' > .cook/scratch/file
    ./build/bin/$(cat .cook/scratch/tool) < "$(cat .cook/scratch/file)"

The interactive task work lives in a chore (§ 7): every shell line is interactive by default (§ 7.3), so fzf inherits the terminal without any per-line marker. recipe tools is a pure aggregator (deps only). Exercises: § 6.1 (explicit headers with deps), § 6.2 (dependency list), § 7 (chore body), § 8.8 (interactive-by-default chore shell commands), App. A.3, App. A.4.

B.3. Module use and call (from examples/modules/fzf-picker/Cookfile)

use cpp

config
    env.CFLAGS = "-O2 -Wall"

recipe colorize
    cpp.bin("colorize", {
        sources = { "src/colorize.c" },
    })

Exercises: § 5.1 (use declaration), § 5.3 (config block with Lua body), § 8.1 (step dispatch), § 4.4 (module-call step), App. A.2, App. A.4.

B.4. Using-block Lua with multiple outputs (from cli/e2e-fixtures/multi-output/Cookfile)

recipe build_lua
    gather "src/*.rs"
    cook "staging-lua/out.js" "staging-lua/out.wasm" >{
        os.execute("mkdir -p staging-lua")
        local sources = table.concat(inputs, " ")
        local js = io.open(outputs[1], "w")
        js:write("// generated from " .. sources .. "\n")
        js:close()
        local wasm = io.open(outputs[2], "w")
        wasm:write("BINARY\n")
        wasm:close()
    }

Exercises: § 8.5 (multi-output cook with >{ ... } Lua block), § 23.1 (cook-body globals inputs / outputs), App. A.4.

B.5. Cross-recipe references

This example exercises the four surfaces of cross-recipe references defined in § 10.

Bare string substitution

recipe libmath
    gather "src/math/*.c"
    cook "build/obj/math/$<in.stem>.o" { gcc -c $<in> -o $<out> }
    cook "build/lib/libmath.a" { ar rcs $<out> $<in> }

recipe app
    cook "build/bin/app" { gcc -o $<out> main.c $<libmath> }

In app, the $<libmath> placeholder is a bare name reference (§ 10.5). It expands at register time to the single-element output list of libmath, i.e., "build/lib/libmath.a". The resulting app step’s command is gcc -o build/bin/app main.c build/lib/libmath.a.

Dep-driven iteration

recipe protos
    gather "proto/*.proto"

recipe compile_protos
    cook "build/obj/$<protos.stem>.pb.cc" { protoc --cpp_out=build/obj $<in> }

In compile_protos, the $<protos.stem> placeholder in the output pattern (§ 10.4) is an accessor placeholder. It names protos as the iteration driver. The step registers one work unit per item in protos’s output list — which, because protos has no cook step, is the resolved glob proto/*.proto passed through (§ 10.4.1). For each resolved path x, $<in> = x, $<in.stem> = path.stem(x), and $<protos.stem> = path.stem(x).

Gathered inputs-only recipe referenced by another

recipe headers
    gather "include/*.h"

recipe check: headers
    test { clang-tidy {headers} }

headers is a passthrough recipe with no cook step; its output is the resolved glob (§ 10.4.1). {headers} in check’s test command expands to the space-joined list. The : headers dep-list reference (§ 10.1 dep-list surface) creates a whole-recipe edge (§ 10.6); {headers} in the test command is redundant as an edge but fine for string substitution.

Mixed: one driver plus string substitution

recipe core
    cook "build/lib/libcore.a" { … }

recipe protos
    gather "proto/*.proto"

recipe server
    cook "build/obj/$<protos.stem>.o" { gcc -c $<in> -I$<core>/include -o $<out> }

The server step is dep-driven by protos (output pattern contains $<protos.stem>). The $<core> in the shell block is a bare string-substitution reference (§ 10.5) to core’s single output. The step thus depends on both protos (per-unit, driving iteration) and core (whole-recipe or refined per-unit, per § 10.6) — two distinct cross-recipe edges from a single step.

Exercises: § 10 (full chapter), § 8.2 (gather), § 8.4 (one-to-one cook step), § 16.1 (cross-recipe ordering).