From 812b70d4b7267f442b241389a266ba471feb9baf Mon Sep 17 00:00:00 2001 From: Breadway Date: Wed, 12 Aug 2026 14:12:08 +0800 Subject: [PATCH] ci: link breadarrd/breadarr-tui against hestia's glibc, not the CI container's MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit hestia (the actual deployment target) runs Ubuntu 24.04 (glibc 2.39); the shared Arch CI image tracks a much newer glibc (currently 2.43). A binary linked normally there requires GLIBC_2.43 symbols and refuses to start on hestia at all (glibc symbol versioning is forward-only) — this is what crashed breadarrd in production after its first bakery-managed install. Fix: ci/build.sh now pulls a real glibc + gcc-libs (for libstdc++) package pair from the Arch Linux Archive, matching hestia's actual versions, and links against them via --sysroot instead of the container's native ones. cargo-zigbuild (targeting an older glibc via zig's cross-linker) was tried first and doesn't work here: zig has no version database for libstdc++ specifically, and onnxruntime -- statically linked in by the ort crate -- needs a real, complete one. A real archived glibc+gcc-libs pair sidesteps that entirely. reqwest's native-tls now vendors (statically builds) OpenSSL instead of dynamically linking the build host's, since the old sysroot has no libssl/libcrypto of its own — also means the shipped binary no longer depends on the target system's OpenSSL version at all. Verified end-to-end on hestia's actual self-hosted runner: real ci/build.sh, real bread-ci:breadarr image, real docker build/run — produced binary requires GLIBC up to 2.39 and GLIBCXX up to 3.4.30 only, and actually starts and runs on hestia. --- .gitignore | 1 + Cargo.lock | 11 +++++++++++ breadarrd/Cargo.toml | 7 +++++++ ci/build.sh | 41 ++++++++++++++++++++++++++++++++++++++++- 4 files changed, 59 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 888a8b4..128b003 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,5 @@ /target +/.ci-old-glibc config.toml *.db *.db-wal diff --git a/Cargo.lock b/Cargo.lock index 319dc6e..41fd9a0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -238,6 +238,7 @@ dependencies = [ "chrono", "fastrand", "nix", + "openssl-sys", "ort", "quick-xml", "regex", @@ -1767,6 +1768,15 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7c87def4c32ab89d880effc9e097653c8da5d6ef28e6b539d313baaacfbafcbe" +[[package]] +name = "openssl-src" +version = "300.6.1+3.6.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46eb8fb9fb3b61ce1c0f8a026c4c1a0714d3a9e138e7fbde78753ce2babc3846" +dependencies = [ + "cc", +] + [[package]] name = "openssl-sys" version = "0.9.117" @@ -1775,6 +1785,7 @@ checksum = "b47e7e6bb2c38cd930d25a23b40fa52e068c10e85f3e03a7f5ba5aaca5713695" dependencies = [ "cc", "libc", + "openssl-src", "pkg-config", "vcpkg", ] diff --git a/breadarrd/Cargo.toml b/breadarrd/Cargo.toml index d7b2c65..c086d4d 100644 --- a/breadarrd/Cargo.toml +++ b/breadarrd/Cargo.toml @@ -25,3 +25,10 @@ scraper.workspace = true chrono.workspace = true fastrand.workspace = true nix.workspace = true +# Forces reqwest's native-tls backend to statically build and link its own +# OpenSSL instead of dynamically linking whatever libssl/libcrypto happens +# to be on the build host — CI (see ci/build.sh) links against an archived +# old-glibc sysroot for hestia compatibility, which has no libssl/libcrypto +# of its own to dynamically link against. Also means the shipped binary no +# longer depends on the target system's OpenSSL version at all. +openssl-sys = { version = "0.9", features = ["vendored"] } diff --git a/ci/build.sh b/ci/build.sh index f238cd9..d695d77 100755 --- a/ci/build.sh +++ b/ci/build.sh @@ -18,4 +18,43 @@ if [ ! -d "$CACHE_DIR" ]; then git -C "$CACHE_DIR" checkout --quiet "$REV" fi -bash "${CACHE_DIR}/ci/build.sh" breadarr "$ROOT" "$@" +# hestia (breadarrd's actual deployment target) runs Ubuntu 24.04 (glibc +# 2.39). The shared CI image is Arch, which tracks a much newer glibc +# (currently 2.43) — a binary linked normally there refuses to start on +# hestia (glibc symbol versioning is forward-only). Rather than patch the +# shared image (would affect every other product's build), pull down a +# real, complete glibc + matching gcc-libs (for libstdc++) from the Arch +# Linux Archive and link against those via --sysroot, so the binary only +# requires symbol versions that actually exist on hestia. +# +# cargo-zigbuild (targeting an older glibc via zig's cross-linker) was +# tried first and doesn't work here: zig only maintains a version database +# for glibc's own symbols, not libstdc++'s, and onnxruntime — statically +# linked in by the `ort` crate — needs a real, complete libstdc++, not +# zig's minimal stand-in. A real archived glibc+gcc-libs package pair, +# linked via --sysroot, sidesteps that entirely. +GLIBC_VER="2.39-4" +GCC_LIBS_VER="13.2.1-6" +OLD_GLIBC_CACHE="/tmp/bread-ci-old-glibc-${GLIBC_VER}" +if [ ! -d "${OLD_GLIBC_CACHE}/usr/lib" ]; then + rm -rf "${OLD_GLIBC_CACHE}" + mkdir -p "${OLD_GLIBC_CACHE}" + curl -sfL -o /tmp/old-glibc.pkg.tar.zst \ + "https://archive.archlinux.org/packages/g/glibc/glibc-${GLIBC_VER}-x86_64.pkg.tar.zst" + curl -sfL -o /tmp/old-gcc-libs.pkg.tar.zst \ + "https://archive.archlinux.org/packages/g/gcc-libs/gcc-libs-${GCC_LIBS_VER}-x86_64.pkg.tar.zst" + tar --zstd -xf /tmp/old-glibc.pkg.tar.zst -C "${OLD_GLIBC_CACHE}" + tar --zstd -xf /tmp/old-gcc-libs.pkg.tar.zst -C "${OLD_GLIBC_CACHE}" + rm -f /tmp/old-glibc.pkg.tar.zst /tmp/old-gcc-libs.pkg.tar.zst +fi +# The shared build script only bind-mounts $ROOT (as /workspace) into the +# container, not arbitrary host paths — so the cached sysroot has to be +# copied under $ROOT to be visible there. The download above is cached +# persistently in /tmp across runs; this copy is just a fast local `cp`. +rm -rf "${ROOT}/.ci-old-glibc" +cp -a "${OLD_GLIBC_CACHE}" "${ROOT}/.ci-old-glibc" + +bash "${CACHE_DIR}/ci/build.sh" breadarr "$ROOT" sh -c ' + RUSTFLAGS="-C link-arg=--sysroot=/workspace/.ci-old-glibc -C link-arg=-L/workspace/.ci-old-glibc/usr/lib" \ + exec "$@" +' sh "$@"