mirror of
https://github.com/RetroPortingToolKit/psxrecomp
synced 2026-10-26 18:25:35 -04:00
f55c731c5f
Removes 204 tools/ scripts (203 .py/.sh plus tools/_missing_funcs.json) that
no tracked file references. Verified mechanically, not by eye: for each of the
204 stems, a word-boundary grep across every tracked text file in the repo,
excluding files that are themselves being deleted, returns zero hits. So
nothing kept imports, execs, or documents any of them. Most are the
underscore-prefixed one-shot probes the .gitignore convention already treats
as scratch (tools/_*.py is ignored; these predate that rule and were force-
added), plus a long tail of session-specific dump/decode/poll scripts with
hardcoded local paths and addresses.
Also removed at the root:
* card2.mcd.bak.before_beetle_copy -- a stray backup of a memcard.
* .mcp.json -- local MCP server wiring, not repo configuration.
* SCPH1001.toml -- a root duplicate of bios/SCPH1001.toml, still on the
pre-refactor [[recompiler.bios_vectors]] schema while the bios/ copy has
moved to [recompiler.address_model]. Every reference in the tree already
names bios/SCPH1001.toml, so the root copy was a stale trap: editing it
would have had no effect on any build.
* docs/CYCLE_TIMING_ARCH.md -- superseded by
docs/internal/FAITHFUL_TIMING_PLAN.md, CYCLE_MODEL_BEETLE.md and
PRECISE_IRQ_SLICE.md; nothing linked to it.
Memcard fixtures move out of the repo root into
runtime/tests/fixtures/memcards/ with a README recording what each of the
four images actually contains (directory entries read out of the images, not
guessed). Nothing in the build read them from a fixed path -- the four
hardcoded consumers (tools/check_card.py, inspect_card.py, peek_cards.py,
verify_card_buffer.py) are all in the deletion above.
.gitignore is corrected to match: runtime memcards a session creates stay
ignored (*.mcr anywhere, /*.mcd at the root, which is where the runtime drops
card1.mcd/card2.mcd when no path is configured), while the tracked fixtures
are re-included. The old !dummy.*.mcr negation existed only to keep the two
root oracle cards tracked and is replaced by
!runtime/tests/fixtures/memcards/*. Verified with git check-ignore --no-index
on each moved file, on the pre-existing runtime/tests/test_card_synth.mcd and
runtime/tests/test_dir/card1.mcd fixtures (all not-ignored), and on
hypothetical root card1.mcd / card2.mcd / saves/card1.mcr (all ignored).
beetle_libretro.cpp's warn-only memcard sanity check keeps its behaviour; its
WARNING now names where populated fixtures can be copied from. The cards are
opened relative to the process's working directory because the libretro
GET_SAVE_DIRECTORY environment callback answers "." (same file, line 419), so
the message says to copy them into the CWD rather than implying a repo path.
BIOS profiles SCPH101.toml and SCPH5552.toml move from the root into bios/,
joining OpenBIOS.toml and SCPH1001.toml so that bios/*.toml is the whole set.
Behaviour-preserving: config paths inside a profile resolve against
find_project_root() (config_loader.cpp:821), which walks up from the profile's
directory for .gitignore/.git/CMakeLists.txt -- bios/ has none of those, so it
lands on the same repo root as before, and bios/SCPH1001.toml already relied
on exactly that. tools/build_cli.py's staging map is updated to the new
sources; it already copied them to framework/bios/, so the packaged layout is
unchanged. recompiler/src/main_cli.cpp's bios/-first lookup keeps its root
fallback (harmless, and it is what makes older layouts still resolve).
Fixes a real latent break while in bios/SCPH5552.toml: seeds pointed at
"seeds/phase2_ghidra_seeds_SCPH5552.json", but there is no seeds/ directory at
the repo root -- the file lives at
recompiler/seeds/phase2_ghidra_seeds_SCPH5552.json, which is what SCPH101.toml
already named. Porting these two profiles to the address_model schema is
deliberately NOT done here; it is a separate tracked follow-up.
Test files that no build system knew about:
* tools/test_coverage_vault.py PASSES (8/8). Moved to
recompiler/tests/test_coverage_vault.py and registered as the ctest
coverage_vault, which puts it inside runtime/check_test_registration.cmake's
glob so it can never silently rot again. Its ROOT is adjusted from
parents[1] to parents[2] for the new depth, matching every other python
test in that directory. Re-run from the new location and from an unrelated
CWD: 8/8. The registration guard was run standalone before and after, and
with the add_test() deliberately broken as a negative control -- it does
name recompiler/tests/test_coverage_vault.py as an orphan when
unregistered, so the registration is load-bearing rather than decorative.
* tools/test_compile_overlays_additive.py FAILS, 10 of 14 tests erroring
against an API that has moved on, so it is removed rather than wired up.
It calls four module attributes that no longer exist in
tools/compile_overlays.py -- load_additive_captures,
validated_cached_bundle_ids, cached_bundle_pairs, compile_and_publish_dll
(zero occurrences each) -- and two signatures have changed under it:
parse_overlay_func_ids() no longer takes require_stored_crc, and
load_region_coverage() now takes 2-3 positional arguments where the test
passes 5. Reviving it means rewriting it against the current additive
capture API, which is a change to overlay-cache test coverage and needs its
own commit and its own evidence, not a rename.
Verification: py_compile over all 113 remaining tracked tools/*.py plus
psxrecomp_cli.py passes; bash -n over every remaining tracked tools/*.sh
passes; importing sdk_progress, pad_delivery and cursor_writers from tools/
succeeds.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
146 lines
5.3 KiB
Python
146 lines
5.3 KiB
Python
"""Build and package the PSXRecomp developer command-line tools."""
|
|
|
|
from __future__ import annotations
|
|
|
|
import argparse
|
|
import os
|
|
import pathlib
|
|
import platform
|
|
import shutil
|
|
import subprocess
|
|
import sys
|
|
|
|
|
|
ROOT = pathlib.Path(__file__).resolve().parent.parent
|
|
TOOLS = ("psxrecomp", "psxrecomp-toml", "psxrecomp-game", "psxrecomp-bios")
|
|
|
|
|
|
def run(command: list[str]) -> None:
|
|
print("+", subprocess.list2cmdline(command), flush=True)
|
|
subprocess.run(command, cwd=ROOT, check=True)
|
|
|
|
|
|
def platform_name() -> str:
|
|
systems = {"Windows": "windows", "Linux": "linux", "Darwin": "macos"}
|
|
machines = {
|
|
"amd64": "x86_64",
|
|
"x86_64": "x86_64",
|
|
"arm64": "arm64",
|
|
"aarch64": "arm64",
|
|
}
|
|
raw_system = platform.system()
|
|
if raw_system.startswith(("MSYS", "MINGW", "CYGWIN")):
|
|
raw_system = "Windows"
|
|
system = systems.get(raw_system, raw_system.lower())
|
|
machine = machines.get(platform.machine().lower(), platform.machine().lower())
|
|
return f"{system}-{machine}"
|
|
|
|
|
|
def find_tool(build_dir: pathlib.Path, name: str, config: str) -> pathlib.Path:
|
|
suffix = ".exe" if os.name == "nt" else ""
|
|
filename = name + suffix
|
|
candidates = (build_dir / filename, build_dir / config / filename)
|
|
for candidate in candidates:
|
|
if candidate.is_file():
|
|
return candidate
|
|
checked = ", ".join(str(path) for path in candidates)
|
|
raise FileNotFoundError(f"{filename} was not built; checked {checked}")
|
|
|
|
|
|
def main() -> int:
|
|
parser = argparse.ArgumentParser(
|
|
description="build a redistributable PSXRecomp CLI archive")
|
|
parser.add_argument(
|
|
"configuration", nargs="?", choices=("release", "debug"),
|
|
default="release", help="build configuration (default: release)")
|
|
parser.add_argument(
|
|
"--build-dir", default="recompiler/build-cli",
|
|
help="CMake build directory (default: recompiler/build-cli)")
|
|
parser.add_argument(
|
|
"--dist-dir", default="dist",
|
|
help="package output directory (default: dist)")
|
|
parser.add_argument(
|
|
"--skip-build", action="store_true",
|
|
help="package tools already present in --build-dir")
|
|
args = parser.parse_args()
|
|
|
|
config = "Release" if args.configuration == "release" else "Debug"
|
|
build_dir = (ROOT / args.build_dir).resolve()
|
|
dist_dir = (ROOT / args.dist_dir).resolve()
|
|
|
|
if not args.skip_build:
|
|
if shutil.which("cmake") is None:
|
|
parser.error("CMake is not installed or is not on PATH")
|
|
source_arg = os.path.relpath(ROOT / "recompiler", ROOT)
|
|
build_arg = os.path.relpath(build_dir, ROOT)
|
|
configure = [
|
|
"cmake", "-S", source_arg, "-B", build_arg,
|
|
f"-DCMAKE_BUILD_TYPE={config}",
|
|
"-DPSXRECOMP_STATIC_CLI=ON",
|
|
]
|
|
if not (build_dir / "CMakeCache.txt").exists() and shutil.which("ninja"):
|
|
configure += ["-G", "Ninja"]
|
|
run(configure)
|
|
jobs = str(os.cpu_count() or 2)
|
|
run([
|
|
"cmake", "--build", build_arg, "--config", config,
|
|
"--target", *TOOLS, "--parallel", jobs,
|
|
])
|
|
|
|
package = f"psxrecomp-cli-{platform_name()}"
|
|
stage = dist_dir / package
|
|
archive = dist_dir / f"{package}.zip"
|
|
dist_dir.mkdir(parents=True, exist_ok=True)
|
|
if stage.exists():
|
|
shutil.rmtree(stage)
|
|
if archive.exists():
|
|
archive.unlink()
|
|
stage.mkdir()
|
|
|
|
shutil.copy2(find_tool(build_dir, "psxrecomp", config), stage)
|
|
libexec = stage / "libexec"
|
|
libexec.mkdir()
|
|
for name in TOOLS[1:]:
|
|
shutil.copy2(find_tool(build_dir, name, config), libexec)
|
|
share = stage / "share"
|
|
share.mkdir()
|
|
shutil.copy2(
|
|
ROOT / "recompiler" / "seeds" / "phase2_ghidra_seeds.json", share)
|
|
|
|
framework = stage / "framework"
|
|
source_ignore = shutil.ignore_patterns(
|
|
"build", "build-*", "tests", "__pycache__", "*.pyc", "*.pyo",
|
|
"*.exe", "*.obj", "*.pdb", "*.lib")
|
|
shutil.copytree(ROOT / "runtime", framework / "runtime", ignore=source_ignore)
|
|
shutil.copytree(ROOT / "recompiler", framework / "recompiler", ignore=source_ignore)
|
|
bios_profiles = {
|
|
"OpenBIOS.toml": ROOT / "bios" / "OpenBIOS.toml",
|
|
"SCPH1001.toml": ROOT / "bios" / "SCPH1001.toml",
|
|
"SCPH101.toml": ROOT / "bios" / "SCPH101.toml",
|
|
"SCPH5552.toml": ROOT / "bios" / "SCPH5552.toml",
|
|
}
|
|
(framework / "bios").mkdir()
|
|
for filename, source in bios_profiles.items():
|
|
shutil.copy2(source, framework / "bios" / filename)
|
|
shutil.copy2(ROOT / "bios" / "openbios.bin", framework / "bios")
|
|
shutil.copy2(ROOT / "bios" / "OpenBIOS.LICENSE", framework / "bios")
|
|
shutil.copy2(ROOT / ".gitignore", framework)
|
|
shutil.copy2(ROOT / "LICENSE", framework)
|
|
shutil.copy2(ROOT / "THIRD_PARTY_ATTRIBUTION.md", framework)
|
|
shutil.copy2(ROOT / "README.md", stage)
|
|
shutil.copy2(ROOT / "LICENSE", stage)
|
|
shutil.copy2(ROOT / "THIRD_PARTY_ATTRIBUTION.md", stage)
|
|
|
|
shutil.make_archive(str(archive.with_suffix("")), "zip", dist_dir, package)
|
|
print(f"PSXRecomp CLI package: {archive}")
|
|
return 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
try:
|
|
raise SystemExit(main())
|
|
except subprocess.CalledProcessError as exc:
|
|
print(f"build_cli: command failed with exit code {exc.returncode}",
|
|
file=sys.stderr)
|
|
raise SystemExit(exc.returncode)
|