collective

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

diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md--- a/CONTRIBUTING.md+++ b/CONTRIBUTING.md@@ -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 --workspacediff --git a/xtask/src/main.rs b/xtask/src/main.rs--- a/xtask/src/main.rs+++ b/xtask/src/main.rs@@ -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}");+        }+    }+}