toolchain patch windows

This commit is contained in:
Alex Vanderveen
2026-08-01 14:09:49 -04:00
parent 3e46b5f033
commit db24f79db5
5 changed files with 148 additions and 19 deletions
+40
View File
@@ -538,6 +538,7 @@ static int resolve_toolchain_bin(char* out, size_t cap) {
}
static void activate_toolchain_path(void) {
char pack_root[1400];
g_toolchain_bin[0] = '\0';
if (!resolve_toolchain_bin(g_toolchain_bin, sizeof(g_toolchain_bin)))
return;
@@ -553,6 +554,39 @@ static void activate_toolchain_path(void) {
old ? old : "");
setenv("PATH", neu, 1);
#endif
/* Pack root (parent of bin/) — Windows cmake-clang-v1 ships zlib here. */
if (dirname_copy(pack_root, sizeof(pack_root), g_toolchain_bin) &&
pack_root[0]) {
#if defined(_WIN32)
_putenv_s("ZLIB_ROOT", pack_root);
{
const char* prev = getenv("CMAKE_PREFIX_PATH");
char pref[8192];
if (prev && prev[0] && !strstr(prev, pack_root))
snprintf(pref, sizeof(pref), "%s;%s", pack_root, prev);
else if (!prev || !prev[0])
snprintf(pref, sizeof(pref), "%s", pack_root);
else
pref[0] = '\0';
if (pref[0])
_putenv_s("CMAKE_PREFIX_PATH", pref);
}
#else
setenv("ZLIB_ROOT", pack_root, 1);
{
const char* prev = getenv("CMAKE_PREFIX_PATH");
char pref[8192];
if (prev && prev[0] && !strstr(prev, pack_root))
snprintf(pref, sizeof(pref), "%s:%s", pack_root, prev);
else if (!prev || !prev[0])
snprintf(pref, sizeof(pref), "%s", pack_root);
else
pref[0] = '\0';
if (pref[0])
setenv("CMAKE_PREFIX_PATH", pref, 1);
}
#endif
}
}
static int find_cmake(char* out, size_t cap) {
@@ -1623,6 +1657,12 @@ static int write_windows_deferred_rebuild_helper(char* err_msg, size_t err_cap)
snprintf(err_msg, err_cap, "Failed to form helper path.");
return 0;
}
/* Setup zips omit build-release/; create it before writing the .cmd. */
if (!mkdir_p(g_build_dir)) {
snprintf(err_msg, err_cap, "Failed to create build dir: %s",
g_build_dir);
return 0;
}
FILE* f = fopen(g_helper_path, "wb");
if (!f) {
snprintf(err_msg, err_cap, "Failed to write rebuild helper: %s",
+22 -10
View File
@@ -375,7 +375,7 @@ def ensure_framework(
if need_seed and (ROOT / "bios").is_dir():
if progress:
progress.log(
f"Seeding psxrecomp BIOS profiles from SDK → {fw}"
f"Seeding psxrecomp BIOS profiles from SDK -> {fw}"
)
fw.mkdir(parents=True, exist_ok=True)
_copy_missing(ROOT / "bios", fw / "bios")
@@ -533,7 +533,7 @@ def run_prepare_disc(
script = ROOT / "tools" / "prepare_disc.py"
if not script.is_file():
raise RuntimeError(f"missing {script}")
progress.phase("prepare_disc", pct=0.15, message="Normalizing disc image…")
progress.phase("prepare_disc", pct=0.15, message="Normalizing disc image...")
cmd = [
sys.executable,
str(script),
@@ -633,7 +633,7 @@ def cmd_generate(args: argparse.Namespace, progress: ProgressReporter) -> int:
progress.error(f"BIOS not found: {bios_path}", code=EXIT_USAGE)
return EXIT_USAGE
dest = fw / "bios" / "SCPH1001.BIN"
progress.phase("bios", pct=0.15, message="Staging retail BIOS dump…")
progress.phase("bios", pct=0.15, message="Staging retail BIOS dump...")
try:
dest.parent.mkdir(parents=True, exist_ok=True)
if dest.resolve() != bios_path.resolve():
@@ -642,7 +642,7 @@ def cmd_generate(args: argparse.Namespace, progress: ProgressReporter) -> int:
progress.error(f"failed to stage BIOS: {exc}", code=EXIT_ERROR)
return EXIT_ERROR
try:
progress.phase("bios", pct=0.2, message="Generating SCPH1001 BIOS C…")
progress.phase("bios", pct=0.2, message="Generating SCPH1001 BIOS C...")
regen_bios_profile(project_root, "bios/SCPH1001.toml", progress=progress)
staged_retail = True
except Exception as exc: # noqa: BLE001
@@ -661,7 +661,7 @@ def cmd_generate(args: argparse.Namespace, progress: ProgressReporter) -> int:
):
try:
progress.phase(
"bios", pct=0.25, message="Generating OpenBIOS backend C…"
"bios", pct=0.25, message="Generating OpenBIOS backend C..."
)
regen_bios_profile(project_root, "bios/OpenBIOS.toml", progress=progress)
except Exception as exc: # noqa: BLE001
@@ -682,7 +682,7 @@ def cmd_generate(args: argparse.Namespace, progress: ProgressReporter) -> int:
progress.phase(
"emit",
pct=0.35,
message=f"Running psxrecomp-game → {out_dir}",
message=f"Running psxrecomp-game -> {out_dir}",
)
cmd = [str(game_tool), "--config", str(config)]
proc = subprocess.run(
@@ -1060,7 +1060,7 @@ def cmd_rebuild(args: argparse.Namespace, progress: ProgressReporter) -> int:
try:
if not pgo_enabled:
progress.phase("build", pct=0.2, message="cmake Release build…")
progress.phase("build", pct=0.2, message="cmake Release build...")
_cmake_configure(
project_root, build_dir, pgo="", extra=cmake_extra, progress=progress
)
@@ -1076,7 +1076,7 @@ def cmd_rebuild(args: argparse.Namespace, progress: ProgressReporter) -> int:
progress.phase(
"pgo_instrument",
pct=0.1,
message="PGO instrumented build…",
message="PGO instrumented build...",
)
_cmake_configure(
project_root,
@@ -1103,7 +1103,7 @@ def cmd_rebuild(args: argparse.Namespace, progress: ProgressReporter) -> int:
hide_video=hide_video,
progress=progress,
)
progress.phase("pgo_use", pct=0.85, message="PGO optimized rebuild…")
progress.phase("pgo_use", pct=0.85, message="PGO optimized rebuild...")
_cmake_configure(
project_root,
build_dir,
@@ -1126,7 +1126,7 @@ def cmd_rebuild(args: argparse.Namespace, progress: ProgressReporter) -> int:
prune_raw = (getattr(args, "prune_after", None) or "").strip()
if prune_raw:
modes = {m.strip() for m in prune_raw.split(",") if m.strip()}
progress.phase("prune", pct=0.97, message="Pruning toolchain / build bulk…")
progress.phase("prune", pct=0.97, message="Pruning toolchain / build bulk...")
prune_after_rebuild(project_root, build_dir, modes, progress)
progress.phase("done", pct=1.0, message="Rebuild complete")
@@ -1314,7 +1314,19 @@ def build_parser() -> argparse.ArgumentParser:
return ap
def _configure_stdio() -> None:
"""Best-effort: don't crash on Windows cp1252 when logging Unicode."""
for stream in (sys.stdout, sys.stderr):
reconf = getattr(stream, "reconfigure", None)
if callable(reconf):
try:
reconf(errors="replace")
except Exception: # noqa: BLE001
pass
def main() -> int:
_configure_stdio()
args = build_parser().parse_args()
progress = ProgressReporter(json_progress=bool(getattr(args, "json_progress", False)))
try:
+57 -1
View File
@@ -488,6 +488,60 @@ if(NOT PSXRECOMP_SKIP_BIOS_STALE_CHECK AND _psxrt_bios_linked)
endif()
endif()
# zlib for boot_state v4. System packages first; otherwise FetchContent a pinned
# release so portable Windows cmake-clang-v1 setups can configure without MSYS2.
option(PSX_ZLIB_FETCH
"Fetch zlib when no system ZLIB package is found"
ON)
function(psxrecomp_ensure_zlib)
if(TARGET ZLIB::ZLIB)
return()
endif()
find_package(ZLIB QUIET)
if(TARGET ZLIB::ZLIB)
return()
endif()
if(NOT PSX_ZLIB_FETCH)
message(FATAL_ERROR
"ZLIB was not found. On Windows, use a cmake-clang-v1 pack that "
"ships include/zlib.h + lib/libz.a (sets ZLIB_ROOT), or install "
"zlib-devel / mingw-w64-zlib, or configure with -DPSX_ZLIB_FETCH=ON.")
endif()
message(STATUS
"psxrecomp: ZLIB not in CMAKE_PREFIX_PATH/ZLIB_ROOT; "
"fetching zlib 1.3.1 (prefer a toolchain pack that bundles it)")
include(FetchContent)
set(_psx_zlib_timestamp_args "")
if(CMAKE_VERSION VERSION_GREATER_EQUAL 3.24)
list(APPEND _psx_zlib_timestamp_args DOWNLOAD_EXTRACT_TIMESTAMP TRUE)
endif()
FetchContent_Declare(psx_zlib
URL
"https://github.com/madler/zlib/releases/download/v1.3.1/zlib-1.3.1.tar.gz"
URL_HASH
"SHA256=9a93b2b7dfdac77ceba5a558a580e74667dd6fede4585b91eefb60f03b72df23"
${_psx_zlib_timestamp_args})
FetchContent_MakeAvailable(psx_zlib)
if(TARGET ZLIB::ZLIB)
message(STATUS "psxrecomp: ZLIB via FetchContent (ZLIB::ZLIB)")
return()
endif()
# madler/zlib builds zlibstatic even when a shared zlib target exists.
if(TARGET zlibstatic)
add_library(ZLIB::ZLIB ALIAS zlibstatic)
message(STATUS "psxrecomp: ZLIB via FetchContent (zlibstatic)")
return()
endif()
if(TARGET zlib)
add_library(ZLIB::ZLIB ALIAS zlib)
message(STATUS "psxrecomp: ZLIB via FetchContent (zlib)")
return()
endif()
message(FATAL_ERROR
"Fetched zlib but no linkable target was produced "
"(expected zlibstatic or zlib).")
endfunction()
function(psxrecomp_add_runtime_target target)
set(options ORACLE COSIM)
set(oneValueArgs
@@ -732,7 +786,9 @@ function(psxrecomp_add_runtime_target target)
endif()
# zlib: boot_state v4 savestate compression (RAM/VRAM/SPU blobs).
find_package(ZLIB REQUIRED)
# Portable Windows toolchains (cmake-clang-v1) have no system zlib —
# fetch a pinned release when find_package fails (same pattern as SDL3).
psxrecomp_ensure_zlib()
target_link_libraries(${target} PRIVATE ZLIB::ZLIB)
# Build identity: stamp the psxrecomp commit into the binary so a crash report
+19 -7
View File
@@ -33,6 +33,17 @@ USER_OFF = 24
SYNC = bytes([0x00] + [0xFF] * 10 + [0x00])
def _configure_stdio() -> None:
"""Avoid UnicodeEncodeError on Windows consoles (cp1252 / Store Python)."""
for stream in (sys.stdout, sys.stderr):
reconf = getattr(stream, "reconfigure", None)
if callable(reconf):
try:
reconf(errors="replace")
except Exception: # noqa: BLE001 — best-effort stdio harden
pass
def _build_edc_table() -> list[int]:
table = []
for i in range(256):
@@ -388,7 +399,7 @@ def raw2448_to_bin(src: Path) -> bytes:
raise SystemExit(f"truncated 2448 sector {n}: got {len(sec)} bytes")
out += sec[:DST_SEC]
n += 1
print(f" trimmed {n} sectors 2448 → 2352")
print(f" trimmed {n} sectors 2448 -> 2352")
return bytes(out)
@@ -408,8 +419,9 @@ def matches_known(cfg: PrepareConfig, size: int, md5: str, sha1: str) -> bool:
def main() -> int:
_configure_stdio()
here = Path(__file__).resolve().parent
# tools/ → psxrecomp/ → often game root is parent of psxrecomp
# tools/ -> psxrecomp/ -> often game root is parent of psxrecomp
fw_root = here.parent
ap = argparse.ArgumentParser(description=__doc__)
ap.add_argument("source", nargs="?", default="", help="path to .iso / .cue / .bin")
@@ -489,7 +501,7 @@ def main() -> int:
if kind == "cue":
src = resolve_cue_bin(src)
src_md5, src_sha1, src_size = file_hashes(src)
print(f"cue → bin: {src}")
print(f"cue -> bin: {src}")
print(f" size {src_size}")
print(f" md5 {src_md5}")
print(f" sha1 {src_sha1}")
@@ -512,7 +524,7 @@ def main() -> int:
"verifying boot EXE only."
)
elif not cfg.known and not cfg.skip_hash_check and kind == "bin2352":
print(" no prepare_disc.known_* configured — verifying boot EXE only")
print(" no prepare_disc.known_* configured - verifying boot EXE only")
if kind == "bin2352":
bin_data = src.read_bytes()
@@ -520,11 +532,11 @@ def main() -> int:
elif kind == "iso":
iso_data = src.read_bytes()
entries, files = extract_via(read_user_iso, iso_data, cfg.boot_exe)
print(f" converting {len(iso_data) // USER} sectors ISO → MODE2/2352…")
print(f" converting {len(iso_data) // USER} sectors ISO -> MODE2/2352...")
bin_data = iso_to_bin(iso_data)
extract_via(read_user_bin, bin_data, cfg.boot_exe)
elif kind == "raw2448":
print(" converting 2448 → 2352…")
print(" converting 2448 -> 2352...")
bin_data = raw2448_to_bin(src)
entries, files = extract_via(read_user_bin, bin_data, cfg.boot_exe)
else:
@@ -563,7 +575,7 @@ def main() -> int:
print(f" md5 {out_md5}")
print(f" sha1 {out_sha1}")
if kind == "iso":
print(" rebuilt from ISO (EDC set; ECC zeroed — fine for software readers)")
print(" rebuilt from ISO (EDC set; ECC zeroed - fine for software readers)")
elif kind == "raw2448":
print(" trimmed from 2448-byte/sector dump")
+10 -1
View File
@@ -231,10 +231,19 @@ def resolve_toolchain_bin(project_root: Optional[Path] = None) -> Optional[Path]
def activate_toolchain_bin(bin_dir: Path, log=None) -> None:
prefix = str(bin_dir)
pack_root = bin_dir.parent
cur = os.environ.get("PATH", "")
parts = cur.split(os.pathsep) if cur else []
if not parts or Path(parts[0]) != bin_dir:
os.environ["PATH"] = prefix + (os.pathsep + cur if cur else "")
# Windows cmake-clang-v1 ships zlib under the pack root; help FindZLIB.
pack_s = str(pack_root)
os.environ["ZLIB_ROOT"] = pack_s
prev_prefix = os.environ.get("CMAKE_PREFIX_PATH", "")
if not prev_prefix:
os.environ["CMAKE_PREFIX_PATH"] = pack_s
elif pack_s not in prev_prefix.split(os.pathsep):
os.environ["CMAKE_PREFIX_PATH"] = pack_s + os.pathsep + prev_prefix
for name, env_key in (
("clang", "CC"),
("clang++", "CXX"),
@@ -306,7 +315,7 @@ def download_latest_pack(
token = os.environ.get("GH_TOKEN") or os.environ.get("GITHUB_TOKEN") or ""
url = f"https://github.com/{repo}/releases/latest/download/{asset}"
if log:
log(f"Downloading {asset} from {repo}…")
log(f"Downloading {asset} from {repo}...")
with tempfile.TemporaryDirectory(prefix="psxrecomp-tc-") as tmp:
zpath = Path(tmp) / asset
try: