Skip to content

fix: portable Linux binaries (glibc 2.28 baseline) — Raspberry Pi & Amazon Linux 2023 out of the box#179

Merged
prmoore77 merged 6 commits into
mainfrom
feature/portable-linux-binaries
Jun 12, 2026
Merged

fix: portable Linux binaries (glibc 2.28 baseline) — Raspberry Pi & Amazon Linux 2023 out of the box#179
prmoore77 merged 6 commits into
mainfrom
feature/portable-linux-binaries

Conversation

@prmoore77

Copy link
Copy Markdown
Member

Summary

Linux release binaries previously required GLIBC_2.38 / GLIBCXX_3.4.32 (a side effect of building directly on the ubuntu-24.04 runners), so they failed on Raspberry Pi OS, Amazon Linux 2023, and anything older than ~mid-2024 with "GLIBC_2.38 not found" — workable only via loader hacks (Homebrew glibc + manual ld-linux invocation).

The Linux CI build now runs inside quay.io/pypa/manylinux_2_28 (AlmaLinux 8, glibc 2.28 baseline, gcc-toolset-14) via scripts/build_portable_linux.sh. Resulting symbol ceilings: GLIBC_2.28, GLIBCXX_3.4.22, CXXABI_1.3.11 — covering Raspberry Pi OS (bullseye and bookworm), Amazon Linux 2023, Ubuntu 20.04+, Debian 10+.

No performance impact: identical gcc 14 code generation; glibc selects its optimized SIMD routines at runtime on the target machine (IFUNC), not at build time. This is the same recipe DuckDB uses for its own portable Linux binaries.

Guard rails (every CI run)

  • scripts/build_portable_linux.sh hard-fails if any produced binary exceeds the glibc 2.28 / EL8 GLIBCXX baseline (objdump symbol-version check).
  • New smoke-test step boots the binaries in debian:bookworm-slim (the Raspberry Pi OS userland) and amazonlinux:2023 containers.

Build-system fixes this surfaced

  • Arrow + jwt-cpp ExternalProjects never received OpenSSL hints — they only found OpenSSL implicitly via system paths. Now forwarded via GIZMOSQL_EP_OPENSSL_ROOT_ARG / GIZMOSQL_EP_OPENSSL_STATIC_ARG.
  • DuckDB installed to lib64/ on Red Hat-family hosts, breaking the hard-coded third_party/duckdb/lib paths — pinned -DCMAKE_INSTALL_LIBDIR=lib.
  • The build container mounts the workspace at the host's own path so absolute paths CMake bakes into artifacts (e.g. the $<TARGET_FILE:gizmosql_client> path compiled into the test binary) stay valid when tests run on the host.
  • Static OpenSSL 3 + Boost program_options are built into a cached prefix (build/portable-deps, stamp-guarded) since EL8's system versions are too old (1.1.1 / 1.66).

Verification

  • Green CI run (all jobs): https://github.com/gizmodata/gizmosql/actions/runs/27436244714 — full integration + Python + shell test suites on the portable binaries, both arches, both channels.
  • Local end-to-end on real target userlands: server boot including runtime extension INSTALL spatial; LOAD spatial (validates DuckDB extension dlopen on the old baseline) and a client query round-trip in debian:bookworm; binary startup on amazonlinux:2023.
  • Dockerfile.ci note updated: the trixie-only base constraint is gone (any Debian 11+ base now works).

🤖 Generated with Claude Code

prmoore77 and others added 6 commits June 12, 2026 14:04
… build

Linux release binaries previously required GLIBC_2.38 / GLIBCXX_3.4.32
(built directly on ubuntu-24.04 runners), failing on Raspberry Pi OS,
Amazon Linux 2023, and anything older than ~mid-2024 with
'GLIBC_2.38 not found'.

The Linux CI build now runs inside quay.io/pypa/manylinux_2_28 (AlmaLinux 8,
glibc 2.28, gcc-toolset-14) via scripts/build_portable_linux.sh, which also
builds static OpenSSL 3 + Boost program_options into a cached prefix and
hard-fails if any produced binary exceeds the glibc 2.28 / EL8 GLIBCXX
baseline. CI smoke-tests the binaries in debian:bookworm (the Raspberry Pi
OS userland) and amazonlinux:2023 containers on every run.

Verified locally end-to-end on both userlands (server boot, extension
INSTALL/LOAD, client query). Resulting symbol maxima: GLIBC_2.28,
GLIBCXX_3.4.22, CXXABI_1.3.11.

Build-system changes this surfaced:
- Forward OPENSSL_ROOT_DIR/OPENSSL_USE_STATIC_LIBS into the Arrow and
  jwt-cpp ExternalProjects (GIZMOSQL_EP_OPENSSL_*) — they only found
  OpenSSL implicitly via system paths before.
- Pin -DCMAKE_INSTALL_LIBDIR=lib for DuckDB: Red Hat-family hosts default
  to lib64, breaking the hard-coded third_party/duckdb/lib paths.
- No perf impact: same gcc 14 codegen; glibc picks optimized routines at
  runtime via IFUNC on the target machine.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
The integration test binary embeds $<TARGET_FILE:gizmosql_client> as an
absolute path at compile time. Building at /work inside the container made
that path dangle when tests ran on the host. Mounting the workspace at the
host's own path keeps every baked-in absolute path valid.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…/work

The first portable run built at /work inside the container; its cached
CMake build trees embed that path and CMake refuses to reuse them now that
the workspace is mounted at the host path (which is stable across runs).

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
If the server did not come up within the probe deadline, ASSERT_TRUE
returned from the test with server_thread still joinable — std::thread's
destructor then called std::terminate, aborting the whole test binary
('terminate called without an active exception', exit 134). Join the
thread before asserting, and double the probe deadline to 30s for loaded
4-core CI runners.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
…citly

Inside the manylinux container (root) the cache-restored, runner-owned git
clones tripped git's 'dubious ownership' guard. That silently broke two
version detections:
- GizmoSQL's own get_latest_git_tag() (empty version)
- DuckDB's git describe → fell back to v0.0.1, so every runtime extension
  INSTALL 404'd against extensions.duckdb.org/v0.0.1/ — the cause of the
  arm64-lts test failures (env-var server init SQL INSTALL spatial,
  instrumentation json extension, fixture SetUps).

Fix both: git config safe.directory '*' inside the container, and pass
-DOVERRIDE_GIT_DESCRIBE=<tag> to DuckDB (officially supported) so its
version always equals the tag we check out, independent of git state.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@prmoore77 prmoore77 merged commit 2ec82e6 into main Jun 12, 2026
23 checks passed
@prmoore77 prmoore77 deleted the feature/portable-linux-binaries branch June 12, 2026 22:17
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