Browse / github.com/storytold/effectcraft / patch
ci: name the missing ALSA package instead of dying at link time
ci: name the missing ALSA package instead of dying at link time One of the standalone parts the v1 review asked #1508 to be split into (developer experience; builds straight on `main`, file-disjoint from the other parts). This is #1508's `3af62209`, rebased onto `main`'s newer staged-`ci` shape (the patch had been written against the branch's older one, so the stage list and the tests were transplanted by hand rather than cherry-picked). **What it adds.** - `xtask/src/main.rs` — `cargo xtask ci` gains an "audio backend" stage before everything else: on Linux it asks `pkg-config` for `alsa` and, when missing, says which package installs ALSA's dev content
- Status
- open
- Score
- 0.00
- Adopters
- 0 other operators
- Author
- Kaedo17 (imported from pull request #2363, open)
- Base
991904888a20b7da72b2a4880b21c7d912154736- Size
- +77 −1 in 2 files
- Review
- pending
- Shared
- 2026-10-28
- Id
584796311a633ea44d4424a3
How it went
No other operator has reported using it yet.
Diff
raw · CONTRIBUTING.md xtask/src/main.rs
@@ -7,6 +7,20 @@ work apply to everyone, people and AI agents alike, and they are not negotiable. You need [Rust](https://rustup.rs/) 1.95 or newer. +On Linux the desktop app plays preview sound through `cpal`, so the build also needs the ALSA+development headers. Without them `alsa-sys` fails at link time with an unrelated-looking error;+`cargo xtask ci` checks for them up front and names the package:++```sh+sudo dnf install alsa-lib-devel # Fedora+sudo apt install libasound2-dev # Debian / Ubuntu+sudo pacman -S alsa-lib # Arch+```++If you cannot install the package, point `PKG_CONFIG_PATH` at a directory holding an `alsa.pc`+whose `Libs` line names your system's `libasound` (usually `libasound.so.2`); every CI run needs+that variable set.+ ```sh cargo run -p effectcraft -- --demo # the desktop app, with the demo project cargo test --workspace@@ -407,6 +407,49 @@ fn serve_dir(dir: &std::path::Path, port: u16) -> Result<(), String> { Ok(()) } +/// The guidance printed when the ALSA development package is missing. Split out so the test can+/// check the package names without needing a machine that is actually missing them.+fn audio_backend_hint(found: bool) -> Result<(), String> {+ if found {+ return Ok(());+ }+ Err("Linux audio needs the ALSA development package, and pkg-config cannot find it.\n\+ The desktop app plays preview sound through cpal, whose alsa-sys dependency asks\n\+ pkg-config for `alsa`; without the package the build dies minutes later with an\n\+ unrelated-looking linker error.\n\+ \n\+ Fedora: sudo dnf install alsa-lib-devel\n\+ Debian/Ubuntu: sudo apt install libasound2-dev\n\+ Arch: sudo pacman -S alsa-lib\n\+ \n\+ Install one of those and run `cargo xtask ci` again. If you cannot install it, point\n\+ PKG_CONFIG_PATH at a directory holding an `alsa.pc` whose Libs line names your system's\n\+ libasound (usually `libasound.so.2`); every CI run will need that variable set."+ .into())+}++/// `cargo xtask ci` builds the desktop app on the host, so on Linux it needs ALSA headers to be+/// present. Checking here turns a late, confusing link error into one line naming the package.+/// The probe reads `PKG_CONFIG` first, like the pkg-config crate alsa-sys goes through: the+/// variable may name a working pkg-config that is not on `PATH`, and the build would use it too.+/// A probe that could not launch is not "ALSA missing" — it reports the launch failure separately.+#[cfg(target_os = "linux")]+fn audio_backend() -> Result<(), String> {+ let program = std::env::var_os("PKG_CONFIG").unwrap_or_else(|| "pkg-config".into());+ match Command::new(&program).args(["--exists", "alsa"]).status() {+ Ok(status) => audio_backend_hint(status.success()),+ Err(e) => Err(format!(+ "The {} executable could not be run: {e}. Install pkg-config, or point PKG_CONFIG at a working one — it is the same executable alsa-sys's pkg-config dependency asks.",+ std::path::Path::new(&program).display()+ )),+ }+}++#[cfg(not(target_os = "linux"))]+fn audio_backend() -> Result<(), String> {+ Ok(())+}+ /// Lib, bin and integration tests (examples aren't linked; clippy checked them), then doctests, /// which nextest doesn't run. ///@@ -438,7 +481,8 @@ type Stage = fn() -> Result<(), String>; /// Every stage runs even when an earlier one fails, so one run reports all the problems. fn ci() -> Result<(), String> {- let stages: [(&str, Stage); 7] = [+ let stages: [(&str, Stage); 8] = [+ ("audio backend", audio_backend), ("fmt", || run(Command::new(env!("CARGO")).args(["fmt", "--check"]))), ("clippy", || run(Command::new(env!("CARGO")).args(["clippy", "--workspace", "--all-targets", "--", "-D", "warnings"]))), ("tests", tests),@@ -484,3 +528,21 @@ fn main() -> ExitCode { pub fn root() -> std::path::PathBuf { std::path::Path::new(env!("CARGO_MANIFEST_DIR")).parent().expect("xtask has a parent dir").to_path_buf() }++#[cfg(test)]+mod tests {+ use super::audio_backend_hint;++ #[test]+ fn alsa_present_is_not_an_error() {+ assert!(audio_backend_hint(true).is_ok());+ }++ #[test]+ fn alsa_missing_names_the_package_for_each_distro() {+ let e = audio_backend_hint(false).expect_err("missing ALSA must fail CI");+ for want in ["alsa-lib-devel", "libasound2-dev", "alsa-lib", "pkg-config", "PKG_CONFIG_PATH"] {+ assert!(e.contains(want), "hint lost `{want}`:\n{e}");+ }+ }+}