2 Commits

Author SHA1 Message Date
gffranco 9884f7b13c chore(release): 0.5.2
CI / cargo fmt --check (push) Successful in 20s
CI / cargo test (push) Successful in 34s
CI / cargo clippy (push) Successful in 35s
Release / bump + tag (push) Successful in 43s
Release / build aarch64-unknown-linux-musl (push) Successful in 2m10s
Release / build x86_64-unknown-linux-gnu (push) Successful in 2m15s
Release / build aarch64-unknown-linux-gnu (push) Successful in 2m18s
Release / build x86_64-unknown-linux-musl (push) Successful in 2m18s
Release / gitea release (push) Successful in 1m36s
2026-08-07 15:24:10 -03:00
gffranco e073533c62 fix(release): make the x86_64 musl binary actually static
CI / cargo fmt --check (push) Successful in 16s
CI / cargo clippy (push) Successful in 43s
CI / cargo test (push) Successful in 50s
Routing the x86_64-unknown-linux-musl link through Ubuntu's musl-gcc
wrapper overrode Rust's crt-static default and produced a dynamic
binary with an interpreter of /lib/ld-musl-x86_64.so.1. That path
exists on approximately no machine outside Alpine, so the shipped
binary died at exec time with "required file not found" everywhere —
the opposite of what a musl build is for. aarch64-unknown-linux-musl
never used musl-gcc and was static all along; only x86_64 was broken.

Drop musl-tools and the linker override and let Rust link with its
own bundled musl libc.a, which yields a static-pie executable.

Add a post-build check that fails the release if a musl binary has an
INTERP segment, so this can't silently ship again.

Also correct the asset-URL comment: Gitea serves
/releases/download/latest/<name>, not GitHub's
/releases/latest/download/<name>.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_011J8C6eRmWEZsh28vkEMD9H
2026-08-07 15:20:44 -03:00
5 changed files with 36 additions and 11 deletions
+30 -5
View File
@@ -133,8 +133,15 @@ jobs:
# crti.o, and friends needed at link time. # crti.o, and friends needed at link time.
apt: "gcc-aarch64-linux-gnu libc6-dev-arm64-cross" apt: "gcc-aarch64-linux-gnu libc6-dev-arm64-cross"
rustflags: "-D warnings" rustflags: "-D warnings"
# No musl-tools / musl-gcc here on purpose. Rust ships a
# self-contained musl libc.a plus the crt objects for this
# target, and the default link mode is static-pie. Routing the
# link through Ubuntu's musl-gcc wrapper instead produces a
# *dynamic* binary needing /lib/ld-musl-x86_64.so.1, which
# exists on approximately no machine outside Alpine — the
# opposite of what a musl build is for.
- target: x86_64-unknown-linux-musl - target: x86_64-unknown-linux-musl
apt: "musl-tools" apt: ""
rustflags: "-D warnings" rustflags: "-D warnings"
- target: aarch64-unknown-linux-musl - target: aarch64-unknown-linux-musl
apt: "" apt: ""
@@ -168,13 +175,29 @@ jobs:
- name: Build nuwiki-ls - name: Build nuwiki-ls
env: env:
# Per-target linker overrides. Cargo ignores the entries that # Per-target linker overrides. Cargo ignores the entries that
# don't match the current target, so setting all of them here # don't match the current target, so setting them here keeps
# keeps the matrix declarative. # the matrix declarative. Only add an override for a target
# whose default linker genuinely can't do the job.
CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc CARGO_TARGET_AARCH64_UNKNOWN_LINUX_GNU_LINKER: aarch64-linux-gnu-gcc
CARGO_TARGET_X86_64_UNKNOWN_LINUX_MUSL_LINKER: musl-gcc
RUSTFLAGS: ${{ matrix.rustflags }} RUSTFLAGS: ${{ matrix.rustflags }}
run: cargo build --release --target ${{ matrix.target }} -p nuwiki-ls run: cargo build --release --target ${{ matrix.target }} -p nuwiki-ls
# A musl build only earns its keep if it is actually static. A
# dynamic one silently fails at exec time with "no such file or
# directory" on every non-Alpine host, so fail the release here
# rather than shipping it.
- name: Verify musl binary is statically linked
if: contains(matrix.target, 'musl')
run: |
set -euo pipefail
bin="target/${{ matrix.target }}/release/nuwiki-ls"
if readelf -l "$bin" | grep -q INTERP; then
echo "::error::$bin is dynamically linked but should be static:"
readelf -l "$bin" | grep -A2 INTERP
exit 1
fi
echo "OK: $bin has no INTERP segment (statically linked)."
- name: Package archive - name: Package archive
id: package id: package
env: env:
@@ -183,7 +206,9 @@ jobs:
set -euo pipefail set -euo pipefail
archive="nuwiki-ls-${VERSION}-${{ matrix.target }}.tar.gz" archive="nuwiki-ls-${VERSION}-${{ matrix.target }}.tar.gz"
tar -czf "$archive" -C "target/${{ matrix.target }}/release" nuwiki-ls tar -czf "$archive" -C "target/${{ matrix.target }}/release" nuwiki-ls
# Use a stable name without version so /releases/latest/download/nuwiki-ls-{target}.tar.gz always resolves. # Use a stable name without version so the download URL always
# resolves. Note the Gitea shape is /releases/download/latest/<name>,
# not GitHub's /releases/latest/download/<name> — the latter 404s.
stable="nuwiki-ls-${{ matrix.target }}.tar.gz" stable="nuwiki-ls-${{ matrix.target }}.tar.gz"
mv "$archive" "$stable" mv "$archive" "$stable"
echo "archive=$stable" >> "$GITHUB_OUTPUT" echo "archive=$stable" >> "$GITHUB_OUTPUT"
Generated
+3 -3
View File
@@ -376,11 +376,11 @@ checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79"
[[package]] [[package]]
name = "nuwiki-core" name = "nuwiki-core"
version = "0.5.1" version = "0.5.2"
[[package]] [[package]]
name = "nuwiki-ls" name = "nuwiki-ls"
version = "0.5.1" version = "0.5.2"
dependencies = [ dependencies = [
"nuwiki-lsp", "nuwiki-lsp",
"tokio", "tokio",
@@ -388,7 +388,7 @@ dependencies = [
[[package]] [[package]]
name = "nuwiki-lsp" name = "nuwiki-lsp"
version = "0.5.1" version = "0.5.2"
dependencies = [ dependencies = [
"async-trait", "async-trait",
"dashmap 6.1.0", "dashmap 6.1.0",
+1 -1
View File
@@ -3,7 +3,7 @@ resolver = "2"
members = ["crates/*"] members = ["crates/*"]
[workspace.package] [workspace.package]
version = "0.5.1" version = "0.5.2"
edition = "2021" edition = "2021"
rust-version = "1.83" rust-version = "1.83"
authors = ["Gabriel Fróes Franco <gffranco@gmail.com>"] authors = ["Gabriel Fróes Franco <gffranco@gmail.com>"]
+1 -1
View File
@@ -17,5 +17,5 @@ name = "nuwiki-ls"
path = "src/main.rs" path = "src/main.rs"
[dependencies] [dependencies]
nuwiki-lsp = { path = "../nuwiki-lsp", version = "0.5.1" } nuwiki-lsp = { path = "../nuwiki-lsp", version = "0.5.2" }
tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-std"] } tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-std"] }
+1 -1
View File
@@ -13,7 +13,7 @@ homepage.workspace = true
workspace = true workspace = true
[dependencies] [dependencies]
nuwiki-core = { path = "../nuwiki-core", version = "0.5.1" } nuwiki-core = { path = "../nuwiki-core", version = "0.5.2" }
tower-lsp = "0.20" tower-lsp = "0.20"
tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-std", "sync", "fs"] } tokio = { version = "1", features = ["macros", "rt-multi-thread", "io-std", "sync", "fs"] }
dashmap = "6" dashmap = "6"