Skip to content

§ 18 — Output materialisation

18. Output materialisation

Normative. This chapter defines the parent-directory-creation rule that the engine performs before invoking a cook step’s shell text.

18.1. Output path materialisation

Before invoking the shell text of a cook step, a conforming implementation MUST ensure that the parent directory of every output path declared by the step exists, creating it (and any missing ancestors) if necessary. The creation MUST be idempotent: it is not an error if the directory already exists. The creation MUST NOT proceed if the parent path resolves to a non-directory (regular file, symbolic link to a regular file, etc.); in that case the implementation MUST surface a clear diagnostic naming the output path and the offending parent, and MUST NOT execute the step’s shell text.

The output paths covered by this rule are exactly those declared by the cook step in its surface form (§ 8.4, § 8.5) — that is, the paths recorded as the unit’s output-path list during the register phase (§ 17). Each output path is resolved against the unit’s working directory using the same resolution that the cache fingerprint applies. An output path with no parent component (a path that resolves to the working directory itself) is a no-op.

This rule applies to cook steps only. test steps (§ 8.6) declare no cacheable output paths and are therefore not covered; authors of test step bodies that need to create directories MUST do so explicitly.

Note 18.1.1

This rule turns the common mkdir -p $<out.dir> boilerplate into a no-op; authors MAY omit it from new recipes. Existing recipes that contain mkdir -p in their cook-step shell text continue to work — the explicit call becomes idempotently harmless after the engine’s pre-step mkdir -p.

Note 18.1.2

The pre-step directory creation is the engine acting on a path that the register phase has already declared as an output of the unit. It is not a Cook Lua API call and is therefore independent of the fs.* sandbox in § 25.1 (CS-0045). Out-of-project output paths are governed by the cache contract in § 17 and the path-resolution rules in § 20.1; this rule does not relax them.

Note 18.1.3

For a directory output (an outputs[] entry ending in /, § 17.6), the parent-directory-creation rule applies by treating dir itself as the path whose parent is ensured; the directory output’s own root (dir/) is created by the producing command, not by this rule.