Packages keep what building the launcher reads too: a game folder made from the source may take a package's tools

setup.py builds the launcher in a game folder made from the source, and that folder may be one unpacked from a builder
package (or the AppImage's deps/), whose compiler and Linux kit were trimmed to what the game's build reads: no C++
headers for the launcher. make_package.py and linux_used.py now also measure the launcher's headers and links. The
Linux kit's paths are normalized (libstdc++'s headers came as lib/gcc/.../../../../include/c++/10).

Co-Authored-By: Claude Opus 5.5 <[email protected]>
This commit is contained in:
kuraeowandClaude Opus 5.5 committed 2026-11-01 22:45:25 +03:00
1 parent e2ed7511db
commit d2b7f1581e
2 files changed
+48 -7

No files matched your search

+28 -5
View File
@@ -12,6 +12,7 @@ usage: python tools/linux_used.py --home ../release-test [--out release/linux-us
"""
import argparse
import pathlib
import posixpath
import re
import shutil
import subprocess
@@ -30,12 +31,12 @@ ALWAYS = ('linux/licenses/', 'linux/README', 'linux/kit.json', 'linux/sysroot/us
def classify(path, used):
p = path.strip().strip('"')
m = KIT.search(p)
if m:
used.add('linux/' + m.group(1).replace('\\', '/'))
if m: # normalized: libstdc++'s headers come as lib/gcc/x86_64-linux-gnu/10/../../../../include/c++/10/...
used.add('linux/' + posixpath.normpath(m.group(1).replace('\\', '/')))
return
m = RESOURCE.search(p)
if m:
used.add('clang/' + m.group(1).replace('\\', '/'))
used.add('clang/' + posixpath.normpath(m.group(1).replace('\\', '/')))
def tool(name):
@@ -72,7 +73,26 @@ def measure(home):
sys.exit(f'the header probe of {s} failed:\n{out.stderr[-2000:]}')
for p in re.split(r'\s+', out.stdout.replace('\\\n', ' ')):
classify(p, used)
# what lld reads linking the game (its link line, the objects of build-linux) and the encoder
# the launcher's headers: tools/setup.py builds it in a game folder made from the source (build_launcher_into),
# which may take its tools from a package (the AppImage's deps/)
import build_launcher
import deps_install
deps_install.launcher_libs(ROOT)
build_launcher.resources(tmp) # its version.h
inc = [f'-I{ROOT / d}' for d in ('deps/launcher/imgui', 'deps/launcher/imgui/backends', 'deps/launcher/nanosvg',
'deps/launcher/stb')] + [f'-I{tmp}', '-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS',
'-march=x86-64-v2']
for s in build_launcher.SOURCES:
cxx = s.endswith('.cpp')
cmd = [tool('clang++' if cxx else 'clang'), '-M', *flags, *inc, str(ROOT / s)]
if cxx:
cmd += ['-std=c++17', '-stdlib=libstdc++']
out = subprocess.run(cmd, capture_output=True, text=True, env=tool_env())
if out.returncode:
sys.exit(f'the header probe of {s} failed:\n{out.stderr[-2000:]}')
for p in re.split(r'\s+', out.stdout.replace('\\\n', ' ')):
classify(p, used)
# what lld reads linking the game (its link line, the objects of build-linux), the encoder and the launcher
link = re.search(r'^rule link\n command = clang (.*) -o \$out @\$out\.rsp (.*)$', text, re.M)
objs = re.search(r'^build linux/ultratears: link (.*)$', text, re.M).group(1).split()
probe = tmp / 'probe.cpp'
@@ -83,7 +103,10 @@ def measure(home):
'@' + str(rsp), *link.group(2).split()],
[tool('clang++'), *flags, '-fuse-ld=lld', '--rtlib=libgcc', '--unwindlib=libgcc', '-stdlib=libstdc++',
'-static-libstdc++', '-o', str(tmp / 'bc7build'), str(probe), f'-L{kit}/lib', '-l:libzstd.a', '-pthread',
'-lm']]
'-lm'],
[tool('clang++'), *flags, '--rtlib=libgcc', '--unwindlib=libgcc', '-no-pie', f'-L{kit}/lib', '-fuse-ld=lld',
'-o', str(tmp / 'launcher'), str(probe),
*build_launcher.LINUX_LIBS.replace("'$$ORIGIN'", '$ORIGIN').replace('$$ORIGIN', '$ORIGIN').split()]]
for cmd in runs:
cmd = [c for c in cmd if c != '-g'] + ['-Wl,--verbose']
r = subprocess.run(cmd, capture_output=True, text=True, env=tool_env(), cwd=home)
+20 -2
View File
@@ -122,12 +122,30 @@ def clang64_files_used(home):
p = p.replace('\\', '/')
if p.lower().startswith(str(PREFIX).replace('\\', '/').lower()):
used.add(pathlib.Path(p))
# libraries: what lld reads in the two links (--verbose)
# the launcher's headers: tools/setup.py builds it in a game folder made from the source (build_launcher_into), and
# such a folder may be one unpacked from this package, with only these tools
import build_launcher
deps_install.launcher_libs(ROOT)
build_launcher.resources(tmp) # its version.h
inc = [f'-I{ROOT / d}' for d in ('deps/launcher/imgui', 'deps/launcher/imgui/backends', 'deps/launcher/nanosvg',
'deps/launcher/stb')] + [f'-I{tmp}', '-DIMGUI_DISABLE_OBSOLETE_FUNCTIONS', '-DUNICODE',
'-D_UNICODE', '-march=x86-64-v2']
for src in build_launcher.SOURCES:
cxx = src.endswith('.cpp')
cmd = [str(CLANG64 / ('clang++.exe' if cxx else 'clang.exe')), '-M', *inc, str(ROOT / src)] + (['-std=c++17'] if cxx else [])
r = subprocess.run(cmd, capture_output=True, text=True, env=tool_env())
if r.returncode:
sys.exit(f'the launcher header probe of {src} failed:\n{r.stderr[-2000:]}')
for p in re.split(r'\s+', r.stdout.replace('\\\n', ' ')):
p = p.replace('\\', '/')
if p.lower().startswith(str(PREFIX).replace('\\', '/').lower()):
used.add(pathlib.Path(p))
# libraries: what lld reads in the links of the game, the texture encoder and the launcher (--verbose)
ninja = (home / 'build/build.ninja').read_text()
rsp = re.search(r'^build UltraTears\.exe: link (.*)$', ninja, re.M).group(1).split() # ninja deletes the .rsp
link = re.search(r'command = clang (.*) -o \$out @\$out.rsp (.*)', ninja)
flags = link.group(1).split() + link.group(2).split()
for objs, libs in ((rsp, flags), ([], ['-static', '-pthread', '-lzstd', '-lc++'])):
for objs, libs in ((rsp, flags), ([], ['-static', '-pthread', '-lzstd', '-lc++']), ([], build_launcher.LIBS.split())):
probe = tmp / 'probe.c'
probe.write_text('int main(void) { return 0; }\n')
cmd = [str(CLANG64 / 'clang.exe'), '-fuse-ld=lld', '-Wl,--verbose', '-o', str(tmp / 'probe.exe')]