mirror of
https://github.com/tangerineturtle1/NX2navi.git
synced 2026-11-15 19:19:58 -04:00
Stop a launcher release and a build kit on an nx2navi_dlssg.dll that lacks an export runtime/dlssg/nx2_sl.h declares, before they download anything.
The review found that nothing on the release path ran the new export check: tools/make_launcher.py build_app and tools/make_kit.py copied whatever --dlssg DLL they were given, and the release script still named the DLL of 0.8.0, which lacks nx2sl_reflex2. Shipped that way, Reflex would never hold the frame limit while players still got this branch's other changes. make_launcher.py check_dlssg and make_kit.py main now run build_dlssg.check on the --dlssg DLL beside the translator's check, before anything is resolved, downloaded or deleted; build_dlssg.check also stops on a missing file and on a file that is no DLL, with a message instead of a traceback. tests/dlssg_exports_check.py adds a DLL with every declared export (it passes), the two-export DLL, a missing file and two files that are no DLL (they stop, naming why), make_launcher.check_dlssg on both DLLs, and that both scripts' main makes the check before streamline_pin.resolve and shutil.rmtree; it fails when the call is taken out of make_launcher.py main. The DLL built from this branch passes make_launcher.check_dlssg; the DLL of 0.8.0 is refused, naming nx2sl_reflex2. docs/launcher.md and docs/building.md "Checks" say so. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -773,8 +773,11 @@ on screen once and to the pacer the second time. No GPU, no game files.
|
||||
|
||||
A change to `runtime/dlssg/nx2_sl.h` or to the export check in `tools/build_dlssg.py` (`declared_exports`,
|
||||
`pe_exports`) passes `python tests\dlssg_exports_check.py`, which builds a small DLL with MSYS2's clang and checks that
|
||||
the export it lacks is the one named, and that every function `nx2_sl.h` declares is read. The DLL itself is checked
|
||||
when `tools/build_dlssg.py` builds it, or with `--check <dll>`. No MSVC, no Streamline SDK, no game files.
|
||||
the export it lacks is the one named; that `build_dlssg.check` stops on that DLL, a missing file and a file that is no
|
||||
DLL, and passes a DLL with every export `nx2_sl.h` declares; that every function `nx2_sl.h` declares is read; and that
|
||||
`tools/make_launcher.py` and `tools/make_kit.py` make that check of their `--dlssg` DLL before they download anything.
|
||||
The DLL itself is checked when `tools/build_dlssg.py` builds it, or with `--check <dll>`. No MSVC, no Streamline SDK,
|
||||
no game files.
|
||||
|
||||
A change to which frames the flight recorder takes for a one-frame flash (`runtime/flight_flash.h`, `runtime/flight.c`
|
||||
`flight_cells`) passes `python tests\flight_flash_check.py`, which builds the header alone, draws pictures of the
|
||||
|
||||
@@ -516,9 +516,11 @@ stays playable and Rebuild the Game, or Begin Installation, goes on from the ste
|
||||
`tools/streamline_pin.py` pins. The script downloads that release once (cached in `toolchain/launcher-dl/`), checks
|
||||
the archive's size and sha256 and each file's sha256, and writes `dlssg-NOTICE.txt` with the two licence texts;
|
||||
`make_game.py` copies the whole set beside the game. `--streamline SDK` takes an SDK folder on disk instead (its
|
||||
files must be the pinned ones). `tools/build_dlssg.py` fails a DLL that lacks an export `runtime/dlssg/nx2_sl.h`
|
||||
declares, and `python tools/build_dlssg.py --check <dll>` makes that check of a DLL built earlier: the runtime
|
||||
takes a missing optional export for an older DLL and leaves that feature out, Reflex's frame limit among them.
|
||||
files must be the pinned ones). The runtime takes a missing optional export for an older DLL and leaves that
|
||||
feature out, Reflex's frame limit among them, so a DLL that lacks an export `runtime/dlssg/nx2_sl.h` declares fails
|
||||
`tools/build_dlssg.py`, and the release stops on such a `--dlssg` DLL before anything is downloaded
|
||||
(`make_launcher.py` `check_dlssg`; `make_kit.py` the same). `python tools/build_dlssg.py --check <dll>` makes that
|
||||
check of a DLL built earlier.
|
||||
|
||||
`--pgo FILE` puts an execution profile and its record in the release (`app/<version>/data`), and the prebuilt
|
||||
runtime is compiled with it; the release stops when the record names another `recomp/` than the checkout's, and
|
||||
|
||||
@@ -3,10 +3,17 @@ has, and names those the DLL lacks. A DLL built from older sources would otherwi
|
||||
optional export (nx2sl_reflex2, nx2sl_frames_max) for an older DLL and leaves its feature out without an error.
|
||||
|
||||
Builds a small DLL with two of three declared exports with MSYS2 UCRT64's clang (no MSVC, no Streamline SDK, no game
|
||||
files) and checks that the third is the one reported; then that nx2_sl.h's own declarations are read in full.
|
||||
files) and checks that the third is the one reported; then that nx2_sl.h's own declarations are read in full. The
|
||||
release gate: build_dlssg.check stops on that DLL (nx2_sl.h lists nx2sl_reflex2), on a missing file and on files that
|
||||
are no DLL, and passes a DLL built with every export nx2_sl.h declares; tools/make_launcher.py and tools/make_kit.py
|
||||
run it on their --dlssg DLL before they resolve, download or delete anything (a release that shipped the DLL of 0.8.0
|
||||
would never let Reflex hold the frame limit).
|
||||
|
||||
Usage: dlssg_exports_check.py
|
||||
"""
|
||||
import contextlib
|
||||
import inspect
|
||||
import io
|
||||
import os
|
||||
import shutil
|
||||
import subprocess
|
||||
@@ -37,6 +44,16 @@ def compiler():
|
||||
return shutil.which('clang') or 'clang'
|
||||
|
||||
|
||||
def refused(fn, *args):
|
||||
"""The message fn(*args) exits with, None when it returns."""
|
||||
try:
|
||||
with contextlib.redirect_stdout(io.StringIO()):
|
||||
fn(*args)
|
||||
except SystemExit as e:
|
||||
return str(e.code)
|
||||
return None
|
||||
|
||||
|
||||
def main():
|
||||
if os.name != 'nt':
|
||||
print('dlssg_exports_check: Windows only (it builds a DLL)')
|
||||
@@ -67,6 +84,35 @@ def main():
|
||||
expect(f'{name} declared in nx2_sl.h', name in declared, True)
|
||||
# the header names its version and log types too, which are no exports of their own
|
||||
expect('types that are no functions', {'nx2sl_' + t for t in ('Image', 'Camera', 'Log')} & declared, set())
|
||||
|
||||
# The release gate. A DLL with every export nx2_sl.h declares passes; the two-export one, a missing file and files
|
||||
# that are no DLL stop it, naming why.
|
||||
(work / 'all.c').write_text(''.join(f'__declspec(dllexport) void {n}(void) {{}}\n' for n in sorted(declared)),
|
||||
encoding='utf-8')
|
||||
full = work / 'all.dll'
|
||||
subprocess.check_call([compiler(), '-shared', '-O1', str(work / 'all.c'), '-o', str(full)], env=env)
|
||||
expect('missing from a DLL with every declared export', build_dlssg.missing_exports(full), [])
|
||||
expect('check of a DLL with every declared export', refused(build_dlssg.check, full), None)
|
||||
why = refused(build_dlssg.check, dll) or ''
|
||||
expect('check of the two-export DLL names nx2sl_reflex2', 'nx2sl_reflex2' in why and 'build it again' in why, True)
|
||||
expect('check of a missing DLL', 'is missing' in (refused(build_dlssg.check, work / 'none.dll') or ''), True)
|
||||
(work / 'tiny.dll').write_bytes(b'MZ')
|
||||
for name in ('two.c', 'tiny.dll'):
|
||||
expect(f'check of {name}, no DLL', 'no DLL' in (refused(build_dlssg.check, work / name) or ''), True)
|
||||
|
||||
# make_launcher.py's check_dlssg is that check, and both packaging scripts make it before they resolve the
|
||||
# Streamline files (a download) or delete their output folder.
|
||||
import make_kit
|
||||
import make_launcher
|
||||
expect('make_launcher.check_dlssg passes the full DLL', refused(make_launcher.check_dlssg, full), None)
|
||||
expect('make_launcher.check_dlssg names nx2sl_reflex2',
|
||||
'nx2sl_reflex2' in (refused(make_launcher.check_dlssg, dll) or ''), True)
|
||||
for mod, call, later in ((make_launcher, 'check_dlssg(a.dlssg)', ('streamline_pin.resolve(', 'shutil.rmtree(')),
|
||||
(make_kit, 'build_dlssg.check(a.dlssg)', ('streamline_pin.resolve(', 'shutil.rmtree('))):
|
||||
src = inspect.getsource(mod.main)
|
||||
at = src.find(call)
|
||||
for what in later:
|
||||
expect(f'{mod.__name__}.main checks the DLL before {what}', 0 <= at < src.find(what), True)
|
||||
print(f'dlssg_exports_check: {"ok" if not fails else f"{fails} failed"} ({len(declared)} exports in nx2_sl.h)')
|
||||
return 1 if fails else 0
|
||||
|
||||
|
||||
@@ -12,7 +12,8 @@ tools/make_game.py place_dlssg puts them beside the game.
|
||||
The built DLL must export every function runtime/dlssg/nx2_sl.h declares (each PFN_nx2sl_<name> is the export
|
||||
nx2sl_<name>), or the build fails naming the ones it lacks: the runtime takes a missing optional export for an older
|
||||
DLL and leaves its feature out without an error. --check makes the same check of a DLL built before, such as the one
|
||||
a release is about to ship.
|
||||
a release is about to ship; tools/make_launcher.py and tools/make_kit.py make it on their --dlssg DLL first and stop
|
||||
on one that fails.
|
||||
"""
|
||||
import argparse
|
||||
import os
|
||||
@@ -83,8 +84,14 @@ def missing_exports(dll, header=HEADER):
|
||||
|
||||
|
||||
def check(dll):
|
||||
"""Exit naming the exports nx2_sl.h declares that dll lacks."""
|
||||
missing = missing_exports(dll)
|
||||
"""Exit naming the exports nx2_sl.h declares that dll lacks, or saying that dll is missing or no PE file.
|
||||
tools/make_launcher.py and tools/make_kit.py run it on their --dlssg DLL before anything is downloaded or built."""
|
||||
if not Path(dll).is_file():
|
||||
sys.exit(f'{dll} is missing')
|
||||
try:
|
||||
missing = missing_exports(dll)
|
||||
except (ValueError, TypeError, struct.error) as e: # pe_exports: no PE signature, or a table outside the file
|
||||
sys.exit(f'{dll} is no DLL that can be read ({e})')
|
||||
if missing:
|
||||
sys.exit(f'{dll} lacks exports runtime/dlssg/nx2_sl.h declares: {", ".join(missing)} '
|
||||
'(a DLL built from older sources: build it again)')
|
||||
|
||||
@@ -14,7 +14,8 @@ tools/build_dlssg.py beside NVIDIA Streamline's runtime, tools/streamline_pin.py
|
||||
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. 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.
|
||||
checkout's sources (tools/build_xlate.py check_built), and the --dlssg DLL must export every function
|
||||
runtime/dlssg/nx2_sl.h declares (tools/build_dlssg.py check); 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,6 +74,7 @@ def main():
|
||||
ap.add_argument('--zip', action='store_true')
|
||||
a = ap.parse_args()
|
||||
sys.path.insert(0, str(ROOT / 'tools'))
|
||||
import build_dlssg
|
||||
import build_shaders
|
||||
import build_xlate
|
||||
import dlss_pin
|
||||
@@ -83,6 +85,8 @@ def main():
|
||||
reason = build_xlate.check_built(a.xlate, 'nx2navi_xlate.exe') # the translator of this checkout's sources
|
||||
if reason:
|
||||
sys.exit(reason)
|
||||
if a.dlssg: # a DLL older than runtime/dlssg/nx2_sl.h would leave features out at run time without an error
|
||||
build_dlssg.check(a.dlssg)
|
||||
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')
|
||||
|
||||
@@ -26,7 +26,8 @@ The release folder (--out) holds:
|
||||
bin/dlssg/ with --dlssg (DLSS Frame Generation: nx2navi_dlssg.dll, Streamline's
|
||||
runtime DLLs and nvngx_dlssg.dll at the version tools/streamline_pin.py pins,
|
||||
downloaded from NVIDIA's Streamline SDK release and checked, or --streamline; their
|
||||
licences and a notice),
|
||||
licences and a notice; the release stops first on a DLL that lacks an export
|
||||
runtime/dlssg/nx2_sl.h declares, tools/build_dlssg.py check),
|
||||
lib/libnx2navirt.a (the runtime, prebuilt with the release's compiler),
|
||||
data/pgo-v111.profdata and .json with --pgo (the execution profile make_game.py
|
||||
compiles the lifted code and the runtime with, the prebuilt runtime included, and
|
||||
@@ -209,6 +210,17 @@ def check_xlate(xlate):
|
||||
print(f'translator identity {have[:16]}: built from this checkout\'s sources')
|
||||
|
||||
|
||||
def check_dlssg(dll):
|
||||
"""A release carries an nx2navi_dlssg.dll that exports every function runtime/dlssg/nx2_sl.h declares. The runtime
|
||||
takes a missing optional export (nx2sl_reflex2, nx2sl_frames_max) for an older DLL and leaves that feature out
|
||||
with one log line, so a DLL built from older sources would ship without an error: with the DLL of 0.8.0, which
|
||||
lacks nx2sl_reflex2, Reflex would never hold the frame limit. Such a DLL, or a missing one, stops the build
|
||||
(build_dlssg.check); main runs this before anything is resolved, downloaded or deleted."""
|
||||
import build_dlssg
|
||||
build_dlssg.check(dll)
|
||||
print(f'{dll}: exports the {len(build_dlssg.declared_exports())} functions runtime/dlssg/nx2_sl.h declares')
|
||||
|
||||
|
||||
def build_app(app, ver, xlate, feed_repo, lock, ffx=None, dlss=None, art=None, dlssg=None, pipelines=None, ffx4=None,
|
||||
pgo_profile=None):
|
||||
# The runtime's own shaders are source in the repository and SPIR-V headers in a release: a player's PC compiles
|
||||
@@ -404,6 +416,8 @@ def main():
|
||||
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
|
||||
if a.dlssg:
|
||||
check_dlssg(a.dlssg) # and so is nx2navi_dlssg.dll
|
||||
out = a.out
|
||||
shutil.rmtree(out, ignore_errors=True)
|
||||
folder = out / 'NX2navi'
|
||||
|
||||
Reference in New Issue
Block a user