65816-llvm-mos/docs/INSTALL.md
2026-05-25 21:00:32 -05:00

477 lines
18 KiB
Markdown

# Installing llvm816
This document covers everything you need to get from a fresh Ubuntu /
Debian install to a working W65816 Clang compiler + Apple IIgs MAME
emulator + matching runtime libraries. The entire toolchain installs
*locally* under your repo checkout — nothing goes into `/usr/local`,
`/opt`, or your home directory beyond a few standard apt packages.
If you've never built LLVM or used a cross-compiler before, follow this
document top to bottom. If you're comfortable, the
[One-command install](#one-command-install) section gets you running
in 5-10 minutes.
---
## What you'll have when it's done
After install, the `llvm816/` directory tree contains everything:
| Component | Disk usage (approx) | Purpose |
|---|---:|---|
| `tools/llvm-mos/` | 5.0 GB | LLVM source tree (clone of llvm-mos). Our backend source is *symlinked* into here at build time. |
| `tools/llvm-mos-build/` | 1.4 GB | Compiled clang/llc/llvm-mc binaries. This is where you actually run the compiler from. |
| `tools/llvm-mos-sdk/` | 400 MB | Prebuilt llvm-mos SDK (the original 6502 distribution). Mostly unused by us; kept as a reference baseline. |
| `tools/calypsi/` | 580 MB | Commercial Calypsi 5.16 65816 C compiler — installed for output-quality comparisons in `compare/`. |
| `tools/orca-c/` | 10 MB | Apple's official ORCA/C compiler source — header reference for the IIgs Toolbox bindings. |
| `tools/gsos/` | 13 MB | Apple GS/OS 6.0.2 / 6.0.4 disk images for booting under MAME. |
| `tools/mame/roms/` | 1.5 MB | Apple IIgs ROM 01 + ROM 03 (downloaded from archive.org). |
| **Total** | **~7-8 GB** | |
Plus a few system-wide apt packages (cmake, ninja, MAME, ...). These
are listed up front in [System requirements](#system-requirements) so
you can audit them before installing.
The compiler binary itself is at
**`tools/llvm-mos-build/bin/clang`** — you'll see this path referenced
everywhere.
---
## System requirements
- **OS:** Ubuntu 22.04 LTS or 24.04 LTS (other Debian-based distros work
if you can find equivalents for the apt packages). Pure Arch / Fedora
installs need package-name translation but the project itself is
distro-neutral.
- **CPU:** any 64-bit x86 or ARM Linux machine. We're cross-compiling,
so the host CPU only matters for build speed.
- **Disk:** ~10 GB free total (~5 GB during build, ~7 GB after install
with all reference compilers). If you skip Calypsi (`--skip-calypsi`),
knock 580 MB off.
- **RAM:** 8 GB minimum for the default install (downloads a prebuilt
llvm-mos SDK). 16 GB recommended if you use `--build-llvm` (compiles
LLVM from source).
- **Time:** ~5 minutes for the default (prebuilt) path; 30-60 minutes
for `--build-llvm` on a modern laptop (depends on core count).
- **Network:** the install pulls ~500 MB of binaries from GitHub,
archive.org, and the Calypsi releases page. No proxy support
baked in — set `http_proxy` / `https_proxy` if you need one.
### apt packages installed
`scripts/installDeps.sh` runs `sudo apt-get install` for these
packages:
| Package | Why it's needed |
|---|---|
| `build-essential` | gcc, make, libc-dev — needed to build LLVM and our linker |
| `cmake`, `ninja-build` | LLVM's build system |
| `clang`, `lld` | Bootstrap a host clang (faster LLVM build than gcc) |
| `python3`, `python3-pip` | Build-time scripting + LLVM's lit test runner |
| `git` | Cloning the llvm-mos source tree |
| `zlib1g-dev`, `libedit-dev`, `libxml2-dev`, `libncurses-dev` | LLVM link-time deps |
| `zstd`, `xz-utils`, `unzip`, `tar` | Unpacking downloaded archives |
| `lua5.4`, `liblua5.4-dev` | MAME's autoboot scripting (used by the smoke harness) |
| `curl`, `ca-certificates` | Downloading installer payloads |
| `mame`, `mame-tools` | Apple IIgs emulator |
All packages are installed with `--no-install-recommends`, so the
total apt footprint is bounded. If you want to inspect or audit before
running, see `scripts/installDeps.sh` for the exact list.
> **Requires sudo:** the apt install step needs root. `setup.sh`
> prompts via `sudo` once and then continues without root for everything
> else.
---
## One-command install
```bash
git clone <this-repo-url> llvm816
cd llvm816
./setup.sh
```
That's it. `setup.sh` runs five stages in order:
| Stage | Script | What it does | Time |
|---|---|---|---|
| 1/5 | `installDeps.sh` | `sudo apt-get install` the packages listed above. | ~1 min |
| 2/5 | `installLlvmMos.sh` | Clone `llvm-mos` source (5 GB), download prebuilt llvm-mos SDK (400 MB), build our W65816 clang under `tools/llvm-mos-build/`. Without `--build-llvm`, downloads the prebuilt SDK only; clang for our target is then built incrementally. | ~5 min (no source build) or 30-60 min (with `--build-llvm`) |
| 3/5 | `installMame.sh` | Install MAME via apt, download `apple2gs.zip` (ROM 03) and `apple2gsr1.zip` (ROM 01) into `tools/mame/roms/`. | ~30 s |
| 4/5 | `installCalypsi.sh` | Download Calypsi 5.16 .deb, extract its payload into `tools/calypsi/` (no system-wide install). | ~30 s |
| 5/5 | `installOrcaC.sh` | Shallow clone of byteworksinc's ORCA/C repo into `tools/orca-c/` for toolbox header reference. | ~15 s |
After each stage, the script prints `=== N/5 stage-name ===` so you
can follow progress. At the end it runs `verify.sh` which sanity-
checks every tool was installed.
A successful install ends with:
```
[llvm816] setup complete
```
### `setup.sh` flags
| Flag | Effect |
|---|---|
| `--build-llvm` | Build clang from source (30-60 min) instead of using the prebuilt SDK. Required if you plan to modify the W65816 backend. |
| `--skip-deps` | Don't run apt (use if you've already installed the system packages). |
| `--skip-llvm` | Skip the LLVM clone + build. Useful for iterating on other parts. |
| `--skip-mame` | Skip MAME + ROM download. |
| `--skip-calypsi` | Skip Calypsi (saves 580 MB if you don't need the comparison benchmarks). |
| `--skip-orca` | Skip ORCA/C (saves ~10 MB; only needed if you regenerate `iigs/toolbox.h`). |
| `--skip-verify` | Don't run the post-install verification check. |
| `--verify-only` | Just run the verification check, don't install anything. |
---
## What gets installed where
After a complete `setup.sh` run, your `llvm816/` directory looks like
this:
```
llvm816/ ← your repo checkout
├── setup.sh ← the installer you just ran
├── README.md
├── docs/ ← documentation (you're reading INSTALL.md)
│ ├── INSTALL.md
│ ├── USAGE.md
│ └── multiSegmentPlan.md
├── src/ ← OUR backend source (W65816 target)
│ ├── llvm/lib/Target/W65816/ ← ~41 files; symlinked into tools/llvm-mos
│ ├── clang/ ← clang frontend hooks
│ └── link816/ ← linker source
├── patches/ ← upstream-llvm-mos patches
├── runtime/ ← C standard library + crt0
│ ├── include/ ← <stdio.h>, <stdlib.h>, <iigs/toolbox.h> ...
│ ├── src/ ← .c and .s sources
│ └── *.o ← built object files (after runtime/build.sh)
├── scripts/ ← install + run + bench scripts
├── benchmarks/ ← cycle-count benchmarks
├── compare/ ← side-by-side ours-vs-Calypsi assembly
├── demos/ ← example IIgs programs (helloBeep, reversi, ...)
├── tests/ ← larger compile-only tests (e.g. tests/lua/)
└── tools/ ← everything installed by setup.sh
├── llvm-mos/ (5.0 GB) — LLVM source tree clone
│ └── llvm/lib/Target/W65816/ ← symlinks point back to ../../src/llvm/lib/Target/W65816/
├── llvm-mos-build/ (1.4 GB) — cmake build directory
│ └── bin/
│ ├── clang → clang-23 ← THE COMPILER ⭐
│ ├── clang++ ← C++ driver
│ ├── clang-23 ← actual binary
│ ├── llc ← standalone codegen (.ll → .s)
│ ├── llvm-mc ← standalone assembler
│ ├── llvm-objdump ← disassembler
│ └── ... (FileCheck, llvm-readobj, opt, etc.)
├── llvm-mos-sdk/ (400 MB) — prebuilt llvm-mos SDK
├── link816 (~120 KB) — OUR LINKER ⭐
├── omfEmit (~70 KB) — OMF v2.1 emitter for GS/OS Loader
├── cadius/ — Apple ProDOS / GS/OS disk image tool
├── calypsi/ (580 MB) — Calypsi 5.16 reference compiler
├── orca-c/ (10 MB) — ORCA/C compiler (header reference)
├── gsos/ (13 MB) — GS/OS 6.0.2 / 6.0.4 disk images
├── mame/
│ └── roms/ (1.5 MB) — apple2gs ROM 01 + ROM 03
└── venv/ — Python venv (used by genToolbox.py)
```
The starred items (`clang` and `link816`) are the two binaries you
interact with daily. See [USAGE.md](USAGE.md) for how to use them.
### Why so much LLVM?
`tools/llvm-mos/` is a full LLVM source tree (about 5 GB). We need it
because our W65816 backend is part of LLVM — we build it as a
target inside LLVM's normal codegen pipeline. Our backend lives in
`src/llvm/lib/Target/W65816/`; `scripts/applyBackend.sh` symlinks it
into the LLVM source tree under `tools/llvm-mos/llvm/lib/Target/W65816/`
so cmake picks it up.
The size is unavoidable if you want to rebuild the backend. If you
don't plan to modify it, you could `rm -rf tools/llvm-mos` after a
successful build — but you'd have to re-clone to fix bugs.
### What's outside `tools/`?
Only the apt packages from [System requirements](#system-requirements).
`apt-get remove mame mame-tools` cleans those up if you want to fully
uninstall.
Importantly, the installer does **NOT** touch:
- `/usr/local/` (no `make install`)
- `/opt/` (no FHS-style component install)
- `~/.mame/` (we use `-rompath` to point at `tools/mame/roms/` instead)
- `~/.cache/` (downloads go to the repo-local `.cache/`)
To uninstall completely:
```bash
rm -rf llvm816/
sudo apt-get remove mame mame-tools build-essential cmake ninja-build \
clang lld lua5.4 liblua5.4-dev # if you want apt deps gone too
```
---
## Step-by-step (if `setup.sh` fails)
You can run each install script in isolation if a stage breaks. They're
idempotent — running them twice is a no-op (or a "fetch updates" for the
LLVM clone).
```bash
bash scripts/installDeps.sh # apt packages
bash scripts/installLlvmMos.sh # llvm-mos clone + prebuilt SDK
bash scripts/installLlvmMos.sh --build # also build clang/llc (slow)
bash scripts/installMame.sh # MAME + apple2gs ROMs
bash scripts/installCalypsi.sh # reference compiler (optional)
bash scripts/installOrcaC.sh # reference compiler (optional)
bash scripts/verify.sh # sanity-check everything
```
If you only want to *build* C programs (no benchmarks, no comparisons),
`installCalypsi.sh` and `installOrcaC.sh` are skippable.
### Building W65816 clang from source
The default install pulls a *prebuilt* llvm-mos SDK but builds our
W65816 backend incrementally on top. If you want to build everything
from source (recommended for backend development):
```bash
./setup.sh --build-llvm
```
This adds about 30-60 minutes to install time but means you can edit
files under `src/llvm/lib/Target/W65816/` and rebuild quickly.
After the initial source build, incremental rebuilds after editing
backend code take ~30 seconds:
```bash
ninja -C tools/llvm-mos-build llc clang
```
`scripts/applyBackend.sh` re-runs the symlink-into-LLVM step if you've
added new files under `src/llvm/lib/Target/W65816/`.
---
## Verifying the install
`setup.sh` automatically runs `scripts/verify.sh` at the end — it walks
every installed tool and checks each runs. If anything fails it shows
which step failed (e.g. `[FAIL] llvm-mos source tree` means the clone
didn't land where expected).
To re-verify later:
```bash
./setup.sh --verify-only
```
For a real end-to-end test (compiles and runs a tiny C program through
the entire pipeline):
```bash
# Build the runtime libraries (libc, libgcc, etc.) — ~30 s
bash runtime/build.sh
# Compile + disassemble a small C demo
bash scripts/cDemo.sh
# Run the full smoke test suite (~150 checks, takes ~3 min)
bash scripts/smokeTest.sh
```
A successful smoke test ends with:
```
[llvm816] all smoke checks passed
```
If smoke passes, your install is good.
---
## Updating
```bash
cd llvm816
git pull # update our backend source
bash scripts/applyBackend.sh # re-symlink into tools/llvm-mos
ninja -C tools/llvm-mos-build llc clang
bash runtime/build.sh
```
If you want a fully clean rebuild (e.g., to chase a "stale .o" bug):
```bash
rm -rf tools/llvm-mos-build
./setup.sh --build-llvm
```
---
## Uninstalling
The toolchain is fully contained under `llvm816/`:
```bash
rm -rf llvm816/
sudo apt-get remove mame mame-tools # if you want MAME gone too
# (also remove build-essential, cmake, etc., if they're not used elsewhere)
```
Nothing remains outside the repo.
---
## Troubleshooting
### `cmake: command not found` / `ninja: command not found`
The apt packages aren't installed yet:
```bash
bash scripts/installDeps.sh
```
### `clang: error: unable to find target 'w65816'`
You're invoking a clang that doesn't include our backend. Likely
causes:
1. You're using the **system** clang (`/usr/bin/clang`). The system
clang doesn't know W65816. Use the full path:
```bash
./tools/llvm-mos-build/bin/clang --target=w65816 ...
```
2. The build didn't complete. Check:
```bash
ls -la tools/llvm-mos-build/bin/clang # should be a symlink to clang-23
./tools/llvm-mos-build/bin/clang --print-targets | grep -i 65816
```
If the binary's missing or no W65816 target appears, rebuild:
```bash
bash scripts/applyBackend.sh
ninja -C tools/llvm-mos-build llc clang
```
3. You're using the prebuilt SDK (`tools/llvm-mos-sdk/bin/...`). That's
the original llvm-mos SDK; our W65816 target lives only in our
*source build* at `tools/llvm-mos-build/bin/`.
### `linkage error: missing __umulhisi3` / `missing __mulsi3` / similar
You forgot to link `runtime/libgcc.o`. See
[USAGE.md § Linking](USAGE.md#linking). Typical link line:
```bash
./tools/link816 -o myprog.bin --text-base 0x1000 \
runtime/crt0.o runtime/libc.o runtime/libgcc.o myprog.o
```
### `ROMs not found at runtime`
The apple2gs ROM download from archive.org occasionally fails. Re-run
the installer (it's idempotent and skips already-present ROMs):
```bash
bash scripts/installMame.sh
ls tools/mame/roms/ # should contain apple2gs.zip and apple2gsr1.zip
```
If you invoke `mame` directly without using our `runInMame.sh` wrapper,
pass `-rompath tools/mame/roms` so it finds them.
### MAME pops up a window I don't want
The supplied `scripts/runInMame.sh` runs headless (`-video none` plus
`SDL_VIDEODRIVER=dummy`). If you're calling `mame` yourself, add those
flags.
### `git: refusing to fetch into ...` for llvm-mos
`installLlvmMos.sh` refuses to refresh the LLVM clone if it has local
modifications or is on a non-`main` branch — because our backend
symlinks are stitched into the clone and a destructive refresh would
stomp them.
If you really want to refresh from upstream:
```bash
bash scripts/updateLlvmMos.sh
```
That script handles the symlinks safely.
### Disk fills up during `--build-llvm`
A full LLVM build needs ~12 GB of temporary build artifacts (cmake's
intermediate `.o` files, .a archives, etc.) on top of the 5 GB source
tree. Free ~15 GB before running `--build-llvm`.
Once the build completes, the *intermediate* artifacts under
`tools/llvm-mos-build/CMakeFiles/` can be deleted — the binaries
under `tools/llvm-mos-build/bin/` are self-contained:
```bash
rm -rf tools/llvm-mos-build/CMakeFiles tools/llvm-mos-build/lib
```
But this disables incremental rebuilds. Re-running `--build-llvm`
recreates everything.
### Calypsi install fails / I don't want it
Calypsi is only used by the `compare/` benchmarks for output-quality
comparison. Everything else works without it. Skip it:
```bash
./setup.sh --skip-calypsi
```
### MAME version mismatch warnings
We're tested against MAME 0.240 ROMs running on whatever MAME apt ships
with (typically 0.260+). Cross-version ROMs usually work but you may
see "BAD CHECKSUM" warnings. These are warnings, not errors — boot
proceeds normally.
If you want a clean match, the ROM 03 set from MAME 0.240 is
`apple2gs.zip` mirrored on archive.org; the installer pulls that exact
version.
### Smoke test fails on a single check
If `scripts/smokeTest.sh` fails one check but otherwise looks fine, it
might be MAME timing. Try:
```bash
MAME_CHECK_FRAME=600 MAME_SECS=12 bash scripts/smokeTest.sh
```
Some demos (especially the larger toolbox ones) need more wall-clock
time to fully draw. Persistent failures are real bugs — file an issue
with the failing check's output.
---
## Where to go next
- **Compile your first program:** [USAGE.md](USAGE.md).
- **Backend internals (if you're hacking on the compiler):**
[LLVM_65816_DESIGN.md](../LLVM_65816_DESIGN.md).
- **Feature matrix (what's implemented):** [STATUS.md](../STATUS.md).