Skip to content

fix(ci): patchelf GNU binaries to use system dynamic linker#112

Merged
antidmg merged 3 commits intomainfrom
fix/patchelf-gnu-binaries
Mar 2, 2026
Merged

fix(ci): patchelf GNU binaries to use system dynamic linker#112
antidmg merged 3 commits intomainfrom
fix/patchelf-gnu-binaries

Conversation

@antidmg
Copy link
Copy Markdown
Contributor

@antidmg antidmg commented Mar 2, 2026

Problem

Nix builds set the ELF interpreter to /nix/store/.../ld-linux-*.so.2, making the GNU binaries unrunnable on standard Linux systems (GitHub runners, user machines, etc.). This was introduced in PR #95 (Nix crane builds) and is why v0.1.5's install script fails:

statespace: ELF 64-bit LSB pie executable, x86-64, dynamically linked,
interpreter /nix/store/wb6rhpznjfczwlwx23zmdrrw74bayxw4-glibc-2.42-47/lib/ld-linux-x86-64.so.2

The musl builds are unaffected (statically linked). v0.1.3 worked because it used cargo-dist's native build matrix, not Nix.

Fix

After copying the GNU binary from the Nix result, use patchelf to reset the interpreter to the standard system path:

  • x86_64: /lib64/ld-linux-x86-64.so.2
  • aarch64: /lib/ld-linux-aarch64.so.1

Uses nix shell nixpkgs#patchelf since patchelf may not be pre-installed on Blacksmith runners.

Summary by CodeRabbit

  • Bug Fixes
    • Improved Linux release binaries for x86_64 and aarch64 by ensuring executables are made runnable and have correct runtime linking set, improving compatibility on GNU systems.
  • Chores
    • Simplified Linux install detection to consistently tag Linux targets the same way, reducing variability in platform identification during installs.

Nix builds set the ELF interpreter to /nix/store/.../ld-linux-*.so.2,
making the binary unrunnable on standard Linux systems. Use patchelf to
reset the interpreter to the standard system path after copying from
the Nix result.
@coderabbitai
Copy link
Copy Markdown

coderabbitai bot commented Mar 2, 2026

Walkthrough

Adds post-build binary patching to the release workflow for x86_64 and aarch64 Linux targets (chmod + patchelf to set interpreter and remove RPATH) and changes platform detection in install script to unconditionally tag Linux as unknown-linux-musl.

Changes

Cohort / File(s) Summary
Release workflow
.github/workflows/build-release-binaries.yml
After copying built statespace for GNU targets, sets executable mode and runs patchelf (via nix) to set the interpreter (/lib64/ld-linux-x86-64.so.2 for x86_64, /lib/ld-linux-aarch64.so.1 for aarch64) and remove RPATH before creating the tar.gz.
Install script platform detection
scripts/install.sh
detect_target now unconditionally sets Linux os="unknown-linux-musl", removing prior runtime branching between musl (Alpine) and glibc (unknown-linux-gnu) detection.

Estimated code review effort

🎯 2 (Simple) | ⏱️ ~10 minutes

🚥 Pre-merge checks | ✅ 2 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Description check ⚠️ Warning The description includes Problem (issue with Nix-set interpreters) and Fix (patchelf solution with specific paths), but lacks the Testing and Checklist sections required by the template. Add the Testing section with cargo fmt/clippy/test checklist items and the Checklist section for documentation updates to match the repository template.
✅ Passed checks (2 passed)
Check name Status Explanation
Title check ✅ Passed The title accurately summarizes the main change: using patchelf to fix GNU binaries' ELF interpreters set by Nix builds to use system dynamic linker paths.
Docstring Coverage ✅ Passed Docstring coverage is 100.00% which is sufficient. The required threshold is 80.00%.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
  • 📝 Generate docstrings (stacked PR)
  • 📝 Generate docstrings (commit on current branch)
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Post copyable unit tests in a comment
  • Commit unit tests in branch fix/patchelf-gnu-binaries

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Inline comments:
In @.github/workflows/build-release-binaries.yml:
- Around line 73-75: After running the patchelf invocation that rewrites the
interpreter and removes rpath for "dist/${ARCHIVE}/statespace", add a fail-fast
verification using patchelf --print-interpreter and patchelf --print-rpath (or
readelf -l) to assert the interpreter equals /lib64/ld-linux-x86-64.so.2 and
that the RPATH is empty; if either check fails, exit with non‑zero status so CI
stops before creating the archive. Target the same block that runs patchelf (the
command using --set-interpreter and --remove-rpath on
"dist/${ARCHIVE}/statespace") and ensure the verification runs immediately after
it and before any archiving/publishing steps.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between d4e20e7 and 85df2c1.

📒 Files selected for processing (1)
  • .github/workflows/build-release-binaries.yml

Comment on lines +73 to +75
# Nix sets the interpreter to /nix/store/...; patch it to the
# standard system path so the binary runs outside NixOS.
nix shell nixpkgs#patchelf -c patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 --remove-rpath "dist/${ARCHIVE}/statespace"
Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🧹 Nitpick | 🔵 Trivial

Add a fail-fast ELF metadata verification after patching.

The patch step is correct, but there’s no assertion that interpreter/RPATH were actually rewritten. Add a quick check before archiving so CI fails instead of publishing a broken tarball.

Suggested hardening
-              nix shell nixpkgs#patchelf -c patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 --remove-rpath "dist/${ARCHIVE}/statespace"
+              nix shell nixpkgs#patchelf -c patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 --remove-rpath "dist/${ARCHIVE}/statespace"
+              test "$(nix shell nixpkgs#patchelf -c patchelf --print-interpreter "dist/${ARCHIVE}/statespace")" = "/lib64/ld-linux-x86-64.so.2"
+              test -z "$(nix shell nixpkgs#patchelf -c patchelf --print-rpath "dist/${ARCHIVE}/statespace")"
@@
-              nix shell nixpkgs#patchelf -c patchelf --set-interpreter /lib/ld-linux-aarch64.so.1 --remove-rpath "dist/${ARCHIVE}/statespace"
+              nix shell nixpkgs#patchelf -c patchelf --set-interpreter /lib/ld-linux-aarch64.so.1 --remove-rpath "dist/${ARCHIVE}/statespace"
+              test "$(nix shell nixpkgs#patchelf -c patchelf --print-interpreter "dist/${ARCHIVE}/statespace")" = "/lib/ld-linux-aarch64.so.1"
+              test -z "$(nix shell nixpkgs#patchelf -c patchelf --print-rpath "dist/${ARCHIVE}/statespace")"

Also applies to: 137-139

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-release-binaries.yml around lines 73 - 75, After
running the patchelf invocation that rewrites the interpreter and removes rpath
for "dist/${ARCHIVE}/statespace", add a fail-fast verification using patchelf
--print-interpreter and patchelf --print-rpath (or readelf -l) to assert the
interpreter equals /lib64/ld-linux-x86-64.so.2 and that the RPATH is empty; if
either check fails, exit with non‑zero status so CI stops before creating the
archive. Target the same block that runs patchelf (the command using
--set-interpreter and --remove-rpath on "dist/${ARCHIVE}/statespace") and ensure
the verification runs immediately after it and before any archiving/publishing
steps.

antidmg added 2 commits March 1, 2026 20:19
The Nix-built GNU binaries have a /nix/store dynamic linker and link
against glibc 2.42, making them unrunnable on standard Linux systems.
Since the CLI uses rustls (no OpenSSL/native deps), musl static builds
work everywhere. Default the install script to musl on all Linux.

Also keep patchelf fix for GNU builds so they work if downloaded
directly.
Copy link
Copy Markdown

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

♻️ Duplicate comments (1)
.github/workflows/build-release-binaries.yml (1)

73-76: 🧹 Nitpick | 🔵 Trivial

Add fail-fast ELF metadata assertions right after patching.

After Line 76 and Line 141, assert interpreter and RPATH explicitly before packaging so CI fails instead of publishing a bad artifact.

Proposed hardening
               nix shell nixpkgs#patchelf -c patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2 --remove-rpath "dist/${ARCHIVE}/statespace"
+              test "$(nix shell nixpkgs#patchelf -c patchelf --print-interpreter "dist/${ARCHIVE}/statespace")" = "/lib64/ld-linux-x86-64.so.2"
+              test -z "$(nix shell nixpkgs#patchelf -c patchelf --print-rpath "dist/${ARCHIVE}/statespace")"
@@
               nix shell nixpkgs#patchelf -c patchelf --set-interpreter /lib/ld-linux-aarch64.so.1 --remove-rpath "dist/${ARCHIVE}/statespace"
+              test "$(nix shell nixpkgs#patchelf -c patchelf --print-interpreter "dist/${ARCHIVE}/statespace")" = "/lib/ld-linux-aarch64.so.1"
+              test -z "$(nix shell nixpkgs#patchelf -c patchelf --print-rpath "dist/${ARCHIVE}/statespace")"

Also applies to: 138-141

🤖 Prompt for AI Agents
Verify each finding against the current code and only fix it if needed.

In @.github/workflows/build-release-binaries.yml around lines 73 - 76, After
calling patchelf --set-interpreter and --remove-rpath on the built binary (the
command using "patchelf --set-interpreter /lib64/ld-linux-x86-64.so.2
--remove-rpath \"dist/${ARCHIVE}/statespace\""), add immediate fail-fast
assertions that verify the ELF interpreter is /lib64/ld-linux-x86-64.so.2 and
that the RPATH is empty by invoking patchelf --print-interpreter and patchelf
--print-rpath against dist/${ARCHIVE}/statespace and making the CI step exit
non-zero if the values do not match expected; repeat the same verification after
the later patching/packaging block (the duplicate patchelf usage near the second
occurrence) so the workflow fails early instead of publishing a bad artifact.
🤖 Prompt for all review comments with AI agents
Verify each finding against the current code and only fix it if needed.

Duplicate comments:
In @.github/workflows/build-release-binaries.yml:
- Around line 73-76: After calling patchelf --set-interpreter and --remove-rpath
on the built binary (the command using "patchelf --set-interpreter
/lib64/ld-linux-x86-64.so.2 --remove-rpath \"dist/${ARCHIVE}/statespace\""), add
immediate fail-fast assertions that verify the ELF interpreter is
/lib64/ld-linux-x86-64.so.2 and that the RPATH is empty by invoking patchelf
--print-interpreter and patchelf --print-rpath against
dist/${ARCHIVE}/statespace and making the CI step exit non-zero if the values do
not match expected; repeat the same verification after the later
patching/packaging block (the duplicate patchelf usage near the second
occurrence) so the workflow fails early instead of publishing a bad artifact.

ℹ️ Review info

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

📥 Commits

Reviewing files that changed from the base of the PR and between 85df2c1 and ac21880.

📒 Files selected for processing (2)
  • .github/workflows/build-release-binaries.yml
  • scripts/install.sh

@antidmg antidmg merged commit ef7a2a9 into main Mar 2, 2026
14 checks passed
@antidmg antidmg deleted the fix/patchelf-gnu-binaries branch March 2, 2026 04:37
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.

1 participant