Skip to content

bklibcvenv: hermetic glibc helper (analogue to bkpyvenv) #344

Description

@tannevaled

Summary

Propose a brewkit helper libexec/bklibcvenv that lets a recipe produce a binary bottle whose runtime libc is fully hermetic — i.e. the binaries always use the bundled gnu.org/glibc@X.Y regardless of what the host has. Same shape as the existing libexec/bkpyvenv (two-phase stage / seal), and aligned with the pattern @codex described in #342:

Hermetic binary: use a wrapper:

exec "$prefix/lib/ld-linux-x86-64.so.2" \
  --library-path "$prefix/lib:$other_libs" \
  "$prefix/libexec/foo" "\$@"

The inner ELF can even have a dummy/system PT_INTERP; the wrapper explicitly invokes the loader.

Context

Triggered by:

Proposed API

Mirror bkpyvenv:

# In a recipe's build.script, after make install:
- bklibcvenv stage {{prefix}}           # sets CC/CXX/CPP/SYSROOT for hermetic build
- ../configure --prefix={{prefix}}  # (already wired through CC etc.)
- make && make install
- bklibcvenv seal  {{prefix}}           # bin/* → libexec/*; bin/* becomes shell wrappers

Phase 1: `bklibcvenv stage `

  • Resolve the glibc bottle prefix (from `build.dependencies.gnu.org/glibc` resolution, env-injected by brewkit)
  • Determine arch's LDSO (`ld-linux-x86-64.so.2` / `ld-linux-aarch64.so.1`) and LIBDIR (`/lib/glibc-X.Y/`)
  • Export:
    • `SYSROOT=`
    • `CC="$CC -nostdinc -isystem /include -L -Wl,--rpath= -Wl,--dynamic-linker=/"`
    • `CXX="$CXX …"` similarly
    • `CPP="$CPP -nostdinc -isystem …"`

Phase 2: `bklibcvenv seal `

For every ELF executable in `$prefix/bin/`:

  1. `mv $prefix/bin/foo → $prefix/libexec/foo`

  2. Write `$prefix/bin/foo`:

    #!/bin/sh
    here=\"\$(cd \"\$(dirname \"\$0\")\" && pwd)\"
    exec \"\$here/../lib/glibc-X.Y/<LDSO>\" \
      --library-path \"\$here/../lib/glibc-X.Y:\$here/../lib\" \
      \"\$here/../libexec/\$(basename \"\$0\")\" \"\$@\"
  3. `chmod +x $prefix/bin/foo`

Skip symlinks, skip non-ELFs (shell scripts already handled by `fix-shebangs.ts`).

Relation to @jhheider's default-glibc plan

These compose orthogonally:

Layer Mechanism Who needs it
Build defaults to glibc 2.17 (forward-compat baseline) brewkit `useShellEnv` injection (no recipe change) ~95% of recipes
Override glibc version `build.dependencies.gnu.org/glibc: '>=2.34'` A few recipes needing newer symbols
Opt out entirely `build.skip: linux-glibc` (like `skip: fix-machos`) Rare — libc-less Go binaries, kernel modules
Hermetic binary (host glibc never touched at runtime) `bklibcvenv` Numerical / scientific packages, packages that must run on Alpine + Debian + RHEL identically

`bklibcvenv` is purely opt-in — recipes that don't need runtime hermeticity simply don't call it.

Pilot recipes

Candidates that would benefit and could validate the helper:

  • Something with C extensions and tight glibc-symbol coupling (numpy.org?)
  • A scientific computing lib that has to work on HPC clusters (manylinux2014 era)
  • llm.cpp or similar ML inference binary that ships a self-contained tarball today

Open questions

  1. Wrapper language: pure POSIX `sh` (least dependency, slowest startup) vs a tiny compiled wrapper (faster, but bootstrap problem). Lean toward `sh` like `fix-shebangs.ts` output, but worth discussing.
  2. `--library-path` content: only the bundled glibc's LIBDIR, or also `$prefix/lib` for the bottle's own non-libc shared libs? Probably both — but order matters (loader resolves left-to-right).
  3. Detecting "this prefix has bklibcvenv-sealed wrappers": brewkit's auditor should know to follow `bin/foo` → `libexec/foo` and audit the inner ELF, not the wrapper.
  4. Interaction with PT_INTERP: the libexec inner ELF can keep whatever PT_INTERP it has (including `+brewing` — the wrapper ignores it). So this completely sidesteps the brewkit#342 problem.

Next steps

Happy to draft a PR for `libexec/bklibcvenv` if there's appetite. Would also need:

  • Pantry-side: at least one pilot recipe using `bklibcvenv stage` / `seal`
  • brewkit auditor: skip the wrapper's "shebang" check, follow into libexec for the real audit
  • Docs in brewkit AGENTS.md ("hermetic glibc helper, mirrors bkpyvenv")

cc @jhheider

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions