mirror of
https://github.com/fabro-sh/fabro.git
synced 2026-08-28 05:27:41 +00:00
feat(release): add x86_64 and aarch64 musl Linux targets
Extend the release matrix to two statically-linked musl variants so Alpine and other musl-based Linux hosts can install without glibc. Homebrew and the Docker image remain glibc-only. - release.yml: add x86_64-unknown-linux-musl (ubuntu-24.04) and aarch64-unknown-linux-musl (ubuntu-24.04-arm) matrix rows with musl-tools, CC_*_musl, CARGO_TARGET_*_LINKER, and LIBZ_SYS_STATIC - Cargo.toml: enable git2 vendored-libgit2 so libgit2 compiles from source for every target (needed because musl cannot link against Ubuntu's glibc-built libgit2-dev) - install.sh: check `ldd --version` for "musl" and rewrite the target from -gnu to -musl so Alpine users get the right tarball - upgrade.rs: add detect_linux_libc() / parse_ldd_libc() helper and route detect_target() Linux arms through it, with unit tests covering glibc, musl, empty, and unknown output - tests/it: extend target regex in the dry-run snapshot filter Ubuntu 24.04 is required for the musl runner: 22.04 ships musl 1.2.2 which SIGSEGVs statically-linked x86_64 test binaries at startup. Confirmed against graphviz-sys CI before landing here. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
parent
5335f8bcb4
commit
828d686a6f
5 changed files with 101 additions and 6 deletions
16
.github/workflows/release.yml
vendored
16
.github/workflows/release.yml
vendored
|
|
@ -42,11 +42,27 @@ jobs:
|
|||
runner: ubuntu-latest
|
||||
- target: aarch64-unknown-linux-gnu
|
||||
runner: ubuntu-22.04-arm
|
||||
- target: x86_64-unknown-linux-musl
|
||||
runner: ubuntu-24.04
|
||||
musl: true
|
||||
- target: aarch64-unknown-linux-musl
|
||||
runner: ubuntu-24.04-arm
|
||||
musl: true
|
||||
env:
|
||||
CC_x86_64_unknown_linux_musl: musl-gcc
|
||||
CC_aarch64_unknown_linux_musl: musl-gcc
|
||||
CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc
|
||||
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc
|
||||
LIBZ_SYS_STATIC: "1"
|
||||
steps:
|
||||
- uses: actions/checkout@de0fac2e4500dabe0009e67214ff5f5447ce83dd # v6.0.2
|
||||
with:
|
||||
persist-credentials: false
|
||||
|
||||
- name: Install musl toolchain
|
||||
if: matrix.musl
|
||||
run: sudo apt-get update && sudo apt-get install -y musl-tools
|
||||
|
||||
- name: Set up Rust
|
||||
run: |
|
||||
rustup toolchain install stable --profile minimal --no-self-update
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ tar = "0.4"
|
|||
cli-table = { version = "0.5", default-features = false }
|
||||
console = "0.15"
|
||||
dialoguer = "0.12"
|
||||
git2 = { version = "0.20", default-features = false }
|
||||
git2 = { version = "0.20", default-features = false, features = ["vendored-libgit2"] }
|
||||
tracing = "0.1"
|
||||
tracing-subscriber = { version = "0.3", features = ["fmt", "env-filter"] }
|
||||
tracing-appender = "0.2"
|
||||
|
|
|
|||
|
|
@ -57,6 +57,9 @@ case "$OS" in
|
|||
aarch64) TARGET="aarch64-unknown-linux-gnu" ;;
|
||||
*) error "Unsupported Linux architecture: $ARCH. Supported: x86_64, aarch64" ;;
|
||||
esac
|
||||
if ldd --version 2>&1 | grep -qi musl; then
|
||||
TARGET="${TARGET%-gnu}-musl"
|
||||
fi
|
||||
;;
|
||||
*)
|
||||
error "Unsupported OS: $OS. Supported platforms: macOS (Apple Silicon), Linux (x86_64, aarch64)"
|
||||
|
|
|
|||
|
|
@ -277,12 +277,54 @@ async fn select_backend() -> Backend {
|
|||
fn detect_target() -> Result<&'static str> {
|
||||
match (std::env::consts::OS, std::env::consts::ARCH) {
|
||||
("macos", "aarch64") => Ok("aarch64-apple-darwin"),
|
||||
("linux", "x86_64") => Ok("x86_64-unknown-linux-gnu"),
|
||||
("linux", "aarch64") => Ok("aarch64-unknown-linux-gnu"),
|
||||
("linux", "x86_64") => Ok(match detect_linux_libc() {
|
||||
Libc::Musl => "x86_64-unknown-linux-musl",
|
||||
Libc::Gnu => "x86_64-unknown-linux-gnu",
|
||||
}),
|
||||
("linux", "aarch64") => Ok(match detect_linux_libc() {
|
||||
Libc::Musl => "aarch64-unknown-linux-musl",
|
||||
Libc::Gnu => "aarch64-unknown-linux-gnu",
|
||||
}),
|
||||
(os, arch) => bail!("unsupported platform: {os}/{arch}"),
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq)]
|
||||
enum Libc {
|
||||
Gnu,
|
||||
Musl,
|
||||
}
|
||||
|
||||
/// Parse `ldd --version` output to determine the host libc flavor.
|
||||
///
|
||||
/// glibc's ldd writes to stdout ("ldd (Ubuntu GLIBC 2.35...)");
|
||||
/// musl's ldd writes to stderr ("musl libc (x86_64)\nVersion 1.2.4").
|
||||
/// Callers concatenate both streams before passing in.
|
||||
fn parse_ldd_libc(output: &str) -> Libc {
|
||||
if output.to_ascii_lowercase().contains("musl") {
|
||||
Libc::Musl
|
||||
} else {
|
||||
Libc::Gnu
|
||||
}
|
||||
}
|
||||
|
||||
fn detect_linux_libc() -> Libc {
|
||||
#[expect(
|
||||
clippy::disallowed_methods,
|
||||
reason = "one-shot libc detection at upgrade startup; async overhead is unwarranted"
|
||||
)]
|
||||
let result = std::process::Command::new("ldd").arg("--version").output();
|
||||
let Ok(output) = result else {
|
||||
return Libc::Gnu;
|
||||
};
|
||||
let combined = format!(
|
||||
"{}{}",
|
||||
String::from_utf8_lossy(&output.stdout),
|
||||
String::from_utf8_lossy(&output.stderr),
|
||||
);
|
||||
parse_ldd_libc(&combined)
|
||||
}
|
||||
|
||||
// ── Version helpers ────────────────────────────────────────────────────────
|
||||
|
||||
fn parse_version_from_tag(tag: &str) -> Result<Version> {
|
||||
|
|
@ -690,15 +732,49 @@ mod tests {
|
|||
let result = detect_target();
|
||||
// We can only assert it succeeds on known CI platforms
|
||||
if cfg!(target_os = "linux") && cfg!(target_arch = "x86_64") {
|
||||
assert_eq!(result.unwrap(), "x86_64-unknown-linux-gnu");
|
||||
let got = result.unwrap();
|
||||
assert!(
|
||||
got == "x86_64-unknown-linux-gnu" || got == "x86_64-unknown-linux-musl",
|
||||
"got {got}"
|
||||
);
|
||||
} else if cfg!(target_os = "macos") && cfg!(target_arch = "aarch64") {
|
||||
assert_eq!(result.unwrap(), "aarch64-apple-darwin");
|
||||
} else if cfg!(target_os = "linux") && cfg!(target_arch = "aarch64") {
|
||||
assert_eq!(result.unwrap(), "aarch64-unknown-linux-gnu");
|
||||
let got = result.unwrap();
|
||||
assert!(
|
||||
got == "aarch64-unknown-linux-gnu" || got == "aarch64-unknown-linux-musl",
|
||||
"got {got}"
|
||||
);
|
||||
}
|
||||
// On other platforms it would return an error, which is fine
|
||||
}
|
||||
|
||||
// -- Libc parsing --
|
||||
|
||||
#[test]
|
||||
fn parse_ldd_libc_detects_glibc() {
|
||||
assert_eq!(
|
||||
parse_ldd_libc(
|
||||
"ldd (Ubuntu GLIBC 2.35-0ubuntu3.4) 2.35\nCopyright (C) 2022 Free Software Foundation, Inc."
|
||||
),
|
||||
Libc::Gnu,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_ldd_libc_detects_musl() {
|
||||
assert_eq!(
|
||||
parse_ldd_libc("musl libc (x86_64)\nVersion 1.2.4\nDynamic Program Loader"),
|
||||
Libc::Musl,
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn parse_ldd_libc_defaults_to_gnu_on_unknown_output() {
|
||||
assert_eq!(parse_ldd_libc(""), Libc::Gnu);
|
||||
assert_eq!(parse_ldd_libc("some unrelated output"), Libc::Gnu);
|
||||
}
|
||||
|
||||
// -- Version parsing --
|
||||
|
||||
#[test]
|
||||
|
|
|
|||
|
|
@ -168,7 +168,7 @@ esac
|
|||
"[VERSION]".to_string(),
|
||||
));
|
||||
filters.push((
|
||||
"(aarch64-apple-darwin|x86_64-unknown-linux-gnu|aarch64-unknown-linux-gnu)".to_string(),
|
||||
"(aarch64-apple-darwin|x86_64-unknown-linux-gnu|aarch64-unknown-linux-gnu|x86_64-unknown-linux-musl|aarch64-unknown-linux-musl)".to_string(),
|
||||
"[TARGET]".to_string(),
|
||||
));
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue