mirror of
https://github.com/lucannez64/darling-lol.git
synced 2026-10-27 19:54:38 +00:00
setup failures reported in #137, #138 and #143 happened only after the long fetch/build or at Riot startup. scripts/preflight.py now runs from scripts/build.sh (before configure.py, so an old interpreter gets this message and not a traceback) and from scripts/install-runtime.sh, and checks the host once: - python 3.10+, cmake 3.20+ (the bundled indium CMakeLists requires it), git-lfs 2.13+, kernel 5.14+ and LLVM 16+ exit nonzero with one actionable line each. RCLOL_SKIP_PREFLIGHT=1 bypasses the gate. - llvm-objdump and llvm-nm are required, and unresolved names are explained. - Vulkan 1.3 and timeline semaphores are required when vulkaninfo is installed; they only warn when it is not, because a missing tool does not mean a missing driver. - the X display is probed with xdpyinfo in the environment Darling inherits. It only warns: a build does not need a display. - a prepared build/darling-src is scanned for small .dylib/.a/.so/.o files that still contain Git LFS pointer text, which links but crashes the guest. - --json prints the same report for the diagnostic tools. The installers no longer call hashlib.file_digest (Python 3.11+), so Ubuntu 22.04's Python 3.10 works instead of failing after the overlays are built (#137). A streaming tools/file_digest.py replaces it. LLVM command line tools are resolved by tools/llvm_tools.py: an unversioned name on PATH first, then the highest llvm-<tool>-<N>, then llvm-config --bindir. Debian/Ubuntu install llvm-objdump and llvm-nm only under /usr/lib/llvm-<N>/bin, which broke the runtime validation (#138). Six tools now use it. The LLVM 16 floor also stops the LLVM 15 runtime abort from #139 before anything is built. Two test helpers used APIs added after Python 3.10; they are shimmed so the same suite runs on 3.10, 3.11 and 3.14. Adds tests/test_preflight.py (24 tests, fake host tools only).
94 lines
3.3 KiB
Python
94 lines
3.3 KiB
Python
"""Find LLVM command line tools, including versioned Debian/Ubuntu names.
|
|
|
|
Ubuntu's llvm-<N>-dev installs llvm-objdump and llvm-nm in /usr/lib/llvm-<N>/bin
|
|
without an unversioned name in PATH, so a bare ['llvm-objdump'] run fails on an
|
|
otherwise complete host (issue #138). Resolution order: an unversioned tool on
|
|
PATH, then the highest versioned name on PATH, then the directory llvm-config
|
|
reports. Nothing here runs a guest process.
|
|
"""
|
|
import os
|
|
import subprocess
|
|
|
|
|
|
def _collect(directory, name, found):
|
|
"""Add every `name` and `name-<digits>` executable in the directory to found."""
|
|
try:
|
|
entries = os.listdir(directory)
|
|
except OSError:
|
|
return
|
|
for entry in entries:
|
|
suffix = entry[len(name) + 1:]
|
|
if entry == name:
|
|
version = 0 # An unversioned name always wins.
|
|
elif entry.startswith(name + '-') and suffix.isdigit():
|
|
version = int(suffix)
|
|
else:
|
|
continue
|
|
path = os.path.join(directory or '.', entry)
|
|
if os.path.isfile(path) and os.access(path, os.X_OK):
|
|
found.setdefault(version, path)
|
|
|
|
|
|
def _executables(name):
|
|
"""{version: path} for `name` and for every `name-<digits>` on PATH."""
|
|
found = {}
|
|
for folder in os.environ.get('PATH', '').split(os.pathsep):
|
|
_collect(folder or '.', name, found)
|
|
return found
|
|
|
|
|
|
def _preferred(candidates):
|
|
return candidates[0 if 0 in candidates else max(candidates)] if candidates else None
|
|
|
|
|
|
def _bindir():
|
|
"""`llvm-config --bindir` from the preferred llvm-config, or None."""
|
|
configuration = _preferred(_executables('llvm-config'))
|
|
if not configuration:
|
|
return None
|
|
result = subprocess.run([configuration, '--bindir'],
|
|
capture_output=True, text=True, errors='replace')
|
|
directory = result.stdout.strip()
|
|
if result.returncode or not os.path.isdir(directory):
|
|
return None
|
|
return directory
|
|
|
|
|
|
def find(name):
|
|
"""Path of an LLVM tool, or None when this host does not have it."""
|
|
candidates = _executables(name)
|
|
if candidates:
|
|
return _preferred(candidates)
|
|
directory = _bindir()
|
|
if directory:
|
|
in_bindir = {}
|
|
_collect(directory, name, in_bindir)
|
|
if in_bindir:
|
|
return _preferred(in_bindir)
|
|
return None
|
|
|
|
|
|
def require(name):
|
|
"""Path of an LLVM tool, or exit with what was tried and what to install."""
|
|
path = find(name)
|
|
if path:
|
|
return path
|
|
raise SystemExit(f'{name} not found: looked for an unversioned {name}, a versioned '
|
|
f'{name}-<N> in PATH and `llvm-config --bindir`. Install the LLVM tools '
|
|
f'package (for example llvm-dev, llvm15-tools or llvm23-tools).')
|
|
|
|
|
|
def config(*arguments):
|
|
"""Run llvm-config with the arguments, or exit with an actionable message."""
|
|
path = require('llvm-config')
|
|
result = subprocess.run([path, *arguments], capture_output=True, text=True, errors='replace')
|
|
if result.returncode:
|
|
raise SystemExit(f'{path} {" ".join(arguments)} failed: {result.stderr.strip()}')
|
|
return result.stdout.strip()
|
|
|
|
|
|
def major():
|
|
"""LLVM major version reported by llvm-config, or None when unparsable."""
|
|
head = config('--version').strip().split('.', 1)[0]
|
|
return int(head) if head.isdigit() else None
|