Skip to content

Build on manylinux_2_28 (glibc 2.28, GCC 14) - #17

Merged
excid3 merged 2 commits into
mainfrom
glibc-2.28
Sep 30, 2026
Merged

excid3 merged 2 commits into
mainfrom
glibc-2.28

Conversation

@excid3

@excid3 excid3 commented Sep 30, 2026 •

Copy link
Copy Markdown
Member

Moves every target from manylinux2014 (CentOS 7, glibc 2.17, GCC 10) to manylinux_2_28 (AlmaLinux 8, glibc 2.28, GCC 14).

Why 2.28

It is the newest glibc that still runs on Ubuntu 20.04 (2.31), the oldest release Hatchbox provisions; manylinux_2_34 would drop focal. It also covers Debian 10+ and RHEL 8+.

What it buys (verified on the new builds):

  • Ruby links statx, copy_file_range and getrandom, which the 2.17 builds compiled out. File.birthtime works on 2.7 and later (it raised NotImplementedError); 2.2 to 2.6 predate Ruby's statx support, and 1.8 to 2.1 have no File.birthtime.
  • GCC 14 instead of 10, and off the end-of-life CentOS 7 image.

Changes

  • recipes/targets.yml: new pinned containers (2026.09.29-1, by digest), max_glibc: "2.28".
  • recipes/series.yml: 1.8 to 2.2 downgrade the four GCC 14 permerrors (implicit function declaration, implicit int, int conversion, incompatible pointer types) to warnings. Without them 1.9.3/2.0/2.1/2.2 fail to compile, and their openssl extension's configure checks misdetect OpenSSL functions. Only flags GCC 8 also accepts: CFLAGS stays in rbconfig, and the two GCC-14-only flags (return-mismatch, declaration-missing-parameter-type) made every native gem build fail with an older compiler (caught by the package's own test, which compiles with the image's gcc 8 cc).
  • bin/package-linux: derived image and build volume keyed by the container, so a new pin doesn't reuse the old toolchain's image or dependency builds.
  • README, CLAUDE.md, comments.

Testing

  • CI: Build workflow dispatched on this branch for 1.8.7, 1.9.3, 2.0.0, 2.1.10, 2.2.10, 2.3.8, 2.4.10, 2.5.9, 2.6.10, 2.7.8, 3.0.7, 3.1.7, 3.2.11, 3.3.12, 3.4.11, 4.0.7: all 16 pass on both targets, YJIT variants included.

  • Local arm64 builds of the same 16, tested on Ubuntu 20.04 and 26.04: pg (from source, system libpq) + TLS Postgres 17 + HTTPS in both require orders pass on all 16 on 20.04; no termcap warning, no build paths in rbconfig, strscan 3.1.8 loads (2.4+), puma compiles against the bundled OpenSSL. Tarballs need at most GLIBC_2.28 and ship no run paths (except 4.0.7's pre-existing /./lib).

  • x86_64 CI artifacts of 1.8.7, 2.1.10, 2.7.8 and 3.4.11 (YJIT) on Ubuntu 20.04 amd64: pg/HTTPS both orders pass; YJIT enables; File.birthtime works on 3.4.11.

  • On Ubuntu 26.04 (GCC 15), a plain gem install pg works on the new builds, and pg 1.0.0 on 2.1.10 now compiles there (it fails on the current release).

  • Rails deploy matrix on these builds (arm64, Ubuntu 24.04): fresh app, deployment bundle with native gems from source, migrations over TLS to Postgres, assets, runner with HTTPS, Puma HTTP and ssl:// form flow, both pg/openssl load orders. All pass: 1.8.7/Rails 3.2; 1.9.3, 2.0.0, 2.1.10/4.2; 2.2.10, 2.3.8, 2.4.10/5.2; 2.5.9, 2.6.10/6.1 (2.5.9 also without the mail pin: strscan 3.1.8 now loads); 2.7.8, 3.0.7/7.1; 3.1.7/7.2; 3.2.11/8.0; 3.4.11, 4.0.7/8.1 (Solid Queue, YJIT). Same gem pins as the 2.17 builds; no termcap messages; no build-tree paths in rbconfig or any run path; compiler warnings in gem builds identical to the 2.17 builds.

Also fixes a regression from #16 (merged, unreleased)

The Rails run caught it: merging libruby-static.a into one object made every mkmf probe link all of Ruby with its debug info, ~900 MB of linker memory per have_func on 3.4. Four parallel gem builds in 2 GB got OOM-killed, and a killed probe reads as "function missing" (json 3.0.2 then failed to compile). The merged object is now stripped of debug info: a probe link peaks at ~48 MB (published 2.17 builds: ~290 MB), libruby-static.a drops from ~155 MB to 14 MB, and the 3.4.11 YJIT tarball from ~92 MB to 59 MB. 3.4.11 and 4.0.7 on Rails 8.1 then pass with default parallelism and zero OOM kills. The installation test fails if the archive has debug sections again.

Also in this PR: lib/pkgconfig/*.pc no longer name the build tree (relocated to ${pcfiledir}/../.., and checked), and rbconfig's RUST_LIB build path is blanked.

Known leftover (unchanged from the published builds): the bundled OpenSSL's compiled-in OPENSSLDIR is a build-tree path, so OpenSSL looks for openssl.cnf there; certificate lookup is unaffected (the patched openssl.rb supplies the system store).

After merge

Every build changes. #16 is merged but not yet released, so one Release New Versions run with replace_all publishes both.

glibc 2.28 is the newest that still runs on Ubuntu 20.04 (2.31), the oldest
release Hatchbox provisions. Building against it lets Ruby use statx
(File.birthtime works from 2.7), copy_file_range and getrandom, which the glibc
2.17 builds compiled out, and moves off the end-of-life CentOS 7 image.

GCC 14 rejects implicit function declarations, implicit int and incompatible
pointer types, which Ruby 2.2 and older rely on (and which break their
configure checks for OpenSSL functions), so 1.8 to 2.2 downgrade those four to
warnings. Only flags GCC 8 and older also know: CFLAGS stays in rbconfig and
reaches native gems built on servers with an older compiler.

bin/package-linux keys its derived image and build volume by the container, so
a new pin doesn't reuse the old toolchain's image or dependency builds.
…g files

Merging libruby-static.a into one object (#16) made every mkmf probe link the
whole of Ruby with its debug info: ~900 MB of linker memory per have_func on
3.4, which got four-way parallel gem installs OOM-killed in a 2 GB container,
and a killed link reads as 'function missing' (json 3.0.2 then failed to
compile). Nothing debugs through this archive; stripped, a probe takes ~50 MB
(the published 2.17 builds took ~270 MB) and the archive shrinks from 156 MB to
15 MB. The installation test fails if it has debug sections again.

The pkg-config files copied from the dependencies and Ruby's ruby-X.pc named the
build tree; point them at ${pcfiledir}/../.. like the rest, and check it.
Also blank rbconfig's RUST_LIB, a build-tree path only Ruby's own build uses.
@excid3
excid3 merged commit 9a486d0 into main Sep 30, 2026
37 checks passed
@excid3
excid3 deleted the glibc-2.28 branch September 30, 2026 20:40
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