From da093d4374bcdd7254c3b77a49abfe465c4ceff4 Mon Sep 17 00:00:00 2001 From: Matthew Stanley <1379tech@gmail.com> Date: Mon, 27 Jul 2026 12:32:30 -0700 Subject: [PATCH] fix(build): link a BIOS backend only when its generated C provides one PSXRECOMP_BIOS_STEMS defaults to "OpenBIOS;SCPH1001", so every game link required a SCPH1001 backend. That backend is compiled from generated C which is a derivative of a copyrighted Sony BIOS, so it is gitignored and only exists after a developer regenerates it from their own dump. A checkout that has only the bundled MIT OpenBIOS -- the documented default, and what a fresh clone gets -- configured fine and then failed at link with: undefined reference to `SCPH1001_psx_bios_backend' Hit while building Tomba 1, Tomba 2 and MMX6 to validate an unrelated branch; all three needed -DPSXRECOMP_BIOS_STEMS=OpenBIOS as a workaround. Filter the stem list to those that actually supply a backend, rather than flipping the default. Flipping it would silently drop SCPH1001 for developers who HAVE regenerated it; filtering keeps it fully supported when present and simply absent when not. Presence of the files is not a sufficient test. A generated/ tree produced before the backend-descriptor mechanism existed has both _full.c and _dispatch.c yet defines no descriptor -- exactly the local state that produced the error above. The check therefore probes for the descriptor symbol itself, in _dispatch.c (~1MB, where the emitter puts it) rather than the multi-megabyte _full.c, so configure stays fast. Also report what happened instead of leaving it implicit: - STATUS line naming the linked backends - STATUS line naming skipped stems with the regen command to fix them - FATAL_ERROR, with the OpenBIOS regen command, if no backend resolves at all (previously an empty registry would have surfaced as a confusing link error) Verified: with default flags and a stale local SCPH1001 tree, Tomba 2 now reports "BIOS backends skipped ... SCPH1001" / "BIOS backends linked: OpenBIOS", links, and boots. Co-Authored-By: Claude Opus 5 (1M context) --- runtime/runtime.cmake | 61 +++++++++++++++++++++++++++++++++++++------ 1 file changed, 53 insertions(+), 8 deletions(-) diff --git a/runtime/runtime.cmake b/runtime/runtime.cmake index e2ec93ac..f9b2ac8e 100644 --- a/runtime/runtime.cmake +++ b/runtime/runtime.cmake @@ -279,21 +279,66 @@ set(PSXRECOMP_BIOS_STEM "${PSXRECOMP_BIOS_STEM_PRIMARY}" CACHE STRING set(PSXRECOMP_BIOS_PROFILE "${PSXRECOMP_ROOT}/bios/${PSXRECOMP_BIOS_STEM}.toml" CACHE FILEPATH "BIOS profile TOML this build regenerates from (staleness stamp input)") +# Link a stem only if its generated sources are actually present. +# +# PSXRECOMP_BIOS_STEMS lists every stem this build WOULD like. SCPH1001 is in +# the default list, but its generated C is a derivative of a copyrighted Sony +# BIOS, so it is gitignored and only exists once a developer regenerates it +# from their own dump. Requiring it unconditionally meant a fresh checkout -- +# which legitimately has only the bundled MIT OpenBIOS -- failed every game +# link with "undefined reference to SCPH1001_psx_bios_backend", long after +# configure had succeeded. Filtering here keeps SCPH1001 fully supported for +# anyone who has regenerated it, without making it mandatory for everyone else. set(PSXRECOMP_BIOS_GENERATED "") set(_psxrt_registry_externs "") set(_psxrt_registry_entries "") +set(_psxrt_bios_linked "") +set(_psxrt_bios_skipped "") foreach(_stem IN LISTS PSXRECOMP_BIOS_STEMS) - list(APPEND PSXRECOMP_BIOS_GENERATED - ${PSXRECOMP_ROOT}/generated/${_stem}_full.c - ${PSXRECOMP_ROOT}/generated/${_stem}_dispatch.c) - string(APPEND _psxrt_registry_externs - "extern const PsxBiosBackend ${_stem}_psx_bios_backend; + # Presence is not enough: a generated/ tree left over from before the + # backend-descriptor mechanism has both files but defines no descriptor, + # which links fine at configure time and then fails at link with an + # undefined reference. Probe the descriptor itself. It is emitted into + # _dispatch.c (~1MB), never the multi-megabyte _full.c, so + # this scan stays cheap. + set(_psxrt_desc "") + if(EXISTS "${PSXRECOMP_ROOT}/generated/${_stem}_dispatch.c") + file(STRINGS "${PSXRECOMP_ROOT}/generated/${_stem}_dispatch.c" _psxrt_desc + REGEX "${_stem}_psx_bios_backend" LIMIT_COUNT 1) + endif() + if(EXISTS "${PSXRECOMP_ROOT}/generated/${_stem}_full.c" AND _psxrt_desc) + list(APPEND PSXRECOMP_BIOS_GENERATED + ${PSXRECOMP_ROOT}/generated/${_stem}_full.c + ${PSXRECOMP_ROOT}/generated/${_stem}_dispatch.c) + string(APPEND _psxrt_registry_externs + "extern const PsxBiosBackend ${_stem}_psx_bios_backend; ") - string(APPEND _psxrt_registry_entries - " &${_stem}_psx_bios_backend, + string(APPEND _psxrt_registry_entries + " &${_stem}_psx_bios_backend, ") + list(APPEND _psxrt_bios_linked "${_stem}") + else() + list(APPEND _psxrt_bios_skipped "${_stem}") + endif() endforeach() -list(LENGTH PSXRECOMP_BIOS_STEMS _psxrt_bios_count) + +if(_psxrt_bios_skipped) + message(STATUS + "BIOS backends skipped (generated C missing or predates the backend " + "descriptor): ${_psxrt_bios_skipped} -- regenerate with " + "tools/regen_bios.sh --config bios/.toml") +endif() +if(NOT _psxrt_bios_linked) + message(FATAL_ERROR + "No recompiled BIOS backend available. Wanted: ${PSXRECOMP_BIOS_STEMS}, " + "but no matching generated/_full.c + _dispatch.c were found " + "under ${PSXRECOMP_ROOT}/generated.\n" + "Generate at least one before building the runtime:\n" + " bash tools/regen_bios.sh --config bios/OpenBIOS.toml\n" + "(OpenBIOS is bundled and MIT-licensed, so this needs no BIOS dump.)") +endif() +message(STATUS "BIOS backends linked: ${_psxrt_bios_linked}") +list(LENGTH _psxrt_bios_linked _psxrt_bios_count) # Registry of the compiled-in backends, in preference order. Generated so the # stem list stays the single source of truth.