Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 31 additions & 0 deletions .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,37 @@ jobs:
run: uv run pytest -q -rs
env:
DECOMP_TRAY: "0"
macos:
strategy:
fail-fast: false
matrix:
runner: [macos-15, macos-15-intel]
runs-on: ${{ matrix.runner }}
steps:
- uses: actions/checkout@v7
- uses: astral-sh/setup-uv@v10.3.0
- run: uv sync --locked
- run: uv run ruff check src tests projects
- name: Demo linker and object tools
run: |
brew install llvm lld
echo "$(brew --prefix llvm)/bin" >> "$GITHUB_PATH"
echo "$(brew --prefix lld)/bin" >> "$GITHUB_PATH"
- name: Check Intel compiler runtime on Apple Silicon
run: |
if [ "$(uname -m)" = arm64 ]; then
/usr/bin/arch -x86_64 /usr/bin/true
fi
- name: Free pinned N64 compiler and decompilation tools
run: >-
uv run python -c "from decompnet import toolchains; [toolchains.install(t) for t in
['gcc-2.7.2-kmc', 'binutils-mips', 'm2c', 'decomp-permuter', 'objdiff-cli']]"
- run: uv run python projects/zlib-n64/prepare.py
- name: Native WebKit and portable regressions, including N64 demo matching and rebuild
run: uv run pytest -q -rs
env:
DECOMP_TEST_COCOA: "1"
DECOMP_TRAY: "0"
check:
runs-on: ubuntu-24.04
steps:
Expand Down
4 changes: 2 additions & 2 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ How to work in this repository. Read README.md for what decompdecomp does from a

decompdecomp: AI agents decompile games the user owns into C that compiles, with the game's original compiler, to
the exact same bytes. Python 3.12+, managed with uv. A continuation of decomp.wtf (Sam Wolfs, i12bp8/decomp.wtf,
archived at 0.10.6): `origin` is n-delic/decompdecomp, `upstream` the archived original.
archived at 0.10.6). This fork is RetroReversing/decompdecomp; its parent is n-delic/decompdecomp.

Naming: the project is **decompdecomp** in everything users read. Internal names stay as decomp.wtf left them, so
existing installs and projects keep working: the `decomp` command, the `decompnet` package and data folder,
Expand Down Expand Up @@ -106,7 +106,7 @@ from the vtables constructors store, MIPS: the `get_class` tool and the class li
`compilermap.py` (which compiler built each part of a MIPS game; the judge's survey is `engine.survey_compilers`;
`app/rangecheck.py` tests a suggested range on its neighbours before it applies), `app/tools.py` (the MCP
tools helpers get and their prompt; MCP is only the app's private wiring to the CLI helpers it starts), `app/window.py`
+ `app/gtkwindow.py` + `app/tray.py` (the window: GTK and WebKitGTK from the system, run by the system's python3; the
+ `app/gtkwindow.py` + `app/macwindow.py` + `app/tray.py` (the window: GTK and WebKitGTK from the system, run by the system's python3; the
page answers only it, by the secret in its user agent; and the tray icon; tests set `DECOMP_WINDOW=0` and
`DECOMP_TRAY=0`), `app/edition.py` (release or development copy), `app/saves.py` (a ROM project's work as plain files, and a
project restored from them), `app/readable.py` (polishing matched code), `app/knowledge.py` (what agents learn,
Expand Down
61 changes: 56 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@
<p align="center">
<a href="LICENSE"><img alt="AGPL-3.0 license" src="https://img.shields.io/badge/license-AGPL--3.0-157a49?style=flat-square"></a>
<img alt="Linux" src="https://img.shields.io/badge/platform-Linux-15140f?style=flat-square">
<img alt="macOS" src="https://img.shields.io/badge/platform-macOS%20Intel%20%2F%20Apple%20Silicon-15140f?style=flat-square">
<img alt="Windows" src="https://img.shields.io/badge/platform-Windows%2010%20%2F%2011-15140f?style=flat-square">
<a href="https://discord.gg/hhEm3zZagB"><img alt="Discord" src="https://img.shields.io/badge/Discord-join-5865F2?style=flat-square&logo=discord&logoColor=white"></a>
<img alt="Agents: Claude Code, Codex, opencode, Antigravity, any API model" src="https://img.shields.io/badge/agents-Claude%20Code%20%C2%B7%20Codex%20%C2%B7%20opencode%20%C2%B7%20API%20models-157a49?style=flat-square">
Expand All @@ -28,16 +29,22 @@ under a tenth of a second (1.4 s before), and agents restart by themselves after
stand-in for a model that hands in the demo's own C; the app compiles and judges every function for real.</sub>
</p>

## RetroReversing fork

This fork of [NDelic's decompdecomp](https://github.com/n-delic/decompdecomp) adds a native macOS app.
The original decomp.wtf and decompdecomp credits and licenses are preserved. Report fork issues to
[RetroReversing/decompdecomp](https://github.com/RetroReversing/decompdecomp/issues).

## Install

decompdecomp runs on **Linux and Windows 10/11**, on a 64-bit Intel or AMD PC. On Linux, install it with one command. The installer also gets
decompdecomp runs on **Linux and Windows 10/11** on x86-64, and **macOS 12+** on Intel or Apple Silicon. On Linux, install it with one command. The installer also gets
the free compilers and keeps decompdecomp up to date:

```
curl -fsSL https://decomp.ndelic.com/install.sh | bash
curl -fsSL https://raw.githubusercontent.com/RetroReversing/decompdecomp/macos-support/site/public/install.sh | bash -s -- --source branch:macos-support
```

Or install a package from the [releases](https://github.com/n-delic/decompdecomp/releases):
Upstream Linux packages remain available from the [releases](https://github.com/n-delic/decompdecomp/releases):

```
sudo apt install ./decompdecomp_*_amd64.deb # Debian, Ubuntu, Pop!_OS, Mint
Expand Down Expand Up @@ -66,13 +73,57 @@ brings back a window closed while helpers work. Free tools use Windows builds wh

> [!IMPORTANT]
> **PS1, PS2 and most N64 games need WSL 2 on Windows.** Their period compilers (GCC for PlayStation, EE-GCC and
> CodeWarrior for PS2, KMC GCC for N64) exist only for Linux, so decompdecomp runs them inside WSL 2. Without it,
> CodeWarrior for PS2, KMC GCC for N64) use their Linux builds through WSL 2 on Windows. Without it,
> every compile of such a game fails. Set it up before you import one: run `wsl --install` in an administrator
> PowerShell, restart if asked, then open Ubuntu once to finish its setup.
>
> GameCube, Wii, DS and Windows PC games, and N64 games built with IDO, don't need WSL: their compilers run on
> Windows itself.
macOS isn't supported in this version.

### macOS (Intel and Apple Silicon)

Use the installer above, or clone this fork and install the checkout:

```sh
git clone --branch macos-support https://github.com/RetroReversing/decompdecomp.git
cd decompdecomp
bash site/public/install.sh
```

The installer uses uv and Python 3.12, installs the Cocoa/WebKit bridge, gets the free tools, and creates
`~/Applications/decompdecomp.app`. Open it from Finder or run `decomp`. Projects stay in `~/Decomp`;
toolchains live in `~/Library/Application Support/decompnet/toolchains`. Intel Macs also need Xcode Command Line
Tools (`xcode-select --install`) to build the pinned modern MIPS binutils on their first N64 export; upstream only
publishes those tools for Apple Silicon. Finder launches preserve the PATH
from installation so your installed Node and helper CLIs remain available; rerun `decomp shortcut` after
changing their locations. This is a source install; there is no signed DMG or macOS release bundle yet.
Installs from `macos-support` track that branch in this fork when checking for updates.

**Apple Silicon:** the app, WebKit window and modern tools run natively. The pinned N64 KMC-compatible
GCC 2.7.2 and binutils 2.6 archives contain Intel programs, so install Apple's Rosetta runtime before setup:

```sh
softwareupdate --install-rosetta
```

Read and accept Apple's license if you agree, then rerun `decomp setup`. No proprietary game compiler is
installed automatically. IDO still needs your explicit license acceptance in Compilers & tools.

| Mac capability | Availability |
| --- | --- |
| N64 ROM import, compile, match and export | KMC GCC via Rosetta on Apple Silicon; directly on Intel |
| Native window, file/folder pickers and export downloads | Cocoa and system WKWebView, no GTK or X11 |
| m2c, decomp-permuter and objdiff | Pinned Mac/Python builds |
| Other consoles and public decomp projects | Only where their pinned compiler/tool builds support this Mac |
| Linux-only PS1/PS2 period compilers | Unavailable on macOS; use a supported Linux host |
| Keeping helpers working after closing the window | Run `decomp` again to reopen; no Mac menu bar tray icon yet |

For development: `uv sync`, `uv run decomp` (separate `~/Decomp-dev` state), and `uv run pytest -q`.
On a Mac desktop, `DECOMP_TEST_COCOA=1 uv run pytest -q tests/test_macos.py` also exercises a hidden
WKWebView against a fresh app, including authentication, external links and close confirmation.
The homemade N64 demo tests need `brew install llvm lld`, with `$(brew --prefix llvm)/bin` and
`$(brew --prefix lld)/bin` on PATH, plus the free tools from `decomp setup`.


## Start

Expand Down
7 changes: 6 additions & 1 deletion ROADMAP.md
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,11 @@ Where to start on a gap:
Andreas, 129 in Ridge Racer V.
- **Consoles as packages**: one folder per console (`consoles/<id>/`), a template and a conformance test. PS1 and
GBA are public decomps only now; the git history keeps their code.
- **macOS app** (RetroReversing fork): a native Cocoa/WKWebView window with the private window user agent,
native open/save panels, downloads, Edit/Reload/Quit menus and the page's close confirmation. A uv source
installer creates a Finder app in `~/Applications`. Intel and Apple Silicon CI exercise portable regressions
and the hidden native window. KMC GCC/binutils require Rosetta on Apple Silicon; unavailable Linux-only
compilers remain unavailable. Mac workers use per-thread QoS so they don't lower the whole app's priority.
- **Linux packages**: a `.deb`, an `.rpm` and an AppImage with their own Python, built for each release.
- **Windows native app**: a WebView2 window, Start menu and desktop shortcuts, and a native tray icon.
A custom native caption follows the app's theme, with Windows resizing, snapping and drag-to-restore. Scrollbars
Expand Down Expand Up @@ -358,4 +363,4 @@ An image with % matched, functions and platform, for READMEs and posts. No game
- **Polish in the drafts.** Methods of known classes are drafted as `Class::method` in the brief; the polishing pass
doesn't use them yet.
- A Flatpak on the GNOME runtime.
- macOS.
- macOS signed/notarized distribution and a menu bar tray icon.
6 changes: 4 additions & 2 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -22,12 +22,14 @@ dependencies = [
"ninja>=1.11", # builds GameCube/Wii (dtk) and other ninja-based decomp projects
"zstandard>=0.23; sys_platform == 'linux'", # the .zst runtime old compilers need, without the zstd command
"pywebview>=6.2.1; sys_platform == 'win32'", # the tested WinForms/WebView2 bridge and native shortcut support
"pyobjc-framework-Cocoa>=11.0; sys_platform == 'darwin'", # native macOS window, dialogs, and Finder launcher
"pyobjc-framework-WebKit>=11.0; sys_platform == 'darwin'", # WKWebView with the private window user agent
"tzdata>=2025.2; sys_platform == 'win32'", # Windows has no IANA timezone database for helpers' reset times
]

[project.urls]
Homepage = "https://github.com/n-delic/decompdecomp"
Source = "https://github.com/n-delic/decompdecomp"
Homepage = "https://github.com/RetroReversing/decompdecomp"
Source = "https://github.com/RetroReversing/decompdecomp"

[project.scripts]
decomp = "decompnet.app.cli:main"
Expand Down
29 changes: 17 additions & 12 deletions site/public/install.sh
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
#!/usr/bin/env bash
# decompdecomp installer for Linux. Windows and macOS aren't supported in this version.
# decompdecomp installer for Linux and macOS (Intel and Apple Silicon).
#
# curl -fsSL https://decomp.ndelic.com/install.sh | bash
# curl -fsSL https://raw.githubusercontent.com/RetroReversing/decompdecomp/macos-support/site/public/install.sh | bash -s -- --source branch:macos-support
#
# decompdecomp installs on this computer, with uv:
# 1. installs uv, Astral's Python tool manager, if you don't have it (asks first)
Expand All @@ -15,14 +15,14 @@
#
# Options:
# --no-start install only
# --source <what> where decompdecomp comes from: "release" (default), "branch:<name>" (a branch on GitHub, for
# --source <what> where decompdecomp comes from: "release" (a tagged release), "branch:main" (default), "branch:<name>" (a branch on GitHub, for
# testing; its updates follow that branch) or a folder with decompdecomp's source. Run from a
# git checkout, the checkout is used (and updates follow its branch; main's are releases).
# The same through the environment: DECOMP_SOURCE=..., DECOMP_BRANCH=<name>.
set -euo pipefail

VERSION="1.0.6-alpha.3"
REPO="n-delic/decompdecomp"
REPO="RetroReversing/decompdecomp"
START=1
SOURCE="${DECOMP_SOURCE:-}"
[ -z "$SOURCE" ] && [ -n "${DECOMP_BRANCH:-}" ] && SOURCE="branch:${DECOMP_BRANCH}"
Expand Down Expand Up @@ -57,16 +57,17 @@ if [ -n "${BASH_SOURCE[0]:-}" ] && [ -f "${BASH_SOURCE[0]}" ]; then
CHECKOUT="$(cd "$SCRIPT_DIR/../.." && pwd)"
fi
fi
[ -n "$SOURCE" ] || SOURCE="${CHECKOUT:-release}"
[ -n "$SOURCE" ] || SOURCE="${CHECKOUT:-branch:main}"

bold "decompdecomp setup"
OS="$(uname -s)"
case "$OS" in
Linux) ;;
*) fail "decompdecomp runs on Linux, on x86-64 PCs (the games' compilers are x86 programs). Windows and macOS aren't supported in this version; a Linux virtual machine works." ;;
Linux|Darwin) ;;
*) fail "This installer supports Linux x86-64 and macOS Intel/Apple Silicon. Use the Windows installer on Windows." ;;
esac
case "$(uname -m)" in
x86_64|amd64) ;;
arm64) [ "$OS" = Darwin ] || fail "ARM is supported on macOS only" ;;
*) fail "decompdecomp needs a 64-bit Intel or AMD PC for now: the games' compilers are x86 programs, and this computer's processor is $(uname -m)" ;;
esac
command -v curl >/dev/null || fail "curl is required"
Expand Down Expand Up @@ -103,8 +104,12 @@ resolve_branch() { # the branch's newest commit, installed from GitHub's archiv
fi
}

# ------------------------------------------------------------------------------------------- on this Linux
for d in "$HOME/.local/bin" "$HOME/.cargo/bin"; do [ -x "$d/uv" ] && export PATH="$d:$PATH"; done
# ------------------------------------------------------------------------------------------- on this host
if ! command -v uv >/dev/null; then
for d in "$HOME/.local/bin" "$HOME/.cargo/bin" /opt/homebrew/bin /usr/local/bin; do
[ -x "$d/uv" ] && export PATH="$d:$PATH"
done
fi
if ! command -v uv >/dev/null; then
ask "decompdecomp is installed with uv (Astral's Python tool manager). Install uv now?" || fail "uv is needed: https://docs.astral.sh/uv/"
curl -LsSf https://astral.sh/uv/install.sh | sh
Expand Down Expand Up @@ -133,7 +138,7 @@ uv tool update-shell >/dev/null 2>&1 || true
"$BIN/decomp" install-info --channel "$CHANNEL" --branch "$BRANCH" --commit "$COMMIT" --repo "$REPO" >/dev/null

# the window: GTK and WebKitGTK 4.1 with their Python bindings, from the system (no browser involved)
if ! /usr/bin/python3 -c 'import gi; gi.require_version("Gtk", "3.0"); gi.require_version("WebKit2", "4.1")' 2>/dev/null; then
if [ "$OS" = Linux ] && ! /usr/bin/python3 -c 'import gi; gi.require_version("Gtk", "3.0"); gi.require_version("WebKit2", "4.1")' 2>/dev/null; then
. /etc/os-release 2>/dev/null || true
case " ${ID:-} ${ID_LIKE:-} " in
*" debian "*|*" ubuntu "*) WINDOW_PACKAGES="sudo apt install -y python3-gi gir1.2-gtk-3.0 gir1.2-webkit2-4.1" ;;
Expand All @@ -156,7 +161,7 @@ step "downloading the compilers and tools"
"$BIN/decomp" stop >/dev/null 2>&1 || true

# one decompdecomp at a time: an older .deb or .rpm of it would be a second one in the apps menu and on PATH
if [ -d /opt/decompdecomp ]; then
if [ "$OS" = Linux ] && [ -d /opt/decompdecomp ]; then
if command -v dpkg >/dev/null && dpkg -s decompdecomp >/dev/null 2>&1; then REMOVE="sudo apt remove -y decompdecomp"
elif command -v rpm >/dev/null && rpm -q decompdecomp >/dev/null 2>&1; then REMOVE="sudo dnf remove -y decompdecomp"
else REMOVE=""; fi
Expand All @@ -170,7 +175,7 @@ fi
bold "Done."
echo " Start it any time from your apps menu, or with: decomp"
if [ "$START" = 1 ]; then
if [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
if [ "$OS" = Darwin ] || [ -n "${DISPLAY:-}${WAYLAND_DISPLAY:-}" ]; then
nohup "$BIN/decomp" >/dev/null 2>&1 &
echo " Opening decompdecomp…"
else
Expand Down
2 changes: 1 addition & 1 deletion src/decompnet/app/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -316,7 +316,7 @@ def main(argv: list[str] | None = None) -> int:
ii.add_argument("--channel", choices=["release", "branch"], default="release")
ii.add_argument("--branch", default="")
ii.add_argument("--commit", default="")
ii.add_argument("--repo", default="n-delic/decompdecomp")
ii.add_argument("--repo", default="RetroReversing/decompdecomp")
args = ap.parse_args(argv)
__import__("decompnet").utf8_output()
return {"setup": setup, "stop": stop, "shortcut": shortcut, "update": update_cmd,
Expand Down
19 changes: 19 additions & 0 deletions src/decompnet/app/launcher.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@

import base64
import os
import plistlib
import shlex
import shutil
import subprocess
import sys
Expand Down Expand Up @@ -57,6 +59,23 @@ def install_launcher() -> str:
from its checkout."""
if edition.DEV:
return "a development copy gets no launcher: run it with `uv run decomp` in the checkout"
if sys.platform == "darwin":
bundle = Path.home() / "Applications" / "decompdecomp.app" / "Contents"
executable = bundle / "MacOS" / "decompdecomp"
resources = bundle / "Resources"
executable.parent.mkdir(parents=True, exist_ok=True)
resources.mkdir(parents=True, exist_ok=True)
# Finder doesn't read the user's shell profile. Preserve this interpreter and discover uv explicitly.
executable.write_text("#!/bin/sh\nexport PATH=" + shlex.quote(os.environ.get("PATH", "/usr/bin:/bin"))
+ "\nexec " + shlex.quote(sys.executable)
+ " -m decompnet.app.cli \"$@\"\n", encoding="utf-8")
executable.chmod(0o755)
with (bundle / "Info.plist").open("wb") as stream:
plistlib.dump({"CFBundleName": "decompdecomp", "CFBundleDisplayName": "decompdecomp",
"CFBundleIdentifier": "com.retroreversing.decompdecomp", "CFBundlePackageType": "APPL",
"CFBundleExecutable": "decompdecomp", "LSMinimumSystemVersion": "12.0",
"NSHighResolutionCapable": True}, stream)
return f"added decompdecomp to Finder ({bundle.parent})"
if sys.platform == "win32":
desktop = _windows_folder(0x10) # CSIDL_DESKTOPDIRECTORY
programs = _windows_folder(0x02) # CSIDL_PROGRAMS: the current user's Start menu
Expand Down
Loading
Loading