Skip to content

2026-10-26 mac-slim: warnings, size, build time, cache cap, napple clean

Branch claude/mac-slim-2026-10-26-slim. Mac only; no behaviour change except the new cache cap and the new subcommand.

What changed

  • Warnings. gfx: removed three dead variables (idx in mtl_shader.m, g_pk and g_state_epoch_stage in mtl_replay.m). Studio: removed the .v5 language-mode override from Package.swift (the package now builds in Swift 6 mode), marked pick(...) @MainActor, dropped a useless try in NappleCLI.swift. Result: 0 warnings in every Obj-C file (-Wall -Wextra, runtime without -Wno-unused-parameter too) and 0 Swift warnings. No suppression was added. The runtime still prints two C warnings in files owned by code-slim (services/ncm.c want_id, a32/a32_neon.c recip_estimate_int). frontend.m still calls the CVDisplayLink API that macOS 15 deprecates (the Makefile keeps -Wno-deprecated-declarations); moving to NSView.displayLink is a behaviour change and was left out.
  • Size. Release profile: lto = "fat" (was thin), strip = "none" (rustup's rust-objcopy aborts on this toolchain and printed a warning on every build; stripping is done by strip -x in studio/build_app.sh). Runtime link: -Wl,-dead_strip -Wl,-x; duplicate -framework flags removed. studio/build_app.sh strips the four binaries it bundles. No dSYM is produced anywhere. -Os was measured and rejected: -2.5 % binary size for a risk on the frame rate. panic = "abort" was already set.
  • Build time. All five Makefiles (audio, input, frontend, gfx, runtime) now use -MMD -MP dependency files (touching kernel.c rebuilds 1 object; touching napple.h rebuilds the 59 objects that include it, not all) and build in parallel by default (MAKEFLAGS += -j<ncpu>). runtime/Makefile OPT is overridable (make OPT=-Os). cargo tree -d shows duplicates only in dev/build dependencies (bindgen/unicorn), none in the shipped CLI, so there was nothing to dedupe.
  • Cache cap. gfx/src/cache_trim.{c,h}: at gfx init the cache directory (<save-root>/<title id>/cache) is trimmed oldest-file-first to NAPPLE_GFX_CACHE_MAX_MB (default 1024, 0 = unlimited). The prewarm manifests pipelines.bin and pipelines-seed.bin are never removed. Test: gfx/tests/t_cache_trim.c. A cold 45 s boot writes 0 to 25 MB (below), so the default is far above normal use; a trim logs shader cache: N MB over the M MB cap, removed ....
  • napple clean. crates/napple-cli/src/clean.rs (+ registration and a usage line in main.rs). napple clean [--shader-cache] [--build-cache DIR] [--engine DIR] [--save-root DIR] [--dry-run] lists and removes: per-title shader caches, DIR/.napple-cache.nosync and the napple-runtime, napple-runtime-ios, napple-launcher copies inside a built game folder. Prints sizes; --dry-run removes nothing. Saves, keys, firmware and game files are never touched. 3 unit tests.
  • Format and lint. .clang-format (minimal-diff style: 4 spaces, attached braces, 160 columns) and a single formatting commit over every tracked .m (22 files, third_party excluded). studio/.swiftformat and studio/.swiftlint.yml (neither tool is installed on this Mac, so they were not run).
  • Prune. Untracked the committed studio/packaging/__pycache__/*.pyc and ignored __pycache__/ in studio/.gitignore. A scan for Obj-C functions with a single reference found none (the compiler already reports unused statics). Packaging files (install.sh, dmg_settings.py, gen_assets.py, entitlements.plist, DMG backgrounds) are all referenced by make_release.sh, release.yml, the site or the docs and were kept.

Measurements (Apple Silicon Mac, 45 s headless cold boots, NAPPLE_PERF_LOG=1, in-place data)

before after
napple CLI (release) 2,631,016 B 2,483,672 B (2,029,512 B stripped in the bundle)
napple-runtime 3,380,576 B 2,242,208 B (1,928,952 B stripped in the bundle)
napple-launcher 34,928 B 34,928 B (unchanged)
CLI clean rebuild (napple-cli only) 11 s 9 s (fat LTO is slower to link but the warning-producing strip step is gone; both builds hit warm dependency caches)
C/Obj-C components clean build (-j10, input+audio+frontend+gfx+runtime) about 4 s about 3 s
LAS frames in 45 s 2659 2622 (-1.4 %)
SMO frames 2595 2597 (+0.1 %)
ACNH frames 1281 1285 (+0.3 %)
MK8D frames 2108 2101 (-0.3 %)
Cache after the boot (shaders + archive) LAS 0, SMO 0, ACNH 9 MB (archive 5), MK8D 22 MB (archive 10) LAS 0, SMO 0, ACNH 9 MB, MK8D 25 MB
Time until the guest reports running LAS 0.77 s, SMO 0.83, ACNH 1.05, MK8D 0.65 1.37, 0.83, 1.02, 0.65 (LAS varies 0.77-1.4 s between identical runs)

All 12 boots: exit 0, no CRASH. Frame counts are within the 2 % budget for all four titles. Notes on the numbers: peak RSS is not comparable on LAS (359 to 944 MB between runs of the same binary; the other three: SMO 921/919, ACNH 1205/1515, MK8D 1606/1638 MB before/after, ACNH differing by 300 MB in one sample); "time to first frame" is approximated by the time the guest logs NotifyRunning because the runtime has no first-present log line (adding one would be a runtime change); the Studio.app, DMG and ZIP sizes and the full tools/ci_build.sh timing were not measured (it re-runs the whole pipeline and signs); the runtime/CLI clean times are wall-clock single samples.

Verified

make -C gfx test, make -C runtime test test-services test-host, input, audio, frontend make test, cargo test --workspace (all pass), swift build in Swift 6 mode with 0 warnings and swift test (37 tests), python3 tools/check_docs.py OK, four-title headless boots (above), trim exercised on MK8D (NAPPLE_GFX_CACHE_MAX_MB=1: 11 MB over, removed 10 MB), napple clean run against a real MK8D cache. Not verified: cargo clippy --workspace --all-targets fails in napple-build (four "this loop never actually loops" errors and many warnings in code owned by code-slim; the new clean.rs is clippy-clean); the iOS Simulator build compiles every file but fails at link, see the integrator file.