1{ 2 description = "jev plays Zelda — a Rust app that hosts a SNES core and lets Jev (TypeSafe AI) play A Link to the Past, natively and as WASM"; 3 4 inputs = { 5 # Same branch as ~/config, and locked to the same rev, so Mesen and 6 # ffmpeg-full are the store paths the system already has rather than a 7 # second 600 MB copy. 8 nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; 9 10 # The Rust toolchain comes from fenix, not nixpkgs: the emulator core 11 # (jgenesis' snes-core) uses `float_algebraic`, stabilised after the 12 # rustc 1.95 nixos-26.05 carried — measured 2026-09-20, 16 E0658 13 # errors on 1.95, clean on 1.98.1. fenix's `stable` is the release 14 # channel, i.e. the newest released compiler; `nix flake update fenix` 15 # moves it forward. 16 fenix = { 17 url = "github:nix-community/fenix"; 18 inputs.nixpkgs.follows = "nixpkgs"; 19 }; 20 21 # The estate package set, for buck2 (see the devshell). 22 nix-pkgs.url = "git+ssh://git@github.com/deizel/nix-pkgs"; 23 nix-pkgs.inputs.nixpkgs.follows = "nixpkgs"; 24 }; 25 26 outputs = 27 { 28 nixpkgs, 29 fenix, 30 nix-pkgs, 31 ... 32 }: 33 let 34 system = "x86_64-linux"; 35 pkgs = nixpkgs.legacyPackages.${system}; 36 rust = fenix.packages.${system}; 37 38 # One toolchain for both outputs of the app: the native window and the 39 # browser build. wasm32-unknown-unknown needs only its rust-std — the 40 # linker for it (rust-lld) ships inside rustc. 41 rustToolchain = rust.combine [ 42 rust.stable.rustc 43 rust.stable.cargo 44 rust.stable.clippy 45 rust.stable.rustfmt 46 rust.stable.rust-src 47 rust.stable.rust-analyzer 48 rust.targets.wasm32-unknown-unknown.stable.rust-std 49 ]; 50 51 mesen = pkgs.callPackage ./nix/mesen.nix { 52 enforce = { 53 Video.UseSoftwareRenderer = true; 54 Debug.ScriptWindow = { 55 AllowIoOsAccess = true; 56 AllowNetworkAccess = true; 57 }; 58 }; 59 }; 60 in 61 { 62 packages.${system}.mesen = mesen; 63 64 devShells.${system}.default = pkgs.mkShell { 65 packages = [ 66 rustToolchain 67 68 # The build: buck2 drives it, reindeer turns Cargo.lock into the 69 # third-party BUCK targets. 70 # nix-pkgs' buck2, not nixpkgs': the 2026-08-22 binary drops its 71 # forkserver under test load (fixed in facebook/buck2 1cc3e05f85, 72 # released 2026-09-15); the nix-pkgs package header has the account. 73 nix-pkgs.packages.${system}.buck2 74 pkgs.reindeer 75 76 # buck2's system cxx toolchain looks up plain `clang`/`clang++` by 77 # name and links with -fuse-ld=lld; without both, every Rust binary 78 # and build script fails at the link step. Same wall ~/dashboard and 79 # ~/mobo hit. 80 pkgs.clang 81 pkgs.lld 82 83 # cpal compiles its ALSA host on every Linux build, and alsa-sys's 84 # build script finds libasound through pkg-config or panics. 85 pkgs.pkg-config 86 pkgs.alsa-lib 87 88 # Mesen 2: the reference emulator, for checking our core's RAM and 89 # picture against a known-good one. 90 mesen 91 92 # Capture. -full, not plain ffmpeg: only -full is built with XCB, 93 # so only it has the `x11grab` input device that grabs a WSLg 94 # window by id. xwininfo is what finds that id. 95 pkgs.ffmpeg-full 96 pkgs.xwininfo 97 98 # ROM archives arrive as .7z / .zip. 99 pkgs.p7zip 100 pkgs.unzip 101 102 pkgs.jq 103 104 # The zbanks C bot (third-party/c) was written to run under gdb: 105 # its assert_bp is an int3 breakpoint. gdb is how its static state 106 # (targets, goal scores) is read mid-run. 107 pkgs.gdb 108 109 # Poking the Jev HTTP API by hand. 110 pkgs.curl 111 112 # Linting tools/*.sh - code-bash.md requires shellcheck-clean. 113 pkgs.shellcheck 114 115 # "Which GPU did I actually get": glxinfo/eglinfo and vulkaninfo. 116 pkgs.mesa-demos 117 pkgs.vulkan-tools 118 ]; 119 120 # Reaching the GPU under WSL. `wsl.useWindowsDriver` links the D3D12 121 # libraries into /run/opengl-driver/lib and stops there: Mesa dlopens 122 # libd3d12.so / libdxcore.so by bare name with no runpath to that 123 # directory, and with no DRM node it never picks d3d12 unprompted. 124 # Without these two, GL, EGL and Vulkan all report llvmpipe; with 125 # them, all three report the RTX 3080 (measured 2026-09-20). Vulkan 126 # (Dozen) needs only the library path, GL needs both — and 127 # GALLIUM_DRIVER without the path is worse than neither: GL programs 128 # fail to start. 129 # 130 # The rest of the path is for our own window. winit, wgpu and 131 # xkbcommon-dl link none of their system libraries: they dlopen them 132 # by bare name at startup, so a Nix-built binary finds nothing unless 133 # the directories are on the search path. 134 # 135 # alsa-lib is the one that IS linked (cpal's ALSA host, a DT_NEEDED 136 # on libasound.so.2), but buck2's link writes no runpath to the store, 137 # so the loader still has to be told where it is: without it the 138 # binary dies before main with "libasound.so.2: cannot open shared 139 # object file" (measured 2026-09-20). 140 GALLIUM_DRIVER = "d3d12"; 141 LD_LIBRARY_PATH = "/run/opengl-driver/lib:" + pkgs.lib.makeLibraryPath [ 142 pkgs.alsa-lib 143 pkgs.wayland 144 pkgs.libxkbcommon 145 pkgs.vulkan-loader 146 pkgs.libGL 147 pkgs.libx11 148 pkgs.libxcursor 149 pkgs.libxi 150 pkgs.libxrandr 151 ]; 152 }; 153 }; 154}