10. Dropping into Lua
Most Cookfiles are pure surface syntax. Underneath, every Cookfile compiles to Lua, and you can reach for that API when the surface can't express what you…
Most Cookfiles are pure surface syntax. Underneath, every Cookfile compiles to
Lua, and you can reach for that API when the surface can’t express what you need.
cook emit-lua prints exactly what a Cookfile lowers to.
Cook runs in two phases, and Lua appears in both:
-
Execute-phase Lua is a
>{ ... }body on acook/test/probestep (or a>step inside a chore). It runs when the unit runs, withinput/output(orinputs/outputs) bound to the unit’s resolved I/O:recipe uppergather "src/*.txt"cook "build/$<in.stem>.txt" >{local text = fs.read(input)fs.write(output, text:upper())} -
Register-phase Lua in a recipe body is a bare module call:
cook.add_unit {...},cook.step_group(...), ormymod.fn(...). For loops or locals, put the code in a top-levelregisterblock or a module function:registerfor _, src in ipairs(fs.glob("src/*.c")) docook.add_unit({inputs = { src },output = "build/" .. path.stem(src) .. ".o",command = "gcc -c " .. src .. " -o build/" .. path.stem(src) .. ".o",})end
cook.add_unit is the lowest level: the surface cook step desugars to it. Its
fields include inputs, output/outputs, command (or lua_code),
discovered_inputs (for compiler .d depfiles, folded into the key), and the
cache-trust fields probes, seal, sharing, and record. Fields are strictly
typed: a wrong-typed field is a hard error, never coerced. Use cook.sh(cmd) when
you need a command’s output now in your Lua (feature detection, a git tag);
it runs immediately and returns stdout.
The >> register prefix and the @ interactive prefix that older docs mention
were removed; register-phase Lua is a bare module call, and chore shell is
interactive by default.