From 2cbf9cd88f1e5f6f34eea0a0eecb6442f8334e82 Mon Sep 17 00:00:00 2001 From: Joe DiPrima Date: Tue, 28 Jul 2026 20:14:22 -0500 Subject: [PATCH] mkdist: archive the .map beside the .pdb, and stop shipping d3dx9_43.dll twice Symbols only matter if they survive the build that produced them, so archive BOTH per version, not just the PDB. The .map is the one that gets used in practice: tools/symcrash.py resolves btl4+0xNNNN from plain text with no debugger installed, which is the normal state of an operator box -- this machine has no cdb either. Warns loudly if either file is missing, since that silently means a crash in that build can never be read. Also: d3dx9_43.dll was written into the zip twice. It exists both next to the exe and in redist/, and both paths land at build/Release/ in the archive, so the entry was duplicated -- about 2 MB wasted and a duplicate-name warning from Python's zipfile that some extractors also complain about. Redist entries now skip anything already taken from beside the exe. Neither the pdb nor the map can reach a zip: .gitignore covers *.pdb and dist/, and the archive only ever picks up .dll from those directories. Co-Authored-By: Claude Fable 5 --- tools/mkdist.py | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/tools/mkdist.py b/tools/mkdist.py index 6417092..8c91ded 100644 --- a/tools/mkdist.py +++ b/tools/mkdist.py @@ -100,8 +100,13 @@ def main(): # d3dx9 + MSVC runtimes -- carried in redist/, shipped next to the exe; # the first zips included them and machines without the redists fail # to load the exe otherwise). + # ...but SKIP any that was already taken from beside the exe: both land at + # build/Release/ in the archive, so shipping both wrote a duplicate + # zip entry (d3dx9_43.dll, ~2 MB wasted, and some extractors warn). + beside_exe = {os.path.basename(p).lower() for p in exes} redist = ["redist/" + f for f in sorted(os.listdir("redist")) - if f.lower().endswith(".dll")] if os.path.isdir("redist") else [] + if f.lower().endswith(".dll") + and f.lower() not in beside_exe] if os.path.isdir("redist") else [] total = 0 with zipfile.ZipFile(zpath, "w", zipfile.ZIP_DEFLATED, compresslevel=6) as z: @@ -172,15 +177,24 @@ def main(): % (len(bats) + len(exes) + len(tracked), total / 1048576.0, zsz / 1048576.0)) - # Crash-forensics: archive this build's PDB next to the zip (operator-side - # only, never shipped) so the [crash] btl4+0xNNNN offsets in player logs - # stay resolvable per distributed version. - pdb = "build/Release/btl4.pdb" - if os.path.exists(pdb): - import shutil - pdb_dest = zpath[:-4] + ".pdb" - shutil.copyfile(pdb, pdb_dest) - print(" symbols archived: %s" % pdb_dest) + # Crash-forensics: archive this build's symbols next to the zip (operator- + # side only, never shipped) so the [crash] btl4+0xNNNN offsets in player + # logs stay resolvable per distributed version. BOTH files: + # .pdb full symbols, for cdb/WinDbg + # .map plain text -- tools/symcrash.py resolves an offset with NO + # debugger installed, which is the common case on an operator box. + # Keep them: once a version is in players' hands its symbols are the only + # way to read a crash it produces. + import shutil + for src, ext in (("build/Release/btl4.pdb", ".pdb"), + ("build/Release/btl4.map", ".map")): + if os.path.exists(src): + dest = zpath[:-4] + ext + shutil.copyfile(src, dest) + print(" symbols archived: %s" % dest) + else: + print(" WARNING: %s missing -- a crash in this build will NOT be " + "resolvable (need /Zi + /DEBUG + /MAP)" % src) if __name__ == "__main__": main()