mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 10:19:47 -04:00
ab87cb8ef4
A misconfigured overlay_autocompile_cmd silently degrades an entire session to the interpreter. The diagnosis machinery for this already existed and was good — autocompile_report_broken_once() fires after 3 consecutive failures and explains exactly what to check — but it writes to fprintf(stdout), and the shipped runtime links -mwindows: a GUI-subsystem binary with no console. The warning is emitted into nothing on precisely the builds people run. Observed cost: a fresh worktree ran 100% interpreted for a whole session (runs=8 fails=8 shard_ok=0, dispatch_native=0) because game.toml named a recompiler path the documented build recipe does not produce. The only symptom was "it feels slow", and it invalidated a performance A/B before anyone thought to query the counters by hand. Three changes: - Validate the command's path arguments at CONFIGURE time. The existing check resolves only the first token (the interpreter); it never looked at --recompiler, which is the argument that actually breaks — it is hardcoded per-title and disagrees with where the recipe builds. Paths now resolve against the child's working directory and are checked before any compile is attempted, rather than the truth emerging after three failed spawns. Advisory, not fatal: the runtime still runs exactly as before, just not silently. - Record WHY in one string, exposed as degraded/degraded_reason in autocompile_status over the TCP debug server. Rule 3's answer rather than more printing. Keeps the FIRST cause, which is the useful one. - Stamp it into psx_last_run_report.json. This is the part that prevents a repeat: a field you have to query is a field nobody queries. A degraded run now says so in its own artifact, so "was that measurement valid?" is answerable after the fact instead of having to be suspected. test_autocompile_degraded (new, registered in CTest) builds the real failure shape and asserts it is caught at configure time, that the reason names the offending flag, that the first cause is retained, and that the reason is escaped so it cannot break the JSON for every consumer. Also fixes a pre-existing %d/LONG format mismatch on last_exit that this change's argument shuffle surfaced; warnings on autocompile.c go 2 -> 1 (the remaining array-bounds one in watch_thread is pre-existing and untouched). NOT done here, deliberately: the underlying cause is that every title's game.toml hardcodes a build-directory path (Tomba 2 names a worktree-relative dir the recipe never creates; MMX6 hardcodes an absolute path into one checkout). Fixing that means having CMake record the real recompiler location and touching six title repos — its own change. This one makes the failure impossible to miss. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
75 lines
3.5 KiB
C
75 lines
3.5 KiB
C
/* autocompile.h — background overlay compile for variant-capture automation
|
|
* (step 2.8). Spawns the configured compile command (compile_overlays.py
|
|
* invocation from game.toml [runtime] overlay_autocompile_cmd) after an
|
|
* automatic capture, collects its output into an in-memory ring (no log
|
|
* files — CLAUDE.md §3; read it via the autocompile_status TCP command),
|
|
* and on success has the emu thread rescan the overlay-DLL cache so the new
|
|
* variant goes native in-session, without a restart. */
|
|
#ifndef PSXRECOMP_AUTOCOMPILE_H
|
|
#define PSXRECOMP_AUTOCOMPILE_H
|
|
|
|
#ifdef __cplusplus
|
|
extern "C" {
|
|
#endif
|
|
|
|
/* Store the command line + working directory. Empty cmd disables. */
|
|
void autocompile_configure(const char *cmd, const char *cwd);
|
|
int autocompile_configured(void);
|
|
|
|
/* Pin the canonical overlay cache dir + captures file the LOADER actually uses
|
|
* (<exe>/cache and <exe>/overlay_captures.json — computed once in main.cpp).
|
|
* autocompile injects these into every spawned compile via the environment
|
|
* (PSX_OVERLAY_CACHE_DIR / PSX_OVERLAY_CAPTURES), so the WRITE cache and the
|
|
* READ captures can never diverge from where the loader reads — for every game,
|
|
* dev or prod, gcc or tcc. compile_overlays.py / coverage_vault.py honor these
|
|
* over any CLI --out-dir/--captures. This is the single source of truth for the
|
|
* cache location: no per-game config, no drift. */
|
|
void autocompile_set_cache_paths(const char *cache_dir, const char *captures);
|
|
|
|
/* Probe whether a C compiler is actually reachable on PATH (gcc/cc/clang) — the
|
|
* REAL "developer machine" signal, distinct from autocompile_configured() which
|
|
* only reports that a command STRING is set (the shipped game.toml always sets
|
|
* one). overlay_backend_resolve uses this so `auto` picks gcc only when the
|
|
* toolchain can really build a shard, else tcc (toolchain-less production).
|
|
* Memoized; safe to call repeatedly. */
|
|
int autocompile_toolchain_available(void);
|
|
|
|
/* 1 while a compile process is running. */
|
|
int autocompile_busy(void);
|
|
|
|
/* Kick a compile if configured and idle. Returns 1 if started. */
|
|
int autocompile_request(void);
|
|
|
|
/* Emu-thread tick: applies a finished compile (cache rescan on success).
|
|
* Must be called from the same thread that owns the overlay loader. */
|
|
void autocompile_poll_main(void);
|
|
|
|
/* Process-shutdown teardown, emu thread only: stops the publication pipeline,
|
|
* kills the compiler process tree (job object), and JOINS the watcher and
|
|
* preparer threads — waiting out any in-flight LoadLibrary rather than
|
|
* abandoning a thread inside the Windows loader lock (which can deadlock
|
|
* ExitProcess). Safe to call in any state, including mid-run; idempotent. */
|
|
void autocompile_shutdown(void);
|
|
|
|
/* JSON status blob for the debug server: state, run/fail counters, last
|
|
* exit code, and the output tail. Returns bytes written. */
|
|
int autocompile_status_json(char *out, int cap);
|
|
|
|
/* Why overlay autocompile cannot work, or NULL if nothing is known to be wrong.
|
|
*
|
|
* When this is non-NULL, no shard will ever be compiled and overlay execution
|
|
* stays in the interpreter — the run is valid but its performance is
|
|
* meaningless. Callers that report timings should say so rather than publish a
|
|
* number measured in that state.
|
|
*
|
|
* This exists because the equivalent warnings are written to stdout and the
|
|
* shipped runtime links -mwindows, so they reach nobody. `autocompile_status`
|
|
* carries this out over the TCP debug server as "degraded"/"degraded_reason". */
|
|
const char *autocompile_degraded_reason(void);
|
|
|
|
#ifdef __cplusplus
|
|
}
|
|
#endif
|
|
|
|
#endif /* PSXRECOMP_AUTOCOMPILE_H */
|