fix(compiler): woc build -o creates the output's parent directory — a fresh checkout has no target/

- `woc build <dir> -o <example>/target/<name>` wrote its temp file beside the
  output and failed with "No such file or directory" when target/ was absent;
  target/ is gitignored, so every fresh checkout hit it — the db-actor and
  db-bench gates went red on a clean master worktree while passing on dev,
  where the directories exist from history
- the driver now creates the output's parent (mkdir -p shape) before the
  temp write; project-mode builds and existing directories are unchanged
- single-binary-smoke.sh gains `build-into-missing-dir` (4 checks, was 3),
  red on the old driver, green on this one; woc-test clean

Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
(cherry picked from commit e9213bb949e1c26cb3a29d6f9babf2322a82d839)
This commit is contained in:
shoney.arickathil 2026-09-15 01:33:25 +02:00
parent ed2786c6ea
commit 37d3ba1543
2 changed files with 25 additions and 0 deletions

View file

@ -878,6 +878,16 @@ let build_mode ?(deps : (string * string) list = []) ~(runtime : string option)
Printf.eprintf "woc: %s\n" msg;
exit 2
in
(* a fresh checkout has no target/ directories: create the output's
parent, so `-o <dir>/<name>` works the way every gate and README
invokes it instead of failing on the temp file below *)
let rec mkdir_p d =
if d <> "" && d <> "." && d <> "/" && not (Sys.file_exists d) then begin
mkdir_p (Filename.dirname d);
(try Sys.mkdir d 0o755 with Sys_error _ -> ())
end
in
mkdir_p (Filename.dirname out);
let tmp = out ^ ".woc-build.tmp" in
(* stale tmp from an interrupted earlier build must not survive: its
permission bits would leak through, since Open_creat on an

View file

@ -62,6 +62,21 @@ else
ok "single-binary/build"
fi
# ---- -o into a directory that does not exist yet ---------------------------
# A fresh checkout has no target/ anywhere (gitignored), and every example
# gate builds with `-o <example>/target/<name>`: `woc build` must create the
# output's parent rather than fail on its own temp file there.
FRESH="$WORK/fresh/target/app"
if ! timeout "$TIMEOUT" "$WOC" build "$SRC" -o "$FRESH" --runtime "$WOVM" \
>"$WORK/fresh.out" 2>"$WORK/fresh.err"; then
rc=$?
bad "single-binary/build-into-missing-dir" "woc build exited $rc: $(head -1 "$WORK/fresh.err")"
elif [[ ! -x "$FRESH" ]]; then
bad "single-binary/build-into-missing-dir" "output missing or not executable: $FRESH"
else
ok "single-binary/build-into-missing-dir"
fi
# ---- relocate outside the repo, run with no args, diff --------------------
if [[ -x "$APP" ]]; then
cp "$APP" "$ELSEWHERE/app"