mirror of
https://github.com/valentderah/totk-pc-recomp.git
synced 2026-11-11 01:41:02 +00:00
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
127 lines
6.6 KiB
Python
127 lines
6.6 KiB
Python
#!/usr/bin/env python3
|
|
"""Fails when runtime code outside runtime/platform/ uses the Win32 API directly.
|
|
|
|
New runtime code goes through runtime/platform/platform.h. Files that still use Win32 are listed in ALLOWED with the
|
|
reason; the list shrinks as the platform layer takes over.
|
|
A file in ALLOWED that no longer matches is noted, so the entry gets removed.
|
|
|
|
Usage: python tools/check_platform.py [--root DIR] (DIR holds runtime/; default: the repository root)
|
|
"""
|
|
import argparse
|
|
import re
|
|
import sys
|
|
from pathlib import Path
|
|
|
|
# Per-file allowlist. "window", "input", "audio" and "probe" are permanent (OS-specific by nature); the rest wait for
|
|
# 2.7a (memory, faults, page tracking) or 2.7b (threads, time, locks, FP state).
|
|
ALLOWED = {
|
|
"gfx_window.c": "window",
|
|
"gfx_window_probe.c": "probe",
|
|
"input_win.c": "input",
|
|
"prof_win.c": "profiler",
|
|
"rdoc_win.c": "RenderDoc loader",
|
|
"audren.c": "audio",
|
|
"kernel_probe.c": "probe",
|
|
"nvn_probe.c": "probe",
|
|
"ov_probe.c": "probe",
|
|
"tex_probe.c": "probe",
|
|
"vk_exec_probe.c": "probe",
|
|
"gfx_shader_probe.c": "probe",
|
|
"gfx_shader.c": "2.7b: threads, SRW locks, interlocked counters, tick count",
|
|
"memory.c": "2.7a",
|
|
"kernel.c": "2.7a/b",
|
|
"main.c": "2.7a/b",
|
|
"dispatch.c": "2.7b",
|
|
"loader.c": "2.7a",
|
|
"svc.c": "2.7b",
|
|
"vk_memory.c": "2.7a",
|
|
"vk_texture.c": "2.7b",
|
|
"audren.h": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"boot.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"flight.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"fs_host.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"ipc.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"nvn_api_cmd.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"nvn_api_core.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"nvn_api_obj.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"nvn_procs.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"ov_gfx.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"ov_input.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"ov_media.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"ov_system.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"romfs.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"tex_astc_mt.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"vk_backend.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"vk_device.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"vk_dump.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"vk_pipeline.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
"vk_sync.c": "pending: SRW locks, threads, files; not in 2.7a/b/c scope yet",
|
|
}
|
|
|
|
INCLUDE = re.compile(r'^\s*#\s*include\s*[<"](windows|winsock2|ws2tcpip|synchapi|memoryapi|processthreadsapi|'
|
|
r'fileapi|handleapi|libloaderapi|winbase|winnt)\.h[>"]', re.M)
|
|
CALLS = [
|
|
"CreateFile[AW]?", "ReadFile", "WriteFile", "CloseHandle", "DeleteFile[AW]?", "MoveFileEx[AW]?", "CreateDirectory[AW]?",
|
|
"FindFirstFile[AW]?", "GetFileAttributes[AW]?", "GetFileSizeEx", "SetFilePointerEx", "SetEndOfFile",
|
|
"CreatePipe", "CreateProcess[AW]?", "TerminateProcess", "GetModuleFileName[AW]?", "GetEnvironmentVariable[AW]?",
|
|
"VirtualAlloc(Ex)?", "VirtualFree", "VirtualProtect", "VirtualQuery", "MapViewOfFile[A-Za-z0-9]*", "CreateFileMapping[AW]?",
|
|
"GetWriteWatch", "ResetWriteWatch", "AddVectoredExceptionHandler", "RemoveVectoredExceptionHandler",
|
|
"CreateThread", "_beginthread(ex)?", "GetCurrentThread(Id)?", "SetThreadAffinityMask", "SetThreadDescription",
|
|
"SetThreadPriority", "WaitForSingleObject(Ex)?", "WaitForMultipleObjects", "CreateEvent[AW]?", "CreateSemaphore[AW]?",
|
|
"CreateMutex[AW]?", "CreateWaitableTimer(Ex)?[AW]?", "SetWaitableTimer(Ex)?", "Sleep(Ex)?", "SwitchToThread",
|
|
"QueryPerformanceCounter", "QueryPerformanceFrequency", "GetTickCount(64)?", "GetSystemTimePreciseAsFileTime",
|
|
"GetSystemInfo", "GetLogicalProcessorInformation(Ex)?", "SRWLOCK", "CONDITION_VARIABLE", "CRITICAL_SECTION",
|
|
"InitializeCriticalSection[A-Za-z]*", "EnterCriticalSection", "LeaveCriticalSection",
|
|
"(Acquire|Release)SRWLock(Exclusive|Shared)", "WakeAllConditionVariable", "WakeConditionVariable",
|
|
"SleepConditionVariableSRW", "InitOnceExecuteOnce", "INIT_ONCE", "Interlocked[A-Za-z0-9]*", "TlsAlloc", "FlsAlloc",
|
|
"LoadLibrary[AW]?", "GetProcAddress", "FreeLibrary", "HANDLE", "DWORD", "LPVOID", "WINAPI",
|
|
]
|
|
CALL_RE = re.compile(r"\b(" + "|".join(CALLS) + r")\b")
|
|
|
|
|
|
def strip(text):
|
|
"""Blank comments and string literals, keeping line numbers."""
|
|
def blank(m):
|
|
return re.sub(r"[^\n]", " ", m.group(0))
|
|
text = re.sub(r"/\*.*?\*/", blank, text, flags=re.S)
|
|
text = re.sub(r"//[^\n]*", blank, text)
|
|
return re.sub(r'"(?:\\.|[^"\\\n])*"', blank, text)
|
|
|
|
|
|
def scan(path):
|
|
raw = path.read_text(encoding="utf-8", errors="replace")
|
|
hits = [("include", m.group(0).strip()) for m in INCLUDE.finditer(raw)]
|
|
code = strip(raw)
|
|
hits += [("call", m.group(1)) for m in CALL_RE.finditer(code)]
|
|
return hits
|
|
|
|
|
|
def main():
|
|
ap = argparse.ArgumentParser()
|
|
ap.add_argument("--root", default=str(Path(__file__).resolve().parent.parent))
|
|
ap.add_argument("--runtime", default=None, help="runtime dir (default ROOT/runtime)")
|
|
a = ap.parse_args()
|
|
rt = Path(a.runtime) if a.runtime else Path(a.root) / "runtime"
|
|
bad, remaining = [], {}
|
|
for p in sorted(list(rt.glob("*.c")) + list(rt.glob("*.h")) + list(rt.glob("*.cpp"))):
|
|
hits = scan(p)
|
|
if p.name in ALLOWED:
|
|
remaining[p.name] = len(hits)
|
|
elif hits:
|
|
bad.append((p.name, hits))
|
|
for name, hits in bad:
|
|
kinds = sorted({h[1] for h in hits})
|
|
print(f"FAIL runtime/{name}: {len(hits)} Win32 uses outside runtime/platform/ ({', '.join(kinds[:8])})")
|
|
stale = [n for n, c in remaining.items() if c == 0]
|
|
for n in stale:
|
|
print(f"note runtime/{n}: allowlisted but no Win32 use left; remove it from ALLOWED")
|
|
print("remaining Win32 uses per allowlisted file:")
|
|
for n, c in sorted(remaining.items(), key=lambda kv: (-kv[1], kv[0])):
|
|
print(f" {c:5d} runtime/{n} ({ALLOWED[n]})")
|
|
print(f"total {sum(remaining.values())} in {sum(1 for c in remaining.values() if c)} files")
|
|
return 1 if bad else 0
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sys.exit(main())
|