From f3d60331a709fe63f7f70db59a5bb52597731e86 Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Tue, 4 Aug 2026 14:49:29 -0700 Subject: [PATCH] autocompile: name the resolved interpreter at configure, warn on Cygwin builds MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Root-caused on Tomba 1: overlay_autocompile_cmd's bare 'python' resolved through PATH to the devkitPro MSYS2/Cygwin python (usr/bin precedes the Windows install), which segfaults (exit 0x0B00, signal 11) under the kill-on-close job spawn BEFORE writing a byte — so every compile failed with '(no output captured)' and nothing pointed at the cause; the title silently ran interpreted. At configure time, resolve the command's first token exactly as cmd.exe /C will (SearchPathA with .exe), print the binding once, and warn loudly when msys-2.0.dll/cygwin1.dll sits beside the resolved interpreter, recommending the Windows launcher form 'py -3 ...'. Also fail loudly up front when the token doesn't resolve at all. Doc'd in ASYNC_OVERLAY_COMPILE.md. Title game.toml fixes (python -> py -3) ship separately in each game repo. Co-Authored-By: Claude Fable 5 --- docs/ASYNC_OVERLAY_COMPILE.md | 7 +++- runtime/src/autocompile.c | 64 +++++++++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+), 1 deletion(-) diff --git a/docs/ASYNC_OVERLAY_COMPILE.md b/docs/ASYNC_OVERLAY_COMPILE.md index 903c9f18..28eeba45 100644 --- a/docs/ASYNC_OVERLAY_COMPILE.md +++ b/docs/ASYNC_OVERLAY_COMPILE.md @@ -13,8 +13,13 @@ What this session ADDED to make it work under CPS + match the user's gcc-only pr 2. `overlay_loader.c overlay_loader_apply_live_policy` — when the active backend is gcc, sljit-live is forced OFF (gcc>interp; toolchain-less stays sljit>interp) — "mutually exclusive" per user. 3. The dev/soak config (`tomba_soak_a.toml`, untracked): `overlay_cache=true` + - `overlay_autocompile_cmd = python ../psxrecomp/tools/compile_overlays.py … --cps`. The PRODUCTION + `overlay_autocompile_cmd = py -3 ../psxrecomp/tools/compile_overlays.py … --cps`. The PRODUCTION `game.toml` overlay_autocompile_cmd needs `--cps` appended when CPS ships to master. + (Windows recipes must invoke the interpreter as `py -3`, never bare `python`: on machines where + an MSYS2/Cygwin `usr/bin` precedes the Windows Python on PATH, `python` binds to the Cygwin + build, which segfaults under the runtime's job-object spawn before writing any output — every + compile fails with "(no output captured)". The runtime prints the resolved interpreter at + startup and warns when it is a Cygwin binary.) VALIDATED: autocapture fired (triggers≥1) → background `compile_overlays --cps` produced CPS overlay DLLs (new CRCs, post-cache-clear) → loader loaded them (`loads`>0) → `dispatch_native` diff --git a/runtime/src/autocompile.c b/runtime/src/autocompile.c index 6db99553..57e2a997 100644 --- a/runtime/src/autocompile.c +++ b/runtime/src/autocompile.c @@ -560,6 +560,69 @@ static DWORD WINAPI watch_thread(LPVOID arg) { } #endif /* _WIN32 */ +#ifdef _WIN32 +/* Name the interpreter the spawn will actually run, once, at configure time. + * The command line's first token resolves through PATH exactly as cmd.exe /C + * will resolve it, and on machines where an MSYS2/Cygwin usr/bin precedes the + * Windows Python install, a bare `python` silently binds to the Cygwin build. + * That interpreter dies with SIGSEGV (exit 0x0B00) under this file's + * job-object spawn BEFORE writing a single byte, so the failure report shows + * "(no output captured)" and nothing points at the cause. Resolving and + * printing the binding up front turns that class of breakage into a one-line + * diagnosis; the msys-2.0.dll/cygwin1.dll sibling check calls it out loudly + * before the first compile ever runs. */ +static void autocompile_report_interpreter(void) { + char tok[MAX_PATH]; + size_t n = 0; + const char *p = s_cmd; + if (*p == '"') { /* quoted interpreter path */ + p++; + while (*p && *p != '"' && n + 1 < sizeof(tok)) tok[n++] = *p++; + } else { + while (*p && *p != ' ' && n + 1 < sizeof(tok)) tok[n++] = *p++; + } + tok[n] = '\0'; + if (!tok[0]) return; + char resolved[MAX_PATH]; + /* SearchPathA with .exe mirrors cmd.exe's lookup for extension-less + * tokens; a token that already has a path or extension resolves as-is. */ + DWORD r = SearchPathA(NULL, tok, ".exe", sizeof(resolved), resolved, NULL); + if (r == 0 || r >= sizeof(resolved)) { + fprintf(stdout, + "psxrecomp: overlay autocompile interpreter '%s' does not resolve " + "on PATH — every compile run will fail.\n", tok); + fflush(stdout); + return; + } + fprintf(stdout, "psxrecomp: overlay autocompile interpreter: %s\n", resolved); + char *slash = strrchr(resolved, '\\'); + if (!slash) slash = strrchr(resolved, '/'); + if (slash) { + static const char *posix_dlls[] = { "msys-2.0.dll", "cygwin1.dll" }; + for (size_t k = 0; k < sizeof(posix_dlls) / sizeof(posix_dlls[0]); k++) { + char cand[MAX_PATH + 16]; + snprintf(cand, sizeof(cand), "%.*s\\%s", + (int)(slash - resolved), resolved, posix_dlls[k]); + FILE *f = fopen(cand, "rb"); + if (f) { + fclose(f); + fprintf(stdout, + "psxrecomp: WARNING: that interpreter is an MSYS2/Cygwin " + "build (%s beside it).\n" + " Cygwin-runtime processes crash under the autocompile " + "job spawn before producing output,\n" + " so every overlay compile will fail with no diagnostics. " + "Use the Windows Python launcher\n" + " instead: overlay_autocompile_cmd = \"py -3 ...\" in " + "game.toml.\n", posix_dlls[k]); + fflush(stdout); + break; + } + } + } +} +#endif + void autocompile_configure(const char *cmd, const char *cwd) { snprintf(s_cmd, sizeof(s_cmd), "%s", cmd ? cmd : ""); snprintf(s_cwd, sizeof(s_cwd), "%s", cwd ? cwd : ""); @@ -569,6 +632,7 @@ void autocompile_configure(const char *cmd, const char *cwd) { InitializeConditionVariable(&s_publish_cv); s_out_lock_init = 1; } + if (s_cmd[0]) autocompile_report_interpreter(); #endif }