jevsnes.git / nix / README.md
1# Chapter 28: nix, the Mesen launcher
2
3`flake.nix` at the top of the repository is the devshell: every tool at an
4exact version. This folder holds the Nix expressions it calls, and today
5there is one: the wrapper that launches Mesen.
6
7[Mesen 2](https://github.com/SourMesen/Mesen2) is a well-regarded emulator
8the devshell carries as a second opinion. When our core and the game seem to
9disagree about a RAM address or a picture, Mesen running the same ROM
10settles it. Jev never plays in it.
11
12Mesen keeps all its settings in one `settings.json` of about 220 KB, and
13rewrites the whole file on startup and exit. So the file cannot be a
14read-only file Nix puts in place. What can be declared is the handful of
15keys this project depends on, merged into the file before every launch,
16leaving the rest of it Mesen's:
17
18- `Video.UseSoftwareRenderer = true`. Mesen reads it before it parses the
19  command line, so no switch can set it. The GPU renderer shows a black game
20  surface (with working sound) whenever Mesa falls back to software
21  rendering, which an ordinary WSLg session does; the software renderer
22  works either way.
23- `Debug.ScriptWindow.AllowIoOsAccess` and `AllowNetworkAccess = true`,
24  which gate LuaSocket and have no switch at all.
25
26If there is no settings file yet, it writes a seed instead: those keys plus
27`ConfigUpgrade = 1`, the one value for which Mesen fills in controller
28mappings (a bare `{}` leaves every port unmapped), and whose existence
29suppresses the first-run wizard, which would otherwise hang `--testRunner`.
30
31> **Aside: the invisible byte.** Mesen writes `settings.json` with a UTF-8
32> byte-order mark, which `jq` rejects. The wrapper strips it with `sed`
33> before merging. A test against a hand-made seed would never notice, which
34> is why changes here are tested against a copy of a file Mesen really wrote.
35
36> **Try it.** `nix develop -c sh -c 'cat "$(command -v Mesen)"'` prints the
37> wrapper script itself. Inside the devshell, `Mesen` is the only Mesen on
38> `PATH`: the wrapper takes the upstream binary's name so that there is no
39> unwrapped one to start by mistake.
40
41## For the people who maintain it
42
43### In this folder
44
45| File | What |
46| --- | --- |
47| [mesen.nix](mesen.nix) | The `Mesen` launcher: merges the `enforce` attrset (set in `../flake.nix`) into Mesen's settings.json, seeds a missing one, then execs the real emulator. Its header comment is the full rationale, with file and line citations into the Mesen source. |
48| [README.md](README.md) | This chapter. |
49| [CLAUDE.md](CLAUDE.md) | How to test a wrapper change, for agents. |
50
51← Previous: [Chapter 27, hotpatch/](../tools/hotpatch/) · Up: [jevsnes](../) · Next: [Chapter 29, toolchains/](../toolchains/) →