Skip to content

About

What is says on the tin: upstream's "static" builds aren't. This is. Bonus Docker image.

Resources

Stars

1 star

Watchers

0 watching

Forks

Latest commit

 

History

25 Commits

Folders and files

Repository files navigation

rsgain-actuallystatic-autobuild

Statically linked rsgain builds — for real this time.

Why this exists

Upstream publishes a Linux tarball from a CI job named Static. It isn't:

$ file rsgain            # upstream v3.8
rsgain: ELF 64-bit LSB pie executable, x86-64, version 1 (GNU/Linux),
dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, ...
$ ldd rsgain
	linux-vdso.so.1 (...)
	libstdc++.so.6 => /usr/lib/libstdc++.so.6 (...)
	libm.so.6 => /usr/lib/libm.so.6 (...)
	libgcc_s.so.1 => /usr/lib/libgcc_s.so.1 (...)
	libpthread.so.0 => /usr/lib/libpthread.so.0 (...)
	libc.so.6 => /usr/lib/libc.so.6 (...)
	/lib64/ld-linux-x86-64.so.2 => /usr/lib64/ld-linux-x86-64.so.2 (...)

Six NEEDED entries (readelf -d): libstdc++, libm, libgcc_s, libpthread, libc, and — because it's a PIE binary — the dynamic loader itself, ld-linux-x86-64.so.2.

Upstream builds its dependencies statically (ffmpeg, libebur128, inih via vcpkg) but never statically links the toolchain, so the binary still needs a host glibc (>= 2.30) and a matching libstdc++. It can't run in a scratch container or on musl systems.

These builds have zero NEEDED entries, no INTERP segment, and run anywhere with a Linux kernel.

Use it

docker run --rm -v /path/to/music:/music \
  ghcr.io/tfenby/rsgain-actuallystatic easy /music
docker run --rm -v /path/to/music:/music \
  ghcr.io/tfenby/rsgain-actuallystatic easy -p ebur128 /music

The image is FROM scratch — about 6.6 MB (amd64) / 5.7 MB (arm64) on disk, ~3 MB to pull, no shell, no libc, nothing but the binary and its presets. Both architectures are built and published natively (no cross-compilation, no emulation). Or grab a tarball from Releases and drop the binary anywhere on $PATH — note that -p <name> preset lookup only works if the presets end up installed at /usr/share/rsgain/presets (as they are in the image); otherwise pass a preset by its full path instead of by name.

How it's built

Upstream's source, unmodified, built through vcpkg with upstream's own manifest and overlay ports. The change that makes the binary static is one linker flag:

-DCMAKE_EXE_LINKER_FLAGS="-static"

No fork, no patches, no vendored dependencies. Every other configure argument matches upstream's Static job character-for-character, but the build is not identical to it, and the differences are worth stating plainly in a repo about accurate claims:

upstream's Static job here
base image debian:bullseye (EOL, mirrors 404) debian:trixie
architectures x86-64 only amd64 + arm64
man page -DINSTALL_MANPAGE=OFF flag not passed
packaging CPack via --target package tarball assembled directly

Since the binary is statically linked, the build image's glibc version has no bearing on where it runs — which is why moving off upstream's EOL bullseye pin costs nothing. A daily job checks upstream for a new release and builds amd64 and arm64 natively (separate native runners per architecture, not QEMU).

Every build must pass ./verify.sh, which asserts zero NEEDED entries, no INTERP segment, that file reports statically linked, and that the binary actually tags a generated flac correctly. Nothing publishes unless every architecture passes — so a regression to dynamic linking fails the build instead of shipping as another mislabelled tarball.

Run it yourself against any rsgain binary:

./verify.sh /path/to/rsgain

About

What is says on the tin: upstream's "static" builds aren't. This is. Bonus Docker image.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages