fix: find RetroArch where Windows and macOS keep it

This commit is contained in:
Abdessamad Derraz committed 2026-10-17 20:26:02 +02:00
1 parent f0e015b60a
commit 2c61a909f7
6 files changed
+112 -18

No files matched your search

+1 -1
View File
@@ -8,7 +8,7 @@ param(
$ErrorActionPreference = "Stop"
$defaultInstallUrl = "https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
$defaultInstallSha256 = "351450de7dc16195231c2065aef1d1ee72a2231d9a5d7af158dc199099b198ad"
$defaultInstallSha256 = "3eac76733e9f27965ef62da4f3ef8e793b02af289d7a3317b1626c99a64ddcff"
$maximumInstallerBytes = 2MB
$installer = if ($PSScriptRoot) { Join-Path $PSScriptRoot "install.py" } else { $null }
$temporary = $null
+49 -13
View File
@@ -174,15 +174,15 @@ def _os_default_dests(os_type: str) -> dict[str, Path]:
profile = Path(os.environ.get("USERPROFILE", str(home)))
appdata = Path(os.environ.get("APPDATA", str(home / "AppData" / "Roaming")))
return {
"retroarch": appdata / "RetroArch" / "system",
# RetroArch's system directory defaults to <exe folder>\system
# (platform_win32.c), and its installer to C:\RetroArch-Win64.
"retroarch": Path("C:/RetroArch-Win64/system"),
# RetroBat's installer defaults to C:\RetroBat (installer.iss).
"retrobat": Path("C:/RetroBat/bios"),
"bizhawk": profile / "BizHawk" / "Firmware",
}
if os_type == "darwin":
return {
"retroarch": home / "Library" / "Application Support" / "RetroArch" / "system",
}
return {"retroarch": _macos_retroarch_base() / "system"}
return {
"retroarch": home / ".config" / "retroarch" / "system",
"bizhawk": home / ".config" / "BizHawk" / "Firmware",
@@ -455,6 +455,27 @@ def _retroarch_cfg_dir(
return None
def _windows_retroarch_dirs() -> list[Path]:
"""Folders holding retroarch.exe where the installer and the archive put
it: C:\RetroArch-Win64 by default, C:\RetroArch for 32-bit builds."""
candidates = [Path("C:/RetroArch-Win64"), Path("C:/RetroArch")]
for var in ("ProgramFiles", "ProgramFiles(x86)"):
root = os.environ.get(var, "")
if root:
candidates.append(Path(root) / "RetroArch")
return [folder for folder in candidates if (folder / "retroarch.exe").is_file()]
def _macos_retroarch_base() -> Path:
"""Where RetroArch on macOS keeps its system folder by default:
~/Documents/RetroArch, or Application Support/RetroArch when that folder
holds portable.txt (platform_darwin.m)."""
support = Path.home() / "Library" / "Application Support" / "RetroArch"
if (support / "portable.txt").is_file():
return support
return Path.home() / "Documents" / "RetroArch"
# System directory -> the retroarch.cfg it was read from and the directory
# ':' expands to there, for finding the cores of the same installation.
_RETROARCH_CONFIGS: dict[Path, tuple[Path, Path]] = {}
@@ -896,11 +917,17 @@ def detect_platforms(os_type: str) -> list[tuple[str, Path]]:
found.append(("retroarch", ra_dir))
if os_type == "darwin":
home = Path.home()
mac_cfg = home / "Library" / "Application Support" / "RetroArch" / "retroarch.cfg"
ra_dir = _parse_retroarch_system_dir(mac_cfg)
if ra_dir:
found.append(("retroarch", ra_dir))
# open_default_config_file reads <Application Support>/RetroArch/config
# (configuration.c); a value left at default is the documents folder,
# or Application Support itself for a portable install
# (platform_darwin.m). The config beside it is where older builds
# kept it.
support = Path.home() / "Library" / "Application Support" / "RetroArch"
for mac_cfg in (support / "config" / "retroarch.cfg", support / "retroarch.cfg"):
ra_dir = _parse_retroarch_system_dir(mac_cfg, _macos_retroarch_base())
if ra_dir:
found.append(("retroarch", ra_dir))
break
if os_type in ("windows", "wsl"):
# EmuDeck Windows
@@ -911,11 +938,20 @@ def detect_platforms(os_type: str) -> list[tuple[str, Path]]:
if emu_path:
found.append(("emudeck", Path(emu_path) / "bios"))
# RetroArch Windows
# RetroArch Windows: open_default_config_file reads retroarch.cfg
# beside the exe, then under %APPDATA%\RetroArch, and a value left at
# default is <exe folder>\system (configuration.c, platform_win32.c).
appdata = os.environ.get("APPDATA", "")
if appdata:
win_cfg = Path(appdata) / "RetroArch" / "retroarch.cfg"
ra_dir = _parse_retroarch_system_dir(win_cfg)
appdata_cfg = Path(appdata) / "RetroArch" / "retroarch.cfg" if appdata else None
exe_dirs = _windows_retroarch_dirs() if os_type == "windows" else []
for exe_dir in exe_dirs:
ra_dir = _parse_retroarch_system_dir(exe_dir / "retroarch.cfg", exe_dir)
if ra_dir is None and appdata_cfg is not None:
ra_dir = _parse_retroarch_system_dir(appdata_cfg, exe_dir)
found.append(("retroarch", ra_dir or exe_dir / "system"))
break
if not exe_dirs and appdata_cfg is not None:
ra_dir = _parse_retroarch_system_dir(appdata_cfg)
if ra_dir:
found.append(("retroarch", ra_dir))
+1 -1
View File
@@ -18,7 +18,7 @@ esac
TEMP_INSTALLER=""
TEMP_DIRECTORY=""
DEFAULT_INSTALL_URL="https://raw.githubusercontent.com/Abdess/retrobios/main/install.py"
DEFAULT_INSTALL_SHA256="351450de7dc16195231c2065aef1d1ee72a2231d9a5d7af158dc199099b198ad"
DEFAULT_INSTALL_SHA256="3eac76733e9f27965ef62da4f3ef8e793b02af289d7a3317b1626c99a64ddcff"
MAX_INSTALLER_BYTES=2097152
cleanup() {
+9 -1
View File
@@ -171,9 +171,17 @@ platforms:
method: config_file
config: $HOME/.config/retroarch/retroarch.cfg
parse_key: system_directory
# configuration.c reads <Application Support>/RetroArch/config; a value
# left at default is ~/Documents/RetroArch/system (platform_darwin.m).
- os: darwin
method: config_file
config: $HOME/Library/Application Support/RetroArch/retroarch.cfg
config: $HOME/Library/Application Support/RetroArch/config/retroarch.cfg
parse_key: system_directory
bios_path: $HOME/Documents/RetroArch/system
# Beside retroarch.exe first, then %APPDATA%; default <exe folder>\system.
- os: windows
method: config_file
config: 'C:\RetroArch-Win64\retroarch.cfg'
parse_key: system_directory
- os: windows
method: config_file
+49
View File
@@ -1743,5 +1743,54 @@ class TargetListFailureIsNotAnAnswer(unittest.TestCase):
with unittest.mock.patch.object(install.urllib.request, "urlopen", missing):
self.assertEqual(install.fetch_targets("retroarch"), {})
class RetroArchWhereItReallyLives(unittest.TestCase):
"""Windows: retroarch.cfg sits beside retroarch.exe and system defaults
to <exe folder>\\system; only %APPDATA% was read, and the fallback was a
folder RetroArch never reads. macOS: the config is under
Application Support/RetroArch/config, the system folder in Documents."""
def _exe_dir(self) -> tuple[Path, dict]:
program_files = Path(_tempdir(self))
exe_dir = program_files / "RetroArch"
exe_dir.mkdir()
(exe_dir / "retroarch.exe").write_bytes(b"MZ")
return exe_dir, {"ProgramFiles": str(program_files)}
def test_windows_install_folder_without_a_config(self):
exe_dir, env = self._exe_dir()
with unittest.mock.patch.dict(os.environ, env, clear=True):
found = install.detect_platforms("windows")
self.assertIn(("retroarch", exe_dir / "system"), found)
def test_windows_appdata_config_at_default_names_the_exe_folder(self):
exe_dir, env = self._exe_dir()
appdata = Path(_tempdir(self))
(appdata / "RetroArch").mkdir()
(appdata / "RetroArch" / "retroarch.cfg").write_text('system_directory = "default"\n')
env["APPDATA"] = str(appdata)
with unittest.mock.patch.dict(os.environ, env, clear=True):
found = install.detect_platforms("windows")
self.assertIn(("retroarch", exe_dir / "system"), found)
def test_windows_config_beside_the_exe_wins(self):
exe_dir, env = self._exe_dir()
(exe_dir / "retroarch.cfg").write_text('system_directory = "D:\\bios"\n')
with unittest.mock.patch.dict(os.environ, env, clear=True):
found = install.detect_platforms("windows")
self.assertIn(("retroarch", Path("D:\\bios")), found)
def test_macos_config_folder_and_documents_default(self):
home = Path(_tempdir(self))
support = home / "Library" / "Application Support" / "RetroArch"
(support / "config").mkdir(parents=True)
(support / "config" / "retroarch.cfg").write_text('system_directory = "default"\n')
with unittest.mock.patch.object(install.Path, "home", return_value=home):
found = install.detect_platforms("darwin")
self.assertIn(("retroarch", home / "Documents" / "RetroArch" / "system"), found)
(support / "portable.txt").write_text("")
found = install.detect_platforms("darwin")
self.assertIn(("retroarch", support / "system"), found)
if __name__ == "__main__":
unittest.main()
+3 -2
View File
@@ -277,8 +277,9 @@ found on one machine.
| `~/.var/app/org.libretro.RetroArch/config/retroarch/retroarch.cfg` | RetroArch (Flatpak) | `system_directory` |
| `~/snap/retroarch/current/.config/retroarch/retroarch.cfg` | RetroArch (Snap) | `system_directory` |
| `~/.config/retroarch/retroarch.cfg` | RetroArch (native) | `system_directory` |
| `~/Library/Application Support/RetroArch/retroarch.cfg` | RetroArch (macOS) | `system_directory` |
| `%APPDATA%\RetroArch\retroarch.cfg` | RetroArch (Windows) | `system_directory` |
| `~/Library/Application Support/RetroArch/config/retroarch.cfg` | RetroArch (macOS) | `system_directory`; at default, `~/Documents/RetroArch/system` (portable: `Application Support/RetroArch/system`) |
| `retroarch.cfg` beside `retroarch.exe` (`C:\RetroArch-Win64`, `C:\RetroArch`, `Program Files\RetroArch`) | RetroArch (Windows) | `system_directory`; at default or without a config, `system` beside the exe |
| `%APPDATA%\RetroArch\retroarch.cfg` | RetroArch (Windows) | `system_directory`, read when the exe folder has no config |
| `%ProgramFiles(x86)%\Steam\steamapps\common\RetroArch\retroarch.cfg` | RetroArch (Steam) | `system_directory` |
| LaunchBox `Data\Emulators.xml` | RetroArch (portable) | the system directory that entry points at |