The cart-base map at 0x10000000 (so absolute ROM-asset symbols are live host pointers) was Windows-only; the #else branch was a stub that logged "not implemented" and fell to the degraded heap-copy path. - Factor the post-map work (memcpy + pcmodels/pccg sidecar load + D55 RLE header fixup) into romdataFinishCartMap(), shared by both paths. - POSIX #else: anonymous mmap at CART_BASE with MAP_FIXED_NOREPLACE where available; on any failure munmap + fall through to the identical heap copy. - romdataDestroy() munmaps on POSIX (length tracked in mappedLen). Verified on Windows: builds 242/242, -level_09 boots crash-free (identical behaviour with/without the refactor). Linux compile + runtime verification owed — see docs/dev/LINUX-PORT.md. No behaviour change on Windows.
5.1 KiB
Linux port — status & gap analysis
Session M-38 (2026-09-02). Goal-2 on the roadmap (after the Windows alpha / release artifact). This is a scoping + first-patch pass; nothing here has run on a Linux machine yet.
Method
Read build-pc.sh, CMakeLists.txt, docs/building.md, and grepped
port/src, port/fast3d, port/include for Windows-only headers / Win32 APIs
/ unguarded _WIN32 branches. A local Qwen triage pass seeded the hunt; every
claim below was re-checked against the real files (the 27B was wrong on two of
three headline items — see "Ruled out").
What is already Linux-ready (verified by reading)
port/include/platform.h— setsPLATFORM_LINUX/PLATFORM_MACOS/PLATFORM_WINDOWScleanly.CMakeLists.txt—find_package(SDL2 REQUIRED),find_package(ZLIB REQUIRED), andelse()branches already present for the non-Windows case:GL_LIBRARY = GL(l.291),EXTRA_LIBRARIES = stdc++ m dl pthread(l.304),elseif(UNIX)platform block (l.86).WIN32_EXECUTABLEand the MinGW zlib fallback are correctlyif(WIN32)/if(MINGW)guarded.build-pc.sh— already documents the Linux apt deps (cmake libsdl2-dev zlib1g-dev libgl1-mesa-dev) and is a plain bash script, no MSYS-isms in the executable body.port/src/system.c—sysSleep()has ananosleep()#elsebranch (l.76-82);<windows.h>isPLATFORM_WINDOWS-guarded.port/src/libultra.c— the OS-thread kernel has a real pthreads branch next to the Win32_beginthreadexone.port/src/crash.c—MessageBoxW/SetThreadPriority/__debugbreakall_WIN32-guarded, withPLATFORM_LINUXcounterparts.port/src/video.c—GE_MKDIRhas both_mkdirandmkdir(p,0777).- No
__declspec,#pragma comment, or hardcoded\-path / drive-letter usage anywhere inport/.
Ruled out (Qwen triage false positives)
— it does (system.c:75Sleep()has no POSIX branchnanosleep).CMake needs— already there.else()branches for zlib/pthread on Linux
The one real code gap — FIXED this session (verification owed)
port/src/romdata.c — the fixed-address cart map (0x10000000, so absolute
ROM-asset symbols are live host pointers) had a Windows-only implementation
(VirtualAlloc); the #else branch was a stub that logged "not implemented on
this platform" and fell straight to the heap-copy fallback. In heap-copy mode
anything that dereferences a cart address directly (not via
romdataGetRom() / the PI shims) reads wrong memory — so Linux would run, if at
all, in the same degraded mode Windows only hits when VirtualAlloc loses the
address race.
Change (M-38):
- Factored the post-map work (memcpy +
pcmodelsLoadSidecars+pccgLoadSidecars+ D55 RLE-header fixup) intoromdataFinishCartMap(), shared by both paths so they cannot drift. - POSIX
#elsenow does an anonymousmmap((void*)CART_BASE, len, PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANONYMOUS|MAP_FIXED_NOREPLACE, -1, 0).MAP_FIXED_NOREPLACE(Linux 4.17+) fails rather than clobbering an existing mapping; where the macro is absent the plain hint is advisory and theat == CART_BASEcheck catches a relocated result. On any failure itmunmaps and falls through to the identical heap-copy path as before. romdataDestroy()munmaps on POSIX (tracked length inmappedLen).
Owed verification (needs a Linux box):
- Compiles under GCC on Linux (
<sys/mman.h>resolves; no decomp-include-path shadowing surprise). mmapactually lands at0x10000000on a stock ASLR Linux —0x10000000(256 MB) is low but usually free; if the kernel routinely refuses it, consider linking the binary no-PIE or reserving the range via a linker script so the loader keeps it clear.-level_09boots crash-free with the mapped path taken (check the log says "mapped at 0x10000000 (cart base)", not "using heap copy").- Whether the heap-copy fallback is actually survivable on Linux if step 2
fails — audit for direct
0x1xxxxxxxderefs outside the PI shims.
Remaining Linux work after the romdata patch lands
| # | Item | Size | Note |
|---|---|---|---|
| 1 | Run the Ubuntu validate CI job → upgrade it to a real compile job |
S | .github/workflows/ci.yml already configures on Ubuntu; flipping it to cmake --build surfaces the real GCC-strictness gaps cheaply |
| 2 | First actual Linux runtime bring-up (-level_09) |
M | expect a short tail of unguarded calls / struct-layout asserts GCC-on-Linux vs MinGW |
| 3 | docs/building.md — promote Linux from "untested" to "supported" once 1+2 pass |
S | |
| 4 | SDL2 / GL context creation on X11 + Wayland | M | fast3d is GL 3.3 core; PD port runs on Linux so the path is known-good |
| 5 | Package: an AppImage or tarball equivalent of bundle-win.sh |
M | reuse prepare-assets.py verbatim — it is already OS-agnostic |
Recommended next step
Land the romdata patch behind CI (item 1) — turn the Ubuntu validate job into
a compile job in the same PR so the "does it build on Linux" question is
answered by the bots, then do the runtime bring-up on a real machine.