From 37d3ba1543705c6523b586ddd26271e46994f8d7 Mon Sep 17 00:00:00 2001 From: "shoney.arickathil" Date: Tue, 15 Sep 2026 01:33:25 +0200 Subject: [PATCH] =?UTF-8?q?fix(compiler):=20woc=20build=20-o=20creates=20t?= =?UTF-8?q?he=20output's=20parent=20directory=20=E2=80=94=20a=20fresh=20ch?= =?UTF-8?q?eckout=20has=20no=20target/?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - `woc build -o /target/` 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 (cherry picked from commit e9213bb949e1c26cb3a29d6f9babf2322a82d839) --- compiler/bin/main.ml | 10 ++++++++++ scripts/single-binary-smoke.sh | 15 +++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/compiler/bin/main.ml b/compiler/bin/main.ml index bf40073..67b502e 100644 --- a/compiler/bin/main.ml +++ b/compiler/bin/main.ml @@ -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 /` 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 diff --git a/scripts/single-binary-smoke.sh b/scripts/single-binary-smoke.sh index 5a4eb33..bcb47ce 100755 --- a/scripts/single-binary-smoke.sh +++ b/scripts/single-binary-smoke.sh @@ -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 /target/`: `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"