ci: name the missing ALSA package instead of dying at link time

When the ALSA development package is missing, `cargo xtask ci`'s audio
stage failed at link time with a bare linker error. The check now says
which package installs ALSA's contents on each supported distro, the
missing one is named in the error, and the stage's own tests pin both
the present-ALSA pass and the per-distro message.
This commit is contained in:
Kaedo17 committed 2026-10-30 01:30:50 +08:00
1 parent 03f1a1b221
commit ac0188f315
2 files changed
+68 -1

No files matched your search

+14
View File
@@ -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
+54 -1
View File
@@ -407,6 +407,40 @@ 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.
#[cfg(target_os = "linux")]
fn audio_backend() -> Result<(), String> {
let found = Command::new("pkg-config").args(["--exists", "alsa"]).status().map(|s| s.success()).unwrap_or(false);
audio_backend_hint(found)
}
#[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 +472,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 +519,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}");
}
}
}