Problem
rubydex ships precompiled gems for x86_64-linux (glibc), aarch64-linux (glibc), arm64-darwin, x86_64-darwin, and x64-mingw-ucrt, plus a ruby source gem. There is no *-linux-musl precompiled gem, and the glibc-targeted x86_64-linux build fails to load on Alpine / musl libc — even with gcompat installed — because the prebuilt .so references fortify-source symbols (__vsnprintf_chk, etc.) that musl + gcompat do not provide:
Error relocating /usr/local/bundle/gems/rubydex-0.2.3-x86_64-linux/lib/rubydex/3.4/../librubydex_sys.so:
__vsnprintf_chk: symbol not found
- /usr/local/bundle/gems/rubydex-0.2.3-x86_64-linux/lib/rubydex/3.4/rubydex.so (LoadError)
This makes bundle install succeed (because bundler considers x86_64-linux compatible with x86_64-linux-musl) but require "rubydex" fail at runtime — which means anything depending on rubydex (e.g. tapioca >= 0.19) is unusable on Alpine-based CI/runtime images.
Reproduce
FROM ruby:3.4-alpine
RUN apk add --no-cache build-essential libyaml-dev git
RUN gem install rubydex -v 0.2.3
RUN ruby -e "require 'rubydex'"
gem install and bundle install both succeed (bundler installs rubydex-0.2.3-x86_64-linux); the final require errors with the __vsnprintf_chk relocation failure shown above.
Workarounds we tried
gcompat — already a documented compatibility shim on Alpine. Does not implement the glibc *_chk fortify-source family, so this approach is a dead end for any prebuilt gem compiled with -D_FORTIFY_SOURCE=2.
- Force source build (
gem "rubydex", force_ruby_platform: true) — fails on Alpine because the source gem needs cargo, and the alpine Ruby base image does not include the Rust toolchain. Adding it costs ~150 MB and ~60s per fresh build.
- Move CI off Alpine to
ruby:*-slim (Debian/glibc) — what we ended up doing. Works, but it's a bigger change than the failure warranted.
Suggested fix
Publish an x86_64-linux-musl (and ideally aarch64-linux-musl) precompiled variant alongside the existing x86_64-linux build. Other gems with Rust extensions take this approach (e.g. nokogiri, wasmtime, lz4-ruby); typical implementations cross-compile in CI with a musl Rust target (x86_64-unknown-linux-musl).
If a musl prebuild is out of scope, two smaller mitigations would still help:
- Either document the Alpine incompatibility prominently in the README, since the runtime symptom (
__vsnprintf_chk) is opaque enough that it's hard to trace back to rubydex without doing the relocation analysis.
- Or build the existing
x86_64-linux gem without -D_FORTIFY_SOURCE=2, which would let gcompat carry it. (This degrades hardening on glibc systems, so I lean toward the musl-prebuild option.)
Happy to test a prerelease on an Alpine CI image if that's useful.
Environment
- rubydex 0.2.3
- Ruby 3.4 (
ruby:3.4-alpine, Alpine 3.20)
- Bundler 4.0.7
Problem
rubydexships precompiled gems forx86_64-linux(glibc),aarch64-linux(glibc),arm64-darwin,x86_64-darwin, andx64-mingw-ucrt, plus arubysource gem. There is no*-linux-muslprecompiled gem, and the glibc-targetedx86_64-linuxbuild fails to load on Alpine / musl libc — even withgcompatinstalled — because the prebuilt.soreferences fortify-source symbols (__vsnprintf_chk, etc.) that musl + gcompat do not provide:This makes
bundle installsucceed (because bundler considersx86_64-linuxcompatible withx86_64-linux-musl) butrequire "rubydex"fail at runtime — which means anything depending onrubydex(e.g.tapioca >= 0.19) is unusable on Alpine-based CI/runtime images.Reproduce
gem installandbundle installboth succeed (bundler installsrubydex-0.2.3-x86_64-linux); the finalrequireerrors with the__vsnprintf_chkrelocation failure shown above.Workarounds we tried
gcompat— already a documented compatibility shim on Alpine. Does not implement the glibc*_chkfortify-source family, so this approach is a dead end for any prebuilt gem compiled with-D_FORTIFY_SOURCE=2.gem "rubydex", force_ruby_platform: true) — fails on Alpine because the source gem needscargo, and the alpine Ruby base image does not include the Rust toolchain. Adding it costs ~150 MB and ~60s per fresh build.ruby:*-slim(Debian/glibc) — what we ended up doing. Works, but it's a bigger change than the failure warranted.Suggested fix
Publish an
x86_64-linux-musl(and ideallyaarch64-linux-musl) precompiled variant alongside the existingx86_64-linuxbuild. Other gems with Rust extensions take this approach (e.g.nokogiri,wasmtime,lz4-ruby); typical implementations cross-compile in CI with a musl Rust target (x86_64-unknown-linux-musl).If a musl prebuild is out of scope, two smaller mitigations would still help:
__vsnprintf_chk) is opaque enough that it's hard to trace back to rubydex without doing the relocation analysis.x86_64-linuxgem without-D_FORTIFY_SOURCE=2, which would letgcompatcarry it. (This degrades hardening on glibc systems, so I lean toward the musl-prebuild option.)Happy to test a prerelease on an Alpine CI image if that's useful.
Environment
ruby:3.4-alpine, Alpine 3.20)