A modern, network-enabled music player platform built on Rockbox technology. rockboxd.tsiry-sandratraina.com
rust deno navidrome airplay libadwaita zig mpris snapcast mpd rockbox audio subsonic
2

Configure Feed

Select the types of activity you want to include in your feed.

rockboxd / flake.nix
29 kB 641 lines
1{ 2 description = "Rockbox Daemon rockboxd daemon (gRPC/GraphQL/HTTP/MPD audio server)"; 3 4 inputs = { 5 # The Rust workspace depends on path crates under the `deno` git 6 # submodule (deno/cli, deno/runtime, deno/ext/*, …). Pull the flake's 7 # own submodules into `self` so `src = ./.` carries them; without this 8 # `cargo build` fails with "failed to read deno/cli/Cargo.toml". 9 self.submodules = true; 10 11 nixpkgs.url = "github:NixOS/nixpkgs/nixos-26.05"; 12 flake-utils.url = "github:numtide/flake-utils"; 13 rust-overlay = { 14 url = "github:oxalica/rust-overlay"; 15 inputs.nixpkgs.follows = "nixpkgs"; 16 }; 17 }; 18 19 outputs = { self, nixpkgs, flake-utils, rust-overlay }: 20 # x86_64-darwin is intentionally omitted: nixpkgs 26.05 is the last 21 # release to support it, and some dev-shell deps (e.g. babashka) already 22 # drop it from meta.platforms, which breaks whole-flake evaluation 23 # (e.g. FlakeHub's cross-system `nix eval`). 24 flake-utils.lib.eachSystem [ 25 "x86_64-linux" 26 "aarch64-linux" 27 "aarch64-darwin" 28 ] (system: 29 let 30 overlays = [ (import rust-overlay) ]; 31 pkgs = import nixpkgs { inherit system overlays; }; 32 lib = pkgs.lib; 33 34 # ── Rust 1.95 stable ──────────────────────────────────────────────── 35 rustToolchain = pkgs.rust-bin.stable."1.95.0".default.override { 36 extensions = [ "rust-src" "rustfmt" "clippy" ]; 37 }; 38 39 # ── Zig 0.16.0 (fetched from upstream) ────────────────────────────── 40 zigVersion = "0.16.0"; 41 42 zigBySystem = { 43 "x86_64-linux" = { plat = "x86_64-linux"; sha256 = "70e49664a74374b48b51e6f3fdfbf437f6395d42509050588bd49abe52ba3d00"; }; 44 "aarch64-linux" = { plat = "aarch64-linux"; sha256 = "ea4b09bfb22ec6f6c6ceac57ab63efb6b46e17ab08d21f69f3a48b38e1534f17"; }; 45 "x86_64-darwin" = { plat = "x86_64-macos"; sha256 = "0387557ed1877bc6a2e1802c8391953baddba76081876301c522f52977b52ba7"; }; 46 "aarch64-darwin" = { plat = "aarch64-macos"; sha256 = "b23d70deaa879b5c2d486ed3316f7eaa53e84acf6fc9cc747de152450d401489"; }; 47 }; 48 49 zigInfo = zigBySystem.${system}; 50 51 zig = pkgs.stdenv.mkDerivation { 52 pname = "zig"; 53 version = zigVersion; 54 src = pkgs.fetchurl { 55 url = "https://ziglang.org/download/${zigVersion}/zig-${zigInfo.plat}-${zigVersion}.tar.xz"; 56 sha256 = zigInfo.sha256; 57 }; 58 dontConfigure = true; 59 dontBuild = true; 60 installPhase = '' 61 mkdir -p $out/bin $out/lib 62 cp -r lib $out/lib/zig 63 cp zig $out/bin/zig 64 ''; 65 meta = with lib; { 66 description = "Zig ${zigVersion} compiler and toolchain"; 67 homepage = "https://ziglang.org"; 68 license = licenses.mit; 69 platforms = builtins.attrNames zigBySystem; 70 }; 71 }; 72 73 # ── Platform-specific packages ─────────────────────────────────────── 74 75 # Linux: ALSA (cpal), D-Bus, libunwind — linked into rockboxd. 76 linuxPkgs = lib.optionals pkgs.stdenv.isLinux (with pkgs; [ 77 alsa-lib alsa-lib.dev 78 dbus dbus.dev 79 libunwind libunwind.dev 80 ]); 81 82 # macOS: llvm-objcopy for codec --redefine-sym inside build-headless.sh. 83 # Use .llvm (not .bintools — bintools wraps Apple ld and needs the 84 # removed apple_sdk_11_0 stub). 85 darwinPkgs = lib.optionals pkgs.stdenv.isDarwin (with pkgs; [ 86 llvmPackages_18.llvm 87 ]); 88 89 # macOS SDK sysroot for Zig's final link. The C/Rust builds use the 90 # nix cc wrapper (which injects -isysroot), but the `zig build` link 91 # step bypasses it and, with no `xcrun` in the sandbox, has an empty 92 # framework/lib search path — so linking CoreFoundation/CoreAudio/… 93 # fails with "unable to find framework". build.zig's -Dmacos-sdk adds 94 # `-F <sdk>/System/Library/Frameworks` + `-L <sdk>/usr/lib` (the SDK's 95 # .tbd stubs + libSystem). Lazy, so pkgs.apple-sdk is never forced on 96 # Linux. 97 appleSdkRoot = lib.optionalString pkgs.stdenv.isDarwin 98 "${pkgs.apple-sdk}/Platforms/MacOSX.platform/Developer/SDKs/MacOSX.sdk"; 99 100 # ── PKG_CONFIG_PATH / LD_LIBRARY_PATH helpers (devShell only) ──────── 101 102 pkgConfigDirs = lib.concatStringsSep ":" ( 103 [ 104 "${pkgs.SDL2.dev}/lib/pkgconfig" 105 "${pkgs.freetype.dev}/lib/pkgconfig" 106 "${pkgs.zlib.dev}/lib/pkgconfig" 107 "${pkgs.libusb1.dev}/lib/pkgconfig" 108 ] 109 ++ lib.optionals pkgs.stdenv.isLinux [ 110 "${pkgs.alsa-lib.dev}/lib/pkgconfig" 111 "${pkgs.dbus.dev}/lib/pkgconfig" 112 "${pkgs.libunwind.dev}/lib/pkgconfig" 113 ] 114 ); 115 116 ldLibDirs = lib.concatStringsSep ":" ( 117 [ "${pkgs.SDL2}/lib" "${pkgs.freetype}/lib" "${pkgs.zlib}/lib" ] 118 ++ lib.optionals pkgs.stdenv.isLinux [ 119 "${pkgs.alsa-lib}/lib" 120 "${pkgs.dbus}/lib" 121 "${pkgs.libunwind}/lib" 122 ] 123 ); 124 125 # ── Build source (scoped + split) ──────────────────────────────────── 126 # `src = ./.` rehashes the whole repo, so editing docs/CI/mobile apps 127 # busts the (heavy) derivations and defeats the binary cache. Split the 128 # inputs so each derivation only depends on what it actually reads: 129 # rustSrc — the cargo workspace (manifests, all members, deno/rmpc 130 # submodules). Feeds cargoDeps, the rockbox CLI, and the 131 # separately-cached Rust staticlibs. 132 # fwSrc — the firmware(make)+zig half: everything else the build 133 # reads, minus docs/CI/frontends AND minus the rust tree 134 # (so a Rust edit doesn't rebuild the firmware inputs, and 135 # the big deno tree stays out of the firmware derivation). 136 srcExcludes = lib.fileset.unions [ 137 ./.github 138 ./flake.nix 139 ./flake.lock 140 ./expo 141 ./gpui 142 ./bindings 143 ./doc 144 ./docs 145 ./manual 146 ./mintlify 147 ./memory 148 ./.devcontainer 149 ./.fluentci 150 ./dagger.json 151 ./README.md 152 ./CHANGELOG.md 153 ./CLAUDE.md 154 ./CODE_OF_CONDUCT.md 155 ./CONTRIBUTING.md 156 ./AUDIO_SETTINGS.md 157 ./HEADLESS.md 158 ./SNAPCAST.md 159 ./THREADING.md 160 ./WEBASSEMBLY.md 161 ]; 162 rustFileset = lib.fileset.unions [ 163 ./Cargo.toml ./Cargo.lock 164 ./crates ./cli ./gtk ./webui ./deno ./rmpc 165 # [patch.crates-io] hyper-rustls = { path = "vendor/hyper-rustls" } 166 ./vendor 167 ]; 168 rustSrc = lib.fileset.toSource { 169 root = ./.; 170 fileset = rustFileset; 171 }; 172 fwSrc = lib.fileset.toSource { 173 root = ./.; 174 fileset = lib.fileset.difference 175 (lib.fileset.difference ./. srcExcludes) 176 rustFileset; 177 }; 178 179 # ── WebUI static assets ────────────────────────────────────────────── 180 # Compiled from webui/rockbox/ and embedded by rockbox-server. 181 # 182 # To obtain / update npmDepsHash: 183 # nix build .#webui-assets 2>&1 | grep 'got:' 184 # then paste the printed hash below. 185 webuiAssets = pkgs.buildNpmPackage { 186 pname = "rockbox-webui"; 187 version = "0.1.0"; 188 src = ./webui/rockbox; 189 190 npmDepsHash = "sha256-zJxCDqddiRmZ7EFGtEBXPkr+A5Yq1Wtk2YQnFf+NMWQ="; 191 192 # --legacy-peer-deps: the lockfile pins graphql@15.7.2 while 193 # graphql-ws wants graphql@^15.10.1; bun/deno tolerate this, 194 # npm's strict peer resolution does not. 195 # --ignore-scripts: the `build` script produces the web dist via 196 # vite; electron is only a devDependency for the desktop variant 197 # and its postinstall tries to download a binary over the network 198 # (blocked in the sandbox). None of the web-build deps need 199 # install scripts. 200 npmFlags = [ "--legacy-peer-deps" "--ignore-scripts" ]; 201 202 # Only the compiled dist/ is needed; skip npm's default pack step. 203 installPhase = '' 204 runHook preInstall 205 mkdir -p $out 206 cp -r dist/. $out/ 207 runHook postInstall 208 ''; 209 }; 210 211 # ── S3 admin WebUI static assets ───────────────────────────────────── 212 # Compiled from crates/s3/s3webui/ and embedded by rockbox-s3 213 # (rust-embed folder $CARGO_MANIFEST_DIR/s3webui/dist in 214 # crates/s3/src/admin.rs). rockbox-s3 is a dependency of rockbox-server, 215 # so these assets must exist before the Rust build. 216 # 217 # To obtain / update npmDepsHash: 218 # nix build .#s3webui-assets 2>&1 | grep 'got:' 219 # then paste the printed hash below. 220 s3webuiAssets = pkgs.buildNpmPackage { 221 pname = "rockbox-s3-webui"; 222 version = "0.0.0"; 223 src = lib.fileset.toSource { 224 root = ./crates/s3/s3webui; 225 # Full source tree needed for `vite build`. Only the checked-in 226 # inputs are listed; generated/vendored dirs (node_modules, dist, 227 # .tanstack) are gitignored and deliberately excluded. 228 fileset = lib.fileset.unions [ 229 ./crates/s3/s3webui/package.json 230 ./crates/s3/s3webui/package-lock.json 231 ./crates/s3/s3webui/index.html 232 ./crates/s3/s3webui/vite.config.ts 233 ./crates/s3/s3webui/tsconfig.json 234 ./crates/s3/s3webui/tsconfig.app.json 235 ./crates/s3/s3webui/tsconfig.node.json 236 ./crates/s3/s3webui/tsr.config.json 237 ./crates/s3/s3webui/.oxlintrc.json 238 ./crates/s3/s3webui/src 239 ./crates/s3/s3webui/public 240 ]; 241 }; 242 243 npmDepsHash = "sha256-FKkuvP7JfewxGCe8WUjZlDgFSL48ll5/3WE4lGMdE/w="; 244 245 # Only the compiled dist/ is needed; skip npm's default pack step. 246 installPhase = '' 247 runHook preInstall 248 mkdir -p $out 249 cp -r dist/. $out/ 250 runHook postInstall 251 ''; 252 }; 253 254 # ── Vendored Cargo sources ──────────────────────────────────────────── 255 # fetchCargoVendor runs `cargo vendor` once and caches the result. 256 # Single hash covers the entire workspace including all transitive deps. 257 # 258 # To obtain / update the hash: 259 # nix build .#rockboxd 2>&1 | grep 'got:' 260 # then paste the printed hash below. 261 cargoDeps = pkgs.rustPlatform.fetchCargoVendor { 262 src = rustSrc; 263 hash = "sha256-xp2nWa6nX2Q2tV8q1cpvPHEgHPMLaJB3PFI6CaFrRE8="; 264 }; 265 266 # ── Rust staticlibs (separately cached) ────────────────────────────── 267 # librockbox_cli.a + librockbox_server.a, built in their own derivation 268 # (src = rustSrc) so the ~5-min Rust compile is cached independently of 269 # the firmware/zig link and shared via the binary cache. rockboxd's 270 # build-headless.sh consumes these with SKIP_CARGO=1. Features mirror 271 # scripts/build-headless.sh: Linux and macOS both use the default 272 # cpal-sink + Typesense (no fts5). fts5 is a BSD-only fallback there — 273 # and the flake doesn't target the BSDs — so it never applies here. 274 rustCliFeatures = "cpal-sink"; 275 rustServerFeatures = ""; 276 rockboxRustLibs = pkgs.stdenv.mkDerivation { 277 pname = "rockbox-rustlibs"; 278 version = "0.1.0"; 279 src = rustSrc; 280 281 nativeBuildInputs = with pkgs; [ 282 rustToolchain 283 gnumake 284 gcc 285 pkg-config 286 cmake 287 perl 288 python3 289 protobuf # protoc for tonic build.rs 290 rustPlatform.cargoSetupHook 291 ] ++ darwinPkgs; 292 293 # -sys crates' build scripts need these at compile time (alsa/dbus on 294 # Linux for the sink features; zlib for flate2/libz-sys). 295 buildInputs = with pkgs; [ 296 zlib zlib.dev 297 ] ++ linuxPkgs; 298 299 inherit cargoDeps; 300 301 dontUseCmakeConfigure = true; 302 303 # rockbox-server / rockbox-s3 embed the compiled web UIs via rust-embed 304 # at compile time, so the dist/ dirs must exist before cargo runs. 305 preBuild = '' 306 mkdir -p webui/rockbox/dist 307 cp -r ${webuiAssets}/. webui/rockbox/dist/ 308 mkdir -p crates/s3/s3webui/dist 309 cp -r ${s3webuiAssets}/. crates/s3/s3webui/dist/ 310 ''; 311 312 buildPhase = '' 313 runHook preBuild 314 cargo build --release --features "${rustCliFeatures}" -p rockbox-cli 315 ${if rustServerFeatures != "" then 316 ''cargo build --release --features "${rustServerFeatures}" -p rockbox-server'' 317 else 318 ''cargo build --release -p rockbox-server''} 319 runHook postBuild 320 ''; 321 322 installPhase = '' 323 runHook preInstall 324 mkdir -p $out/lib 325 cp target/release/librockbox_cli.a $out/lib/ 326 cp target/release/librockbox_server.a $out/lib/ 327 runHook postInstall 328 ''; 329 }; 330 331 # ── Prebuilt V8 for the `deno` crate (v8 / rusty_v8 130.0.2) ────────── 332 # cli/ (package `rockbox`) depends on the `v8` crate, whose build.rs 333 # downloads a prebuilt librusty_v8 archive from GitHub — blocked in the 334 # nix sandbox. Fetch it here and hand it to the crate via 335 # RUSTY_V8_ARCHIVE; RUSTY_V8_SRC_BINDING_PATH supplies the matching 336 # prebuilt bindings so the build skips bindgen/libclang entirely. 337 # 338 # To refresh after a v8 bump: read the version from Cargo.lock, then 339 # nix store prefetch-file <release-url> --json | jq -r .hash 340 rustyV8Version = "130.0.2"; 341 rustyV8BySystem = { 342 "x86_64-linux" = { triple = "x86_64-unknown-linux-gnu"; archiveHash = "sha256-ew2WZhdsHfffRQtif076AWAlFohwPo/RbmW/6D3LzkU="; bindingHash = "sha256-vbWjlLdQaqz5kBgL0XnrwhhdsPrrdHd1Q54YlxFmYKM="; }; 343 "aarch64-linux" = { triple = "aarch64-unknown-linux-gnu"; archiveHash = "sha256-p9+tHmKIM5wBABubHIAstpwfzO19ypPzOuaV4b6loCU="; bindingHash = "sha256-vbWjlLdQaqz5kBgL0XnrwhhdsPrrdHd1Q54YlxFmYKM="; }; 344 "x86_64-darwin" = { triple = "x86_64-apple-darwin"; archiveHash = "sha256-zNC0DAkMbbFM1M+t6rgKtN0QAm4ONEbCi6Sxivhf8dk="; bindingHash = "sha256-ZJlJ9b4kNwzsQrAfMrtqLc5v2f9M1QB1DsiwNlfiIbw="; }; 345 "aarch64-darwin" = { triple = "aarch64-apple-darwin"; archiveHash = "sha256-aWZ/4Q4Wttx37xOdBmTCPGP+eYGhr4CM1UkYq8pC7Qs="; bindingHash = "sha256-ZJlJ9b4kNwzsQrAfMrtqLc5v2f9M1QB1DsiwNlfiIbw="; }; 346 }; 347 rustyV8 = rustyV8BySystem.${system}; 348 rustyV8Url = kind: "https://github.com/denoland/rusty_v8/releases/download/v${rustyV8Version}/${kind}_release_${rustyV8.triple}"; 349 # rusty_v8 ships the lib gzip-compressed; RUSTY_V8_ARCHIVE wants the 350 # decompressed .a, so gunzip it into a fixed store path. 351 rustyV8Archive = pkgs.runCommand "librusty_v8_release_${rustyV8.triple}.a" { } '' 352 ${pkgs.gzip}/bin/gzip -dc ${pkgs.fetchurl { 353 url = "${rustyV8Url "librusty_v8"}.a.gz"; 354 hash = rustyV8.archiveHash; 355 }} > $out 356 ''; 357 rustyV8Binding = pkgs.fetchurl { 358 url = "${rustyV8Url "src_binding"}.rs"; 359 hash = rustyV8.bindingHash; 360 }; 361 362 # ── rockboxd derivation ─────────────────────────────────────────────── 363 # Build order mirrors scripts/build-headless.sh, minus cargo: 364 # 1. configure + make lib (headless C firmware) 365 # 2. (cargo skipped — prebuilt Rust staticlibs injected below) 366 # 3. zig build (final link) 367 rockboxd = pkgs.stdenv.mkDerivation { 368 pname = "rockboxd"; 369 version = "0.1.0"; 370 src = fwSrc; 371 372 nativeBuildInputs = with pkgs; [ 373 zig 374 gnumake 375 gcc 376 pkg-config 377 cmake 378 perl # tools/configure is a Perl script 379 python3 380 zip # firmware build packages voice/lang zips (tools/buildzip.pl) 381 unzip 382 makeWrapper # wrap rockboxd so typesense-server is on its PATH 383 ] ++ darwinPkgs; 384 385 # Libraries linked into the final binary. 386 buildInputs = with pkgs; [ 387 freetype freetype.dev 388 zlib zlib.dev 389 libusb1 libusb1.dev 390 ] ++ linuxPkgs; 391 392 # Nixpkgs' stdenv injects -Werror=format-security via the "format" 393 # hardening flag. Rockbox's splash()/splashf() are printf-style and 394 # are routinely called with a runtime format pointer (e.g. 395 # `splash(HZ/2, ID2P(LANG_TIMEOUT))`), which trips that check and 396 # turns every such call into a hard error. Upstream Rockbox never 397 # sets this flag; disable it so the firmware compiles as designed. 398 # "fortify" too: the macOS SDK's <string.h> turns strlcpy/strlcat into 399 # __builtin___str*_chk fortify macros at _USE_FORTIFY_LEVEL>0, which 400 # mangle Rockbox's own strlcpy.c/strlcat.c definitions and call sites. 401 hardeningDisable = [ "format" "fortify" ]; 402 403 # macOS defaults _USE_FORTIFY_LEVEL to 2 in the SDK even without the 404 # nixpkgs hardening flag, so force it off explicitly for the firmware 405 # C compile (the nix cc-wrapper appends NIX_CFLAGS_COMPILE; zig has 406 # its own driver and ignores it). Restores the pre-26.05 behavior. 407 NIX_CFLAGS_COMPILE = lib.optionalString pkgs.stdenv.isDarwin "-D_FORTIFY_SOURCE=0"; 408 409 # cmake is present for sub-builds that need it, but the top level 410 # has no CMakeLists.txt — rockboxd builds via make + zig 411 # (scripts/build-headless.sh). Skip cmake's default configurePhase. 412 dontUseCmakeConfigure = true; 413 414 # On macOS, hand Zig's link step the SDK framework/lib dirs (see 415 # appleSdkRoot). build-headless.sh appends $ZIG_EXTRA_ARGS to 416 # `zig build`. Empty on Linux, so it's a harmless no-op there. 417 ZIG_EXTRA_ARGS = lib.optionalString pkgs.stdenv.isDarwin "-Dmacos-sdk=${appleSdkRoot}"; 418 419 # The Rockbox build invokes helper scripts under tools/ (genlang, 420 # *.pl, *.py) whose shebangs hardcode /usr/bin/perl and /usr/bin/python, 421 # absent in the nix sandbox. Rewrite them to the nativeBuildInputs 422 # interpreters so `make` can execute them. 423 postPatch = '' 424 patchShebangs tools 425 ''; 426 427 # Inject the separately-built Rust staticlibs where zig's link step 428 # (build.zig → ../target/release) expects them; SKIP_CARGO=1 then 429 # tells build-headless.sh not to rebuild them. 430 preBuild = '' 431 mkdir -p target/release 432 cp ${rockboxRustLibs}/lib/librockbox_cli.a target/release/ 433 cp ${rockboxRustLibs}/lib/librockbox_server.a target/release/ 434 ''; 435 436 buildPhase = '' 437 runHook preBuild 438 export ZIG_GLOBAL_CACHE_DIR="$TMPDIR/zig-cache" 439 export ZIG_LOCAL_CACHE_DIR="$TMPDIR/zig-cache" 440 SKIP_CARGO=1 bash scripts/build-headless.sh 441 runHook postBuild 442 ''; 443 444 installPhase = '' 445 runHook preInstall 446 mkdir -p $out/bin 447 cp zig/zig-out/bin/rockboxd $out/bin/rockboxd 448 runHook postInstall 449 ''; 450 451 # rockboxd spawns `typesense-server` as a subprocess for the search 452 # index (crates/cli/src/lib.rs), falling back to PATH lookup when 453 # ~/.rockbox/bin/typesense-server is absent. Put typesense on PATH so 454 # an installed rockboxd works out of the box. 455 postInstall = '' 456 wrapProgram $out/bin/rockboxd \ 457 --prefix PATH : ${lib.makeBinPath [ pkgs.typesense ]} 458 ''; 459 460 meta = with lib; { 461 description = "Rockbox daemon gRPC / GraphQL / HTTP / MPD audio server"; 462 homepage = "https://github.com/tsirysndr/rockboxd"; 463 license = licenses.lgpl21; 464 platforms = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 465 mainProgram = "rockboxd"; 466 }; 467 }; 468 469 # ── rockbox CLI derivation ──────────────────────────────────────────── 470 # The `rockbox` gRPC client / CLI (cli/, cargo package "rockbox"). 471 # Pure Rust (tonic client, no C firmware linkage) — its build.rs only 472 # runs tonic_build protoc codegen. Depends on the `deno` (deno/cli) and 473 # `rmpc` (rmpc/) path crates, both git submodules carried into the 474 # source via inputs.self.submodules; their transitive registry deps are 475 # already covered by cargoDeps. 476 rockbox = pkgs.stdenv.mkDerivation { 477 pname = "rockbox"; 478 version = "0.1.0"; 479 src = rustSrc; 480 481 nativeBuildInputs = with pkgs; [ 482 rustToolchain 483 pkg-config 484 cmake 485 perl 486 python3 487 protobuf # protoc for tonic_build codegen 488 # Wires up offline Cargo registry from cargoDeps. 489 rustPlatform.cargoSetupHook 490 ] ++ darwinPkgs; 491 492 # Native libs pulled in by the deno extensions (libffi → deno_ffi, 493 # zlib → __vendored_zlib_ng / flate2). 494 buildInputs = with pkgs; [ 495 zlib zlib.dev 496 libffi libffi.dev 497 ] ++ linuxPkgs; 498 499 inherit cargoDeps; 500 501 # cmake is present for native deps that use it, but the workspace 502 # root has no CMakeLists.txt — skip cmake's default configurePhase. 503 dontUseCmakeConfigure = true; 504 505 # Use the pre-fetched V8 static lib + bindings instead of letting the 506 # v8 crate download them at build time (no network in the sandbox). 507 RUSTY_V8_ARCHIVE = rustyV8Archive; 508 RUSTY_V8_SRC_BINDING_PATH = rustyV8Binding; 509 510 buildPhase = '' 511 runHook preBuild 512 cargo build -p rockbox --release 513 runHook postBuild 514 ''; 515 516 installPhase = '' 517 runHook preInstall 518 mkdir -p $out/bin 519 cp target/release/rockbox $out/bin/rockbox 520 runHook postInstall 521 ''; 522 523 meta = with lib; { 524 description = "rockbox gRPC client / CLI for the Rockbox daemon"; 525 homepage = "https://github.com/tsirysndr/rockboxd"; 526 license = licenses.lgpl21; 527 platforms = [ "x86_64-linux" "aarch64-linux" "x86_64-darwin" "aarch64-darwin" ]; 528 mainProgram = "rockbox"; 529 }; 530 }; 531 532 in 533 { 534 # ── packages ──────────────────────────────────────────────────────────── 535 # nix build / nix shell / nix profile install all use packages.default. 536 packages = { 537 default = rockboxd; # ← what gets installed 538 inherit rockboxd rockbox; 539 rockbox-rustlibs = rockboxRustLibs; # cached separately to speed rebuilds 540 webui-assets = webuiAssets; # exposed separately to ease hash updates 541 s3webui-assets = s3webuiAssets; # exposed separately to ease hash updates 542 }; 543 544 # ── nix develop ───────────────────────────────────────────────────────── 545 devShells.default = pkgs.mkShell { 546 packages = with pkgs; [ 547 zig 548 rustToolchain 549 gnumake 550 gcc 551 pkg-config 552 cmake 553 perl 554 python3 555 zip # firmware build packages voice/lang zips (tools/buildzip.pl) 556 unzip 557 SDL2 SDL2.dev 558 freetype freetype.dev 559 zlib zlib.dev 560 libusb1 libusb1.dev 561 protobuf 562 buf 563 grpcurl 564 evans 565 typesense # rockboxd spawns typesense-server as a subprocess 566 bun 567 deno 568 # tools/console — babashka runs bb.edn tasks, clojure runs the 569 # deps.edn REPL aliases (clj -M:rebel / nREPL); both need a JDK. 570 jdk 571 clojure 572 babashka 573 ] ++ linuxPkgs ++ darwinPkgs; 574 575 shellHook = '' 576 echo "Rockbox Daemon development environment" 577 echo " Zig: $(zig version)" 578 echo " Rust: $(rustc --version)" 579 echo "" 580 echo "Headless build (cpal, no SDL):" 581 echo " cd webui/rockbox && deno install --allow-scripts && deno task build && cd ../.." 582 echo " bash scripts/build-headless.sh" 583 echo "" 584 echo "SDL build:" 585 echo " cd webui/rockbox && deno install --allow-scripts && deno task build && cd ../.." 586 echo " cd build-lib && make lib -j\$(nproc)" 587 echo " cargo build --release -p rockbox-cli -p rockbox-server" 588 echo " cd zig && zig build" 589 590 export PKG_CONFIG_PATH="${pkgConfigDirs}" 591 export ZIG_GLOBAL_CACHE_DIR="$PWD/.zig-cache" 592 export ZIG_LOCAL_CACHE_DIR="$PWD/.zig-cache" 593 '' + lib.optionalString pkgs.stdenv.isLinux '' 594 export LD_LIBRARY_PATH="${ldLibDirs}" 595 '' + lib.optionalString pkgs.stdenv.isDarwin '' 596 export DYLD_LIBRARY_PATH="${pkgs.SDL2}/lib:${pkgs.freetype}/lib:${pkgs.zlib}/lib" 597 export ROCKBOX_LLVM_OBJCOPY="$(command -v llvm-objcopy 2>/dev/null)" 598 ''; 599 }; 600 601 # ── nix run .#<name> convenience scripts ───────────────────────────── 602 apps = { 603 # Full headless build: webui → firmware → Rust → Zig 604 build-headless = { 605 type = "app"; 606 program = "${pkgs.writeShellScript "build-headless" '' 607 set -euo pipefail 608 echo "==> Step 0: WebUI" 609 (cd webui/rockbox && deno install --allow-scripts && deno task build) 610 exec bash scripts/build-headless.sh "$@" 611 ''}"; 612 }; 613 614 # SDL build: webui → make lib → cargo → zig build 615 build-sdl = { 616 type = "app"; 617 program = "${pkgs.writeShellScript "build-sdl" '' 618 set -euo pipefail 619 NCPU=$(nproc 2>/dev/null || sysctl -n hw.logicalcpu 2>/dev/null || echo 4) 620 echo "==> Step 0: WebUI" 621 (cd webui/rockbox && deno install --allow-scripts && deno task build) 622 echo "==> Step 1: firmware (build-lib)" 623 (cd build-lib && make lib -j"$NCPU") 624 echo "==> Step 2: Rust crates" 625 cargo build --release -p rockbox-cli -p rockbox-server 626 echo "==> Step 3: Zig link" 627 (cd zig && zig build) 628 echo "Done: zig/zig-out/bin/rockboxd" 629 ''}"; 630 }; 631 632 # `nix run` (no attr) runs the daemon; the built binary is wrapped so 633 # typesense-server is on its PATH. 634 default = { 635 type = "app"; 636 program = "${rockboxd}/bin/rockboxd"; 637 }; 638 }; 639 } 640 ); 641}