mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Make every packaging script refuse a translator not built from the checkout's sources, early.
build_xlate.py --id-only wrote an nx2navi_xlate.id for whatever exe sat in the folder, from the sources as they are, so make_launcher's guard (check_xlate, which compares only the .id) passed an old exe beside a fresh .id. Nothing calls the option; it is gone, and only a build writes an .id. make_release.check_translator compared build/xlate's .id with build_xlate.identity(), which hashes the tree the last build prepared there, so a patch or vendor change since that build passed unseen; make_appimage.py and make_kit.py checked nothing. The fresh-prepare identity moves from make_launcher into build_xlate as source_identity(), and build_xlate.check_built(folder, exe) refuses a missing exe or .id and an .id that differs from it. make_launcher, make_release, make_appimage and make_kit stop on its reason, each before its downloads, builds or deletions: make_launcher's check moves from build_app to the top of main, before the --out folder is deleted and the toolchain lock is resolved. A translator folder built from the current sources, as the release scripts pass it (work\xlate_6866a13e), passes as before. Not reproduced before the change beyond the audit's probes. tests/xlate_package_check.py (new) checks a matching folder, missing files, another identity and a stale build (refused although identity() over its own tree equals its .id), that --id-only is refused, and that make_launcher, make_release and make_kit stop on a foreign translator, the kit before any download; check_built passes on work\xlate_6866a13e. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -7,10 +7,11 @@ NativeAOT links with the system's clang (no MSVC); NativeAOT builds for the OS i
|
||||
|
||||
Next to the exe it writes nx2navi_xlate.id: the translator identity, a sha256 over everything the build reads (this script,
|
||||
Program.cs, the csproj, the patches, the vendor tree). runtime/gfx_shader.c puts it into every shader cache key, so a
|
||||
translator change re-keys the cache without a hand-made KEY_VERSION bump. --id-only writes it for the exe already built
|
||||
(the caller vouches that the exe matches the sources).
|
||||
translator change re-keys the cache without a hand-made KEY_VERSION bump. Only a build writes it: the packaging scripts
|
||||
(make_launcher.py, make_release.py, make_appimage.py, make_kit.py) take a translator whose .id names this checkout's
|
||||
sources for one built from them (check_built), so no option writes an .id beside an exe it did not build.
|
||||
|
||||
python tools/build_xlate.py [--id-only] [--out DIR]
|
||||
python tools/build_xlate.py [--out DIR]
|
||||
|
||||
--out builds into DIR instead of build/xlate (a task build dir: nx2navi.exe takes the translator next to it).
|
||||
"""
|
||||
@@ -202,9 +203,43 @@ def write_identity(exe: Path) -> None:
|
||||
print(f"translator identity {ident[:16]} -> {exe.with_suffix('.id')}")
|
||||
|
||||
|
||||
def source_identity() -> str:
|
||||
"""The identity a translator built from this checkout's sources gets: the vendor tree copied and patched in a
|
||||
temporary folder (prepare_sources) and hashed as the build hashes it (identity). identity() over a build folder
|
||||
hashes the tree its last build prepared, so a patch or vendor change made since then would not show. Nothing is
|
||||
compiled; it takes a few seconds and needs git on PATH (prepare_sources applies the patches with it)."""
|
||||
import tempfile
|
||||
global BUILD
|
||||
old = BUILD
|
||||
with tempfile.TemporaryDirectory(prefix="xlate-id-") as d:
|
||||
BUILD = Path(d) / "xlate"
|
||||
try:
|
||||
prepare_sources()
|
||||
return identity()
|
||||
finally:
|
||||
BUILD = old
|
||||
|
||||
|
||||
def check_built(folder: Path, exe: str = EXE) -> str | None:
|
||||
"""None when folder holds the translator exe and an nx2navi_xlate.id naming this checkout's sources
|
||||
(source_identity); otherwise why not. The packaging scripts stop on the reason: 0.10.0 and 0.10.1 shipped the
|
||||
0.9.2 translator (identity 4d051299) after tools/xlate/Program.cs had raised the texture pool to 40960 slots, so
|
||||
their translations still clamped every pool handle to slot 32767 and the ground went see-through after some area
|
||||
loads. exe: the file name on the release's OS (EXE is this machine's)."""
|
||||
folder = Path(folder)
|
||||
for name in (exe, "nx2navi_xlate.id"):
|
||||
if not (folder / name).is_file():
|
||||
return f"{folder / name} is missing: build the shader translator with tools/build_xlate.py --out {folder}"
|
||||
have = (folder / "nx2navi_xlate.id").read_text(encoding="ascii", errors="replace").strip()
|
||||
want = source_identity()
|
||||
if have != want:
|
||||
return (f"{folder}: its translator was built from other sources (identity {have[:16]}) than this checkout's "
|
||||
f"({want[:16]}): build it again with tools/build_xlate.py --out {folder}")
|
||||
return None
|
||||
|
||||
|
||||
def main() -> None:
|
||||
parser = argparse.ArgumentParser(description=__doc__.splitlines()[0])
|
||||
parser.add_argument("--id-only", action="store_true", help="write nx2navi_xlate.id for the exe already built")
|
||||
parser.add_argument("--out", type=Path, help="build directory instead of build/xlate")
|
||||
parser.add_argument("--llvm", type=Path, help="Linux: an LLVM directory whose bin/clang and lld link the exe")
|
||||
parser.add_argument("--sysroot", type=Path, help="Linux: link against this sysroot's glibc instead of the host's "
|
||||
@@ -213,9 +248,6 @@ def main() -> None:
|
||||
if a.out:
|
||||
global BUILD
|
||||
BUILD = a.out.resolve()
|
||||
if a.id_only:
|
||||
write_identity(BUILD / EXE)
|
||||
return
|
||||
started = time.time()
|
||||
dotnet = shutil.which("dotnet")
|
||||
if not dotnet:
|
||||
|
||||
@@ -7,7 +7,7 @@ with --events and reads its progress lines).
|
||||
[--dlss libnvidia-ngx-dlss.so.<version> | --no-dlss]
|
||||
|
||||
The AppImage holds no game files: the kit's tools/, recomp/, runtime/ and docs, the shader translator built by
|
||||
tools/build_xlate.py (bin/nx2navi_xlate), NVIDIA's DLSS library with its notice (bin/, tools/dlss_pin.py: downloaded
|
||||
tools/build_xlate.py from this checkout's sources (bin/nx2navi_xlate; the script stops first on another, check_built), NVIDIA's DLSS library with its notice (bin/, tools/dlss_pin.py: downloaded
|
||||
from NVIDIA's DLSS SDK repository and checked, or --dlss; not with --no-dlss: an AppImage made without the library
|
||||
downloads it after a build on machines with NVIDIA's driver, AppRun's get_dlss), the pinned Vulkan Memory Allocator
|
||||
header, the pinned Vulkan headers (toolchain/vulkan-headers, tools/vulkan_pin.py: the runtime names Vulkan extensions
|
||||
@@ -201,6 +201,10 @@ def main():
|
||||
if not need.exists():
|
||||
sys.exit(f'{need} is missing (tools/build_xlate.py builds the translator; tools/build_game.py fetches VMA)')
|
||||
sys.path.insert(0, str(ROOT / 'tools'))
|
||||
import build_xlate
|
||||
reason = build_xlate.check_built(xlate, 'nx2navi_xlate') # the translator of this checkout's sources, or none
|
||||
if reason:
|
||||
sys.exit(reason)
|
||||
import dlss_pin
|
||||
dlss = None if a.no_dlss else dlss_pin.resolve(a.dlss, ROOT / 'build' / 'dl', linux=True)
|
||||
|
||||
|
||||
@@ -13,7 +13,8 @@ or --dlss; not with --no-dlss), DLSS Frame Generation in bin/dlssg/ with --dlssg
|
||||
tools/build_dlssg.py beside NVIDIA Streamline's runtime, tools/streamline_pin.py: downloaded from NVIDIA's Streamline
|
||||
SDK release and checked, or --streamline), AMD's FSR 3.1 library with --ffx, its two FSR 4 libraries with --ffx4, the
|
||||
button art with --prompt-art, and README-BuildKit.md; no game code, data or anything generated from the game.
|
||||
check_content runs over the folder before it is zipped.
|
||||
check_content runs over the folder before it is zipped. The --xlate folder must hold a translator built from this
|
||||
checkout's sources (tools/build_xlate.py check_built); the script stops first if not.
|
||||
|
||||
--prompt-art names folders that hold XGamepad, P5Gamepad and Keyboard_Mouse, or those three folders themselves: the
|
||||
pictures tools/pad_prompts.py reads go into the kit's prompt-art folder (tools/prompt_art.py art_files), and
|
||||
@@ -73,11 +74,15 @@ def main():
|
||||
a = ap.parse_args()
|
||||
sys.path.insert(0, str(ROOT / 'tools'))
|
||||
import build_shaders
|
||||
import build_xlate
|
||||
import dlss_pin
|
||||
import prompt_art
|
||||
import streamline_pin
|
||||
if a.streamline and not a.dlssg:
|
||||
sys.exit('--streamline goes with --dlssg')
|
||||
reason = build_xlate.check_built(a.xlate, 'nx2navi_xlate.exe') # the translator of this checkout's sources
|
||||
if reason:
|
||||
sys.exit(reason)
|
||||
if a.prompt_art:
|
||||
prompt_art.art_files(a.prompt_art) # the art is all there before anything is downloaded
|
||||
dlss = None if a.no_dlss else dlss_pin.resolve(a.dlss, ROOT / 'build' / 'dl')
|
||||
|
||||
@@ -188,32 +188,17 @@ def build_python(py):
|
||||
|
||||
# ---------------------------------------------------------------- app/<version>/
|
||||
|
||||
def xlate_source_identity():
|
||||
"""The identity tools/build_xlate.py writes for a translator built from this checkout: the vendor tree copied and
|
||||
patched in a folder of its own (build_xlate.prepare_sources) and hashed as the build hashes it (build_xlate.identity).
|
||||
Nothing is compiled; it takes a few seconds."""
|
||||
import tempfile
|
||||
import build_xlate
|
||||
old = build_xlate.BUILD
|
||||
with tempfile.TemporaryDirectory(prefix='xlate-id-') as d:
|
||||
build_xlate.BUILD = Path(d) / 'xlate'
|
||||
try:
|
||||
build_xlate.prepare_sources()
|
||||
return build_xlate.identity()
|
||||
finally:
|
||||
build_xlate.BUILD = old
|
||||
|
||||
|
||||
def check_xlate(xlate):
|
||||
"""A release carries the translator of its own sources. 0.10.0 and 0.10.1 shipped the 0.9.2 translator (identity
|
||||
4d051299) after tools/xlate/Program.cs had raised the texture pool to 40960 slots, so their translations still
|
||||
clamped every pool handle to slot 32767 and the ground went see-through after some area loads (issues #569 and
|
||||
#824). A translator whose nx2navi_xlate.id differs from this checkout's sources stops the build."""
|
||||
#824). A missing translator, or one whose nx2navi_xlate.id differs from this checkout's sources
|
||||
(build_xlate.check_built), stops the build; main runs this before anything is resolved, downloaded or deleted."""
|
||||
import build_xlate
|
||||
reason = build_xlate.check_built(xlate, 'nx2navi_xlate.exe')
|
||||
if reason:
|
||||
sys.exit(reason)
|
||||
have = (xlate / 'nx2navi_xlate.id').read_text(encoding='ascii').strip()
|
||||
want = xlate_source_identity()
|
||||
if have != want:
|
||||
sys.exit(f'{xlate}: its translator was built from other sources (identity {have[:16]}) than this checkout\'s '
|
||||
f'({want[:16]}): build it again with tools/build_xlate.py --out {xlate}')
|
||||
print(f'translator identity {have[:16]}: built from this checkout\'s sources')
|
||||
|
||||
|
||||
@@ -233,11 +218,7 @@ def build_app(app, ver, xlate, feed_repo, lock, ffx=None, dlss=None, art=None, d
|
||||
shutil.copy2(ROOT / t, app / t)
|
||||
(app / 'VERSION').write_text(ver + '\n', encoding='utf-8')
|
||||
(app / 'bin').mkdir()
|
||||
for n in ('nx2navi_xlate.exe', 'nx2navi_xlate.id'):
|
||||
if not (xlate / n).is_file():
|
||||
sys.exit(f'{xlate / n} is missing: build the shader translator first (tools/build_xlate.py)')
|
||||
check_xlate(xlate)
|
||||
for n in ('nx2navi_xlate.exe', 'nx2navi_xlate.id'):
|
||||
for n in ('nx2navi_xlate.exe', 'nx2navi_xlate.id'): # main checked them first (check_xlate)
|
||||
shutil.copy2(xlate / n, app / 'bin' / n)
|
||||
if ffx: # FSR 3.1 loads it from beside the game (runtime/vk_ffx.cpp); make_game.py copies it there
|
||||
shutil.copy2(ffx, app / 'bin' / 'amd_fidelityfx_vk.dll')
|
||||
@@ -415,6 +396,7 @@ def main():
|
||||
prompt_art.art_files(a.prompt_art) # the art is all there before anything is downloaded or built
|
||||
if a.pgo:
|
||||
pgo.fitting(a.pgo) # the profile fits this checkout's recomp/ before anything is downloaded or built
|
||||
check_xlate(a.xlate) # the translator is this checkout's before anything is downloaded, built or deleted
|
||||
out = a.out
|
||||
shutil.rmtree(out, ignore_errors=True)
|
||||
folder = out / 'NX2navi'
|
||||
|
||||
@@ -306,12 +306,12 @@ def build_llvm(out):
|
||||
def check_translator():
|
||||
"""Stop on a translator older than the sources. build/xlate is built by hand and only copied here (the Linux release
|
||||
builds its own), so without a rebuild a translator change reaches no Windows release, and nothing fails: the runtime
|
||||
sends job fields the old exe ignores, as happened to gather_bias."""
|
||||
idf = MAIN_ROOT / 'build' / 'xlate' / 'nx2navi_xlate.id'
|
||||
have = idf.read_text(encoding='ascii').strip() if idf.is_file() else 'none'
|
||||
want = build_xlate.identity()
|
||||
if have != want:
|
||||
sys.exit(f'build/xlate has translator {have[:16]}, the sources are {want[:16]}: run tools/build_xlate.py')
|
||||
sends job fields the old exe ignores, as happened to gather_bias. The identity it must have is that of this
|
||||
checkout's sources prepared afresh (build_xlate.check_built), not build_xlate.identity() over build/xlate, which
|
||||
hashes the tree its last build prepared and so matches a translator built before a patch changed."""
|
||||
reason = build_xlate.check_built(MAIN_ROOT / 'build' / 'xlate', 'nx2navi_xlate.exe')
|
||||
if reason:
|
||||
sys.exit(reason)
|
||||
|
||||
|
||||
def build_bin(out):
|
||||
|
||||
Reference in New Issue
Block a user