Merge commit 'refs/review/mint-148' into fix/mint-review-integration

This commit is contained in:
lucannez64 committed 2026-10-26 18:02:11 +01:00
commit 2142b54d94
4 files changed
+171 -4

No files matched your search

+1
View File
@@ -43,3 +43,4 @@ jobs:
- run: python -m unittest discover -s tests -p 'test_clean_stale_helpers.py'
- run: python -m unittest discover -s tests -p 'test_hide_league_client_in_game.py'
- run: python -m unittest discover -s tests -p 'test_client_in_game_tricks.py'
- run: python -m unittest discover -s tests -p 'test_setup_portability.py'
+25
View File
@@ -523,6 +523,31 @@ A separate multi-window path stopped the active async presenter when another dif
- **Prebuilt Swift file contains Git LFS pointer text:** install Git LFS and fetch the original upstream assets; pointer text is not a usable library.
- **Submodule fetch stops with no output right after `src/external/sqlite`:** the next submodule is `src/external/swift`, whose pinned `.lfsconfig` points at the retired `git-lfs.darlinghq.org`. The checkout is blocked on that host, not on sqlite. `prepare.py` redirects that submodule's LFS requests to GitHub. To finish a fetch that was interrupted before any patches were applied, run `git -C build/darling-src -c lfs.url=https://github.com/darlinghq/darling-swift.git/info/lfs submodule update --init --recursive --progress`, then re-run `./scripts/build.sh`. Do not run that submodule update once `prepare.py` has applied patches: it resets every submodule working tree to the pinned revision and discards the patches.
## Checkout moved to another path or account
`build/config.json`, the generated helpers and the CMake cache record absolute paths, so a checkout that was moved (for example from `/root/darling-lol` to `/home/<user>/darling-lol`, or renamed while staying in the same account) keeps pointing at the old location ([issue #142](https://github.com/lucannez64/darling-lol/issues/142)). `scripts/configure.py` now repairs the parts it owns and reports the rest on stderr:
- **Prefix:** a saved prefix that was exactly `<previous home>/.darling` follows the new host home. A prefix you chose yourself is kept, and a prefix inside the previous home prints a reminder to pass `--prefix` explicitly.
- **`build/runtime/build`:** recreated as a relative link, so it survives later moves. An absolute or dangling leftover is replaced; a real directory at that path is reported and left untouched.
- **CMake cache:** a `build/darling-src/build/CMakeCache.txt` whose `CMAKE_HOME_DIRECTORY` names a different checkout is reported, together with the path to remove. It is never deleted automatically because it can hold local build state.
After moving a checkout, run:
```sh
python3 scripts/configure.py
```
If the warning names another source directory, the cache still holds object files and dependency lists for the old path, and the build fails with `Permission denied` or `No such file or directory` against it. Remove it and rebuild (as the same user that owns the checkout):
```sh
rm -rf build/darling-src/build
./scripts/build.sh
```
Patches are rendered at `scripts/prepare.py` time, so `@PROJECT_ROOT@` in a patched file keeps the old path until it runs again. `./scripts/build.sh` and `./scripts/update.sh` both do that; do not run `prepare.py` by hand while the checkout has other edits in `build/darling-src`, because it refuses rather than resetting them.
The opt-in RenderDoc capture bridge (`RCLOL_RENDERDOC_CAPTURE=1`) is a developer diagnostic, not part of the installer. It expects `build/renderdoc/capture-bridge.so` and a RenderDoc build under `build/renderdoc/`, and neither setup script creates them. Without those files the capture is skipped and the game runs normally; the absolute path baked into the Indium patch is refreshed by the same `prepare.py` run.
## launchd crashes at boot after changing compiler flags
`darling shell` fails with `Error connecting to shellspawn` and `/tmp/lolsig.log` shows `LOLSIGFAIL pid=1 sig=11 code=1 addr=0x0` in `memmove`, called from `snprintf` in libkqueue's `epoll_event_dump`. The binaries were tuned for AMD Zen: clang 23 with `-mtune=znver*` (also selected by `-march=native` or `-mtune=native` on Zen) loads a thread-local variable's descriptor into a register other than `%rdi`, but dyld's `tlv_get_addr` reads `%rdi`, so every `__thread` and `thread_local` access returns NULL. Rebuild with `-mtune=generic` (the default in `scripts/build.sh` and the overlay builders), and check any binary with:
+60 -4
View File
@@ -1,15 +1,66 @@
#!/usr/bin/env python3
"""Render local paths into ignored runtime tools; never alter the source snapshot."""
import argparse,json,os,shutil
import argparse,json,os,shutil,sys
from pathlib import Path
from common import ROOT,configuration,render
def warn(message):
"""Diagnostics go to stderr: launcher/run.sh keep stdout for their own output."""
print('configure:',message,file=sys.stderr)
def rehome_prefix(c,requested):
"""The default prefix is derived from the host home, so a checkout that moved to another
machine or account must follow the new home instead of keeping the previous one (issue #142)."""
home=Path.home()
if requested is not None:return str(requested)
saved=c.get('prefix')
if not saved:return str(home/'.darling')
old_home=c.get('host_home')
if old_home and old_home!=str(home):
if saved==str(Path(old_home)/'.darling'):
warn(f'previous home {old_home} is gone; the default prefix moved to {home/".darling"}')
return str(home/'.darling')
try:relative=Path(saved).is_relative_to(old_home)
except (TypeError,ValueError):relative=False
if relative:
warn(f'prefix {saved} is inside the previous home {old_home}; pass --prefix to move it')
return saved
def link_build(runtime):
"""build/runtime/build must resolve to this checkout's build directory. A relative link keeps
working after the checkout moves, and any absolute or dangling leftover is replaced instead of
being treated as already correct (issue #142)."""
link=runtime/'build'
target='..' # build/runtime/build -> build
if link.is_symlink():
if os.readlink(link)==target:return
link.unlink()
elif os.path.lexists(link):
warn(f'{link} is not a symlink; leaving it untouched')
return
link.symlink_to(target,target_is_directory=True)
def stale_cache(build):
"""Return (cache, recorded source directory) when the CMake cache belongs to another checkout."""
cache=build/'darling-src/build/CMakeCache.txt'
try:lines=cache.read_text(errors='replace').splitlines()
except OSError:return None
expected=os.path.realpath(build/'darling-src')
for line in lines:
key,_,value=line.partition('=')
if key.split(':')[0]!='CMAKE_HOME_DIRECTORY':continue
if os.path.realpath(value)!=expected:return cache,value
return None
return None
p=argparse.ArgumentParser(description=__doc__)
p.add_argument('--guest-user');p.add_argument('--prefix',type=Path);p.add_argument('--sdk',type=Path)
a=p.parse_args();c=configuration()
if a.guest_user:
if not a.guest_user.replace('_','').replace('-','').isalnum():p.error('guest user must be a simple account name')
c['guest_user']=a.guest_user;c['guest_home']='/Users/'+a.guest_user
if a.prefix:c['prefix']=str(a.prefix.expanduser().resolve())
# Resolve the prefix before overwriting host_home, so it can still see the previous home.
c['prefix']=rehome_prefix(c,a.prefix.expanduser().resolve() if a.prefix else None)
if a.sdk:c['sdk']=str(a.sdk.expanduser().resolve())
c['project_root']=str(ROOT);c['host_home']=str(Path.home())
build=ROOT/'build';build.mkdir(exist_ok=True)
@@ -23,6 +74,11 @@ for source in (ROOT/'tools').iterdir():
target.unlink(missing_ok=True)
target.write_text(render(source.read_text(),c))
os.chmod(target,source.stat().st_mode & 0o777)
link=folder.parent/'build'
if not link.exists():link.symlink_to(build,target_is_directory=True)
link_build(folder.parent)
stale=stale_cache(build)
if stale:
cache,previous=stale
warn(f'{cache} was generated for {previous}, not {build/"darling-src"}; builds will fail with '
f'missing files or permission errors against the old path. Remove {build/"darling-src/build"} '
'and build again (it is never removed automatically because it may hold local work).')
print('Configured',len(list(folder.iterdir())),'runtime sources for',c['guest_home'])
+85
View File
@@ -120,6 +120,91 @@ exec REAL_INSTALL "$@"'''.replace('REAL_INSTALL', shutil.which('install')))
self.assertFalse(target.is_symlink())
def write_config(self, **changes):
(self.root / 'build/config.json').write_text(json.dumps(dict(self.config, **changes)))
def config_value(self, key):
return json.loads((self.root / 'build/config.json').read_text())[key]
def test_configure_rehomes_default_prefix_after_home_change(self):
previous = Path(self.tmp.name) / 'previous home'
self.write_config(host_home=str(previous), prefix=str(previous / '.darling'))
result = self.run_script('scripts/configure.py')
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(self.config_value('prefix'), str(self.home / '.darling'))
self.assertIn('previous home', result.stderr)
def test_configure_keeps_explicit_prefix_after_home_change(self):
previous = Path(self.tmp.name) / 'previous home'
self.write_config(host_home=str(previous), prefix=str(self.prefix))
self.configure()
self.assertEqual(self.config_value('prefix'), str(self.prefix))
self.assertEqual(self.config_value('host_home'), str(self.home))
def test_configure_warns_about_prefix_inside_previous_home(self):
previous = Path(self.tmp.name) / 'previous home'
self.write_config(host_home=str(previous), prefix=str(previous / 'custom prefix'))
result = self.run_script('scripts/configure.py')
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(self.config_value('prefix'), str(previous / 'custom prefix'))
self.assertIn('--prefix', result.stderr)
def test_configure_creates_relative_build_symlink(self):
self.configure()
link = self.root / 'build/runtime/build'
self.assertEqual(os.readlink(link), '..')
self.assertEqual(link.resolve(), (self.root / 'build').resolve())
def test_configure_repairs_absolute_and_dangling_build_symlink(self):
link = self.root / 'build/runtime/build'
link.parent.mkdir(parents=True)
link.symlink_to(self.root / 'build')
self.configure()
self.assertEqual(os.readlink(link), '..')
link.unlink()
link.symlink_to(self.root / 'moved away/build')
self.configure()
self.assertTrue(link.is_symlink())
self.assertEqual(link.resolve(), (self.root / 'build').resolve())
def test_configure_leaves_foreign_build_directory(self):
link = self.root / 'build/runtime/build'
link.mkdir(parents=True)
(link / 'keep').write_text('local build')
result = self.run_script('scripts/configure.py')
self.assertEqual(result.returncode, 0, result.stderr)
self.assertFalse(link.is_symlink())
self.assertEqual((link / 'keep').read_text(), 'local build')
self.assertIn('not a symlink', result.stderr)
def test_configure_warns_about_stale_cmake_cache(self):
cache = self.root / 'build/darling-src/build/CMakeCache.txt'
cache.parent.mkdir(parents=True)
cache.write_text('// generated\nCMAKE_HOME_DIRECTORY:INTERNAL=/root/old checkout/build/darling-src\n')
result = self.run_script('scripts/configure.py')
self.assertEqual(result.returncode, 0, result.stderr)
self.assertTrue(cache.is_file(), 'configure removed the CMake cache')
self.assertIn('/root/old checkout/build/darling-src', result.stderr)
self.assertIn('Remove', result.stderr)
def test_configure_accepts_current_cmake_cache(self):
cache = self.root / 'build/darling-src/build/CMakeCache.txt'
cache.parent.mkdir(parents=True)
cache.write_text(f'CMAKE_HOME_DIRECTORY:INTERNAL={self.root}/build/darling-src\n')
result = self.run_script('scripts/configure.py')
self.assertEqual(result.returncode, 0, result.stderr)
self.assertEqual(result.stderr, '')
def test_presentation_creates_prerequisites_and_repeat_install(self):
self.configure()
self.runtime_stubs()