{ description = "crabidy — a client/server music player"; inputs = { nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable"; crane.url = "github:ipetkov/crane"; fenix = { url = "github:nix-community/fenix"; inputs.nixpkgs.follows = "nixpkgs"; }; flake-utils.url = "github:numtide/flake-utils"; }; outputs = { self, nixpkgs, crane, fenix, flake-utils, }: flake-utils.lib.eachDefaultSystem ( system: let pkgs = import nixpkgs { inherit system; }; lib = pkgs.lib; fenixPkgs = fenix.packages.${system}; # Source that keeps the .proto files crabidy-core/build.rs compiles — # crane's default cargo-source cleaning would drop them. src = lib.cleanSourceWith { src = ./.; name = "crabidy-source"; filter = path: type: (builtins.match ".*\\.proto$" path != null) || (crane.mkLib pkgs).filterCargoSources path type; }; # Only the real binary crates; never build cbd-web (a wasm crate) for a # host or aarch64 target. Headless: --no-default-features drops the # embedded web UI (its own wasm-bundle derivation is future work). workspaceBins = "-p crabidy-server -p cbd -p cbd-tui"; # --- Native toolchain / build (for `nix profile install` on x86_64, # aarch64, etc.) --- craneLib = (crane.mkLib pkgs).overrideToolchain (_: fenixPkgs.stable.toolchain); nativeArgs = { inherit src; strictDeps = true; cargoExtraArgs = "--locked --no-default-features ${workspaceBins}"; # protoc + pkg-config are build-host tools (run during the build); # with strictDeps they must be nativeBuildInputs or alsa-sys cannot # find pkg-config. alsa-lib is the actual linked library. nativeBuildInputs = [ pkgs.protobuf pkgs.pkg-config ]; buildInputs = [ pkgs.alsa-lib ]; # audio-player links libasound; yt-dlp for /youtube stays a runtime # dependency, not wired here. }; nativeDeps = craneLib.buildDepsOnly nativeArgs; crabidy = craneLib.buildPackage ( nativeArgs // { cargoArtifacts = nativeDeps; doCheck = false; # tests need a config/network; `nix flake check` can run them later } ); # --- Cross toolchain / build: static aarch64 musl (a portable binary # that runs on any aarch64 Linux, incl. a Raspberry Pi) --- muslTarget = "aarch64-unknown-linux-musl"; crossPkgs = pkgs.pkgsCross.aarch64-multiplatform-musl; crossCc = "${crossPkgs.stdenv.cc}/bin/${crossPkgs.stdenv.cc.targetPrefix}cc"; # Static alsa-lib for the target, linked into the binary. crossAlsa = crossPkgs.pkgsStatic.alsa-lib; crossToolchain = fenixPkgs.combine [ fenixPkgs.stable.rustc fenixPkgs.stable.cargo fenixPkgs.targets.${muslTarget}.stable.rust-std ]; craneLibCross = (crane.mkLib pkgs).overrideToolchain (_: crossToolchain); crossEnvTarget = "AARCH64_UNKNOWN_LINUX_MUSL"; crossArgs = { inherit src; strictDeps = true; cargoExtraArgs = "--locked --no-default-features -p crabidy-server"; CARGO_BUILD_TARGET = muslTarget; # Build scripts / proc-macros compile for the build host; deps for the # target use the cross toolchain. protoc + pkg-config are host tools. nativeBuildInputs = [ pkgs.protobuf pkgs.pkg-config ]; buildInputs = [ crossAlsa ]; depsBuildBuild = [ crossPkgs.stdenv.cc ]; # cc-rs (aws-lc-sys, rustls's crypto backend) needs the cross C # compiler; the linker is the same cross cc. Static CRT + -static so # the binary has no interpreter and runs standalone. "CC_aarch64_unknown_linux_musl" = crossCc; "CARGO_TARGET_${crossEnvTarget}_LINKER" = crossCc; "CARGO_TARGET_${crossEnvTarget}_RUSTFLAGS" = "-C target-feature=+crt-static -C link-arg=-static"; # pkg-config resolves the target's static alsa-lib for alsa-sys. PKG_CONFIG_ALLOW_CROSS = "1"; PKG_CONFIG_PATH_aarch64_unknown_linux_musl = "${crossAlsa.dev}/lib/pkgconfig"; }; crossDeps = craneLibCross.buildDepsOnly crossArgs; crabidy-server-aarch64 = craneLibCross.buildPackage ( crossArgs // { cargoArtifacts = crossDeps; doCheck = false; # cannot run aarch64 tests on an x86_64 builder } ); in { packages = { default = crabidy; inherit crabidy crabidy-server-aarch64; }; apps = { cbd = flake-utils.lib.mkApp { drv = crabidy; name = "cbd"; }; cbd-tui = flake-utils.lib.mkApp { drv = crabidy; name = "cbd-tui"; }; crabidy-server = flake-utils.lib.mkApp { drv = crabidy; name = "crabidy-server"; }; default = flake-utils.lib.mkApp { drv = crabidy; name = "cbd"; }; }; } ); }