{ description = "PeerSpeak — decentralized P2P voice chat (Rust/iroh/PipeWire/Opus/iced)"; # Pinned to the same channel the hosts run (nixos-config tracks nixos-26.05), # so the libraries this shell links and dlopens are built against the same # release as the PipeWire daemon and Vulkan ICD actually running on the # machine. Floating to unstable here would reintroduce precisely the # client/server version skew the pin exists to prevent. inputs.nixpkgs.url = "github:nixos/nixpkgs/nixos-26.05"; outputs = { nixpkgs, ... }: let system = "x86_64-linux"; pkgs = nixpkgs.legacyPackages.${system}; # Libraries that iced/winit/wgpu open with dlopen at RUNTIME rather than # linking at build time. Because nothing links them, they never land in # the binary's rpath — under `cargo run` the loader finds them only # through LD_LIBRARY_PATH. Leaving them out builds fine and then panics # at window creation, which is a genuinely confusing failure, so they are # listed explicitly instead of discovered the hard way. runtimeLibs = with pkgs; [ vulkan-loader # wgpu's Vulkan backend (iced's renderer) libxkbcommon # winit keyboard handling wayland # wayland-sys, dlopen'd on a Wayland session libx11 # x11-dl, dlopen'd on the X11 fallback path libxcursor libxrandr libxi ]; # Screen sharing spawns pixelpass as a CHILD PROCESS, and pixelpass in # turn drives GStreamer as a subprocess. That makes these tools a # dependency of peerspeak's own test suite, not just of pixelpass: # `tests/screenshare_host_fault.rs` starts a real pixelpass host, which # aborts at its preflight if gst-launch-1.0 is missing. # # Deliberately duplicated from pixelpass's flake rather than importing it # as an input. The two projects are mutually optional by design — neither # is a dependency of the other, and the coupling is a runtime subprocess # contract. Making one flake consume the other would quietly reintroduce # exactly the build-level dependency that rule exists to prevent. screenshareTools = with pkgs; [ gst_all_1.gstreamer gst_all_1.gst-plugins-base gst_all_1.gst-plugins-good gst_all_1.gst-plugins-bad gst_all_1.gst-plugins-ugly gst_all_1.gst-libav pipewire # pipewiresrc (Wayland capture; ships in this pkg) ]; in { devShells.${system}.default = pkgs.mkShell { nativeBuildInputs = with pkgs; [ rustc cargo rustfmt clippy # The supply-chain gates .gitea/workflows/ci.yml runs, so the same # checks are reproducible locally before a push. These were `cargo # install`ed on the CachyOS side, which does not carry over — those # binaries link that distro's glibc and will not run here. # cargo-deny reads deny.toml; cargo-audit reads .cargo/audit.toml. cargo-audit cargo-deny # Debian packaging (`cargo deb --no-build`). Note the .deb itself # should still be built inside a Debian/Ubuntu distrobox so the # binary links that distro's glibc — see the packaging notes in # Cargo.toml. cargo-deb pkg-config # pipewire-sys and libspa-sys generate their bindings with bindgen, # which needs a real libclang present at build time. clang # audiopus_sys prefers the system libopus via pkg-config but falls # back to a vendored CMake build; cmake keeps that fallback working # rather than failing obscurely inside a build script. cmake # build.rs shells out to `git rev-parse --short=8 HEAD` to stamp # PEERSPEAK_GIT_SHORT into the binary (surfaced in Settings). git ] ++ screenshareTools ++ [ pkgs.pulseaudio # `pactl`, used by pixelpass's audio routing pkgs.mpv # the screen-share viewer ]; buildInputs = with pkgs; [ alsa-lib # alsa-sys, pulled in by rodio/cpal libopus # audiopus_sys, linked dynamically pipewire # pipewire-sys + libspa-sys: the Linux audio backend ] ++ runtimeLibs; # bindgen finds libclang through this variable specifically — having # clang on PATH is not sufficient. LIBCLANG_PATH = "${pkgs.llvmPackages.libclang.lib}/lib"; LD_LIBRARY_PATH = pkgs.lib.makeLibraryPath runtimeLibs; # NixOS keeps every GStreamer plugin in its own store path, so the # gst-launch-1.0 that pixelpass spawns discovers them ONLY through this # search path. Same reasoning as hosts/darp5 and hosts/cazen in # nixos-config. GST_PLUGIN_SYSTEM_PATH_1_0 = pkgs.lib.makeSearchPathOutput "lib" "lib/gstreamer-1.0" screenshareTools; # Only greet an interactive shell. shellHook also runs under # `nix develop --command …`, where printing this would interleave the # banner with the command's own output. shellHook = '' if [ -t 1 ]; then echo "peerspeak — rustc $(rustc --version | cut -d' ' -f2) / cargo $(cargo --version | cut -d' ' -f2)" echo " cargo build --release build" echo " cargo test lib tests" echo " cargo clippy --all-targets -- -D warnings lint" echo echo "Screen sharing spawns pixelpass as a child process — it must be" echo "on PATH. Build it from ../pixelpass and add its target/release." fi ''; }; }; }