Skip to content

fix: use musl static linking to eliminate GLIBC dependency for Linux binaries#513

Open
svarlamov wants to merge 2 commits intomainfrom
devin/1770936330-fix-glibc-compat
Open

fix: use musl static linking to eliminate GLIBC dependency for Linux binaries#513
svarlamov wants to merge 2 commits intomainfrom
devin/1770936330-fix-glibc-compat

Conversation

@svarlamov
Copy link
Member

@svarlamov svarlamov commented Feb 12, 2026

fix: use musl static linking to eliminate GLIBC dependency for Linux binaries

Summary

Addresses #509 — pre-built Linux binaries currently require GLIBC 2.29+ (built on ubuntu:20.04 / GLIBC 2.31), which breaks on CentOS 8, RHEL 8, Debian 10, and other older Linux systems.

Instead of lowering the GLIBC floor (which would require an EOL build image), this PR switches Linux release builds to musl static linking, producing fully self-contained binaries with zero GLIBC dependency.

Changes:

  1. release.yml: Switch Linux build targets from x86_64-unknown-linux-gnu / aarch64-unknown-linux-gnu to their -musl equivalents. Docker build image changed from ubuntu:20.04 to ubuntu:22.04 (maintained). Install musl-tools instead of libssl-dev.
  2. release.yml: Replace the old GLIBC version logging with a static-linking assertion — the release build will now fail if ldd reports the binary as dynamically linked.
  3. install.sh: No functional changes (net diff is a cosmetic blank line).

Artifact names (git-ai-linux-x64, git-ai-linux-arm64) are unchanged — this is a drop-in replacement from the user's perspective.

Review & Testing Checklist for Human

  • musl build has NOT been tested end-to-end: PR CI does not exercise the release workflow (workflow_dispatch only). A dry-run release build (workflow_dispatch with dry_run: true) is strongly recommended before merging to confirm the musl build succeeds for both x64 and arm64.
  • rusqlite bundled SQLite compilation with musl: rusqlite compiles SQLite from C source using cc. Verify musl-gcc (from musl-tools) correctly compiles this on both x64 and arm64. This is the most likely build failure point.
  • Static linking verification pattern: The ldd output check uses grep -q 'not a dynamic executable\|statically linked'. Confirm this matches the actual ldd output for musl binaries on the Ubuntu 22.04 runner (the exact message can vary by ldd version).
  • Binary size and runtime behavior: musl static binaries are typically larger and use musl's allocator instead of glibc's. For a CLI tool this should be negligible, but worth a quick sanity check (run the binary, check --version, try a commit).

Recommended test plan:

  1. Trigger a dry-run release build to confirm both x64 and arm64 musl builds succeed
  2. Download the resulting binaries and verify with file <binary> (should say "statically linked") and ldd <binary> (should say "not a dynamic executable")
  3. Test the binary on a system with old GLIBC (e.g., CentOS 8 / Debian 10) to confirm it runs

Notes

- Switch Docker build image from ubuntu:20.04 (GLIBC 2.31) to debian:10
  (GLIBC 2.28) for Linux release builds
- Add GLIBC version ceiling check in CI to prevent future regressions
- Add GLIBC version check in install.sh to give users a clear error
  message before downloading an incompatible binary

Fixes #509

Co-Authored-By: Sasha Varlamov <sasha@sashavarlamov.com>
@devin-ai-integration
Copy link
Contributor

🤖 Devin AI Engineer

I'll be helping with this pull request! Here's what you should know:

✅ I will automatically:

  • Address comments on this PR. Add '(aside)' to your comment to have me ignore it.
  • Look at CI failures and help fix them

Note: I can only respond to comments from users who have write access to this repository.

⚙️ Control Options:

  • Disable automatic comment and CI monitoring

@CLAassistant
Copy link

CLA assistant check
Thank you for your submission! We really appreciate it. Like many open source projects, we ask that you sign our Contributor License Agreement before we can accept your contribution.
You have signed the CLA already but the status is still pending? Let us recheck it.

Copy link
Contributor

@devin-ai-integration devin-ai-integration bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

✅ Devin Review: No Issues Found

Devin Review analyzed this PR and found no potential bugs to report.

View in Devin Review to see 5 additional findings.

Open in Devin Review

@git-ai-cloud-dev
Copy link

No AI authorship found for these commits. Please install git-ai to start tracking AI generated code in your commits.

@git-ai-cloud
Copy link

git-ai-cloud bot commented Feb 12, 2026

No AI authorship found for these commits. Please install git-ai to start tracking AI generated code in your commits.

@svarlamov
Copy link
Member Author

is there any chance that this will break the builds for newer os's/ubuntu/etc. any potential issues you can think of?

@devin-ai-integration
Copy link
Contributor

No — building against an older GLIBC will not break binaries on newer systems. GLIBC is forward-compatible: a binary linked against GLIBC 2.28 will run on any system with GLIBC 2.28+. This is the same principle used by projects like ripgrep, rustup, and most Linux distro packaging.

The only potential issues I can think of:

  1. Debian 10 Docker image is EOLapt-get update inside the debian:10 container could fail if the default apt sources stop resolving. If that happens, the fix is a one-line change to point at archive.debian.org. I'd recommend running a dry-run release build (workflow_dispatch with dry_run: true) to validate before the next real release.

  2. Older compiler toolchain — Debian 10 ships GCC 8, but this only matters for C dependencies compiled during the build. The Rust toolchain itself is installed fresh via rustup (latest stable), so Rust compilation is unaffected. The project's C dependencies (rusqlite with bundled, rustls) are well-tested on older GCC versions.

  3. No performance/behavior difference — the produced binary is functionally identical; the only difference is the minimum GLIBC version symbol it links against. Users on Ubuntu 22.04/24.04, Debian 12, Fedora, etc. will see no change at all.

@svarlamov
Copy link
Member Author

is there a way to do this without using an EOL'd builder image?

@devin-ai-integration
Copy link
Contributor

Good call. I'll switch the approach to musl static linking instead — this builds fully static binaries with zero GLIBC dependency, using a maintained ubuntu:22.04 Docker image. The project's dependencies (rustls, bundled rusqlite) are all musl-compatible. Will push the update shortly.

- Use x86_64-unknown-linux-musl and aarch64-unknown-linux-musl targets
  for fully static binaries with zero GLIBC dependency
- Build in ubuntu:22.04 Docker (maintained, non-EOL) with musl-tools
- Replace GLIBC version ceiling check with static linking verification
- Remove GLIBC check from install.sh (no longer needed for static binaries)

This eliminates the GLIBC compatibility issue entirely rather than
just lowering the minimum version.

Co-Authored-By: Sasha Varlamov <sasha@sashavarlamov.com>
@devin-ai-integration devin-ai-integration bot changed the title fix: lower GLIBC requirement to 2.28 for older Linux compatibility fix: use musl static linking to eliminate GLIBC dependency for Linux binaries Feb 14, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants