Add a crane flake: native packages + static aarch64 cross build
`flake.nix` packages the binaries with crane, no Docker: - `nix build .#crabidy` / `nix profile install .#crabidy` — native cbd, cbd-tui, crabidy-server for any machine with Nix; `nix run .#cbd-tui`. - `nix build .#crabidy-server-aarch64` — a fully static aarch64 musl server (no glibc/loader dependency), so it runs on stock Raspberry Pi OS. Nix cross-compiles the Rust and the C deps (ALSA, aws-lc) hermetically on an x86_64 host; the isolated derivation avoids the host-linker contamination that plagues cross-linking in a plain devenv shell. The source filter keeps crabidy-core's *.proto (crane would otherwise drop it); builds are limited to the real bin crates with -p so the wasm cbd-web crate is never built for a host/aarch64 target. Packages are headless (--no-default-features) — the embedded web UI stays a normal cargo build. The legacy container `cross` path (Cross.toml + *-Dockerfile) is left as-is; the flake is the recommended cross path. README documents both. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
d078e65a7d
commit
89d5fffd48
32
README.md
32
README.md
|
|
@ -271,6 +271,38 @@ Build the server with `--no-default-features` for a headless,
|
|||
gRPC-only binary. See [cbd-web/README.md](cbd-web/README.md) for the
|
||||
dev loop and details.
|
||||
|
||||
## Nix packages and cross-compiling
|
||||
|
||||
`flake.nix` (built with [crane](https://github.com/ipetkov/crane)) packages
|
||||
the binaries as Nix derivations — for your own machines, and cross-compiled
|
||||
for a Raspberry Pi. No Docker required.
|
||||
|
||||
Native — install on any machine with Nix:
|
||||
|
||||
```sh
|
||||
nix run .#cbd-tui # run without installing
|
||||
nix build .#crabidy # cbd, cbd-tui, crabidy-server → ./result/bin
|
||||
nix profile install .#crabidy # or github:OWNER/crabidy once pushed
|
||||
```
|
||||
|
||||
Raspberry Pi (or any aarch64 Linux) — a fully **static musl** binary, so it
|
||||
has no glibc-version or loader dependency and runs on stock Raspberry Pi OS
|
||||
(bookworm and newer):
|
||||
|
||||
```sh
|
||||
nix build .#crabidy-server-aarch64
|
||||
scp ./result/bin/crabidy-server pi:/usr/local/bin/
|
||||
```
|
||||
|
||||
Nix cross-compiles the Rust *and* the C dependencies (ALSA, aws-lc)
|
||||
hermetically on an x86_64 host — the isolated build avoids the host-linker
|
||||
pitfalls of cross-compiling in a plain shell. The flake packages are headless
|
||||
(no embedded web UI); use a normal `cargo build` if you need the bundle.
|
||||
|
||||
A container-based `cross` setup also exists (`Cross.toml` + the
|
||||
`*-Dockerfile`s) for building against Debian's glibc, but the flake is the
|
||||
recommended path.
|
||||
|
||||
## Logs
|
||||
|
||||
`cbd` and `cbd-tui` log to `~/.local/state/crabidy/` (daily files);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,116 @@
|
|||
{
|
||||
"nodes": {
|
||||
"crane": {
|
||||
"locked": {
|
||||
"lastModified": 1784564969,
|
||||
"narHash": "sha256-TkTWNhJV/8Wk3czlbz4bwHZkFCaCHPsOy+oJe4PUiXg=",
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"rev": "7930f6c291de6f83c257839d434592aa085f290a",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "ipetkov",
|
||||
"repo": "crane",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"fenix": {
|
||||
"inputs": {
|
||||
"nixpkgs": [
|
||||
"nixpkgs"
|
||||
],
|
||||
"rust-analyzer-src": "rust-analyzer-src"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1784795840,
|
||||
"narHash": "sha256-Z5cDTnG/+k7lNMMyuNH2RDWmSuGw2d3nV9AlVrpGnNE=",
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"rev": "85164e3aaadbc35cbbb4a9fef6d358b607da09fc",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-community",
|
||||
"repo": "fenix",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"flake-utils": {
|
||||
"inputs": {
|
||||
"systems": "systems"
|
||||
},
|
||||
"locked": {
|
||||
"lastModified": 1731533236,
|
||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "numtide",
|
||||
"repo": "flake-utils",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1784555310,
|
||||
"narHash": "sha256-/FCliTPgiuV1owejZFNx3Ch9irdvkOfOFl+HHZ+DrtM=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "421eebfd0ec7bccd4abe826ce62d7e6e83129493",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "NixOS",
|
||||
"ref": "nixpkgs-unstable",
|
||||
"repo": "nixpkgs",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"root": {
|
||||
"inputs": {
|
||||
"crane": "crane",
|
||||
"fenix": "fenix",
|
||||
"flake-utils": "flake-utils",
|
||||
"nixpkgs": "nixpkgs"
|
||||
}
|
||||
},
|
||||
"rust-analyzer-src": {
|
||||
"flake": false,
|
||||
"locked": {
|
||||
"lastModified": 1784667699,
|
||||
"narHash": "sha256-853teJQOgTTKRfNxcIJ53ziJOGNeg3c74PvQl5l61Jc=",
|
||||
"owner": "rust-lang",
|
||||
"repo": "rust-analyzer",
|
||||
"rev": "1174734d9c6453d13d2b5e3d578512c579ca37f1",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "rust-lang",
|
||||
"ref": "nightly",
|
||||
"repo": "rust-analyzer",
|
||||
"type": "github"
|
||||
}
|
||||
},
|
||||
"systems": {
|
||||
"locked": {
|
||||
"lastModified": 1681028828,
|
||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
"owner": "nix-systems",
|
||||
"repo": "default",
|
||||
"type": "github"
|
||||
}
|
||||
}
|
||||
},
|
||||
"root": "root",
|
||||
"version": 7
|
||||
}
|
||||
|
|
@ -0,0 +1,149 @@
|
|||
{
|
||||
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";
|
||||
};
|
||||
};
|
||||
}
|
||||
);
|
||||
}
|
||||
Loading…
Reference in New Issue