Chapter 28: nix, the Mesen launcher

flake.nix at the top of the repository is the devshell: every tool at an exact version. This folder holds the Nix expressions it calls, and today there is one: the wrapper that launches Mesen.

Mesen 2 is a well-regarded emulator the devshell carries as a second opinion. When our core and the game seem to disagree about a RAM address or a picture, Mesen running the same ROM settles it. Jev never plays in it.

Mesen keeps all its settings in one settings.json of about 220 KB, and rewrites the whole file on startup and exit. So the file cannot be a read-only file Nix puts in place. What can be declared is the handful of keys this project depends on, merged into the file before every launch, leaving the rest of it Mesen's:

  • Video.UseSoftwareRenderer = true. Mesen reads it before it parses the command line, so no switch can set it. The GPU renderer shows a black game surface (with working sound) whenever Mesa falls back to software rendering, which an ordinary WSLg session does; the software renderer works either way.
  • Debug.ScriptWindow.AllowIoOsAccess and AllowNetworkAccess = true, which gate LuaSocket and have no switch at all.

If there is no settings file yet, it writes a seed instead: those keys plus ConfigUpgrade = 1, the one value for which Mesen fills in controller mappings (a bare {} leaves every port unmapped), and whose existence suppresses the first-run wizard, which would otherwise hang --testRunner.

Aside: the invisible byte. Mesen writes settings.json with a UTF-8 byte-order mark, which jq rejects. The wrapper strips it with sed before merging. A test against a hand-made seed would never notice, which is why changes here are tested against a copy of a file Mesen really wrote.

Try it. nix develop -c sh -c 'cat "$(command -v Mesen)"' prints the wrapper script itself. Inside the devshell, Mesen is the only Mesen on PATH: the wrapper takes the upstream binary's name so that there is no unwrapped one to start by mistake.

For the people who maintain it

In this folder

FileWhat
mesen.nixThe 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.
README.mdThis chapter.
CLAUDE.mdHow to test a wrapper change, for agents.

← Previous: Chapter 27, hotpatch/ · Up: jevsnes · Next: Chapter 29, toolchains/ →