Skip to content

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

@tannevaled

Description

@tannevaled

Summary

Propose a brewkit helper libexec/bkcvenv 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:
- bkcvenv stage {{prefix}}           # sets CC/CXX/CPP/SYSROOT for hermetic build
- ../configure --prefix={{prefix}}  # (already wired through CC etc.)
- make && make install
- bkcvenv seal  {{prefix}}           # bin/* → libexec/*; bin/* becomes shell wrappers

Phase 1: `bkcvenv 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: `bkcvenv 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) `bkcvenv` Numerical / scientific packages, packages that must run on Alpine + Debian + RHEL identically

`bkcvenv` 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 bkcvenv-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/bkcvenv` if there's appetite. Would also need:

  • Pantry-side: at least one pilot recipe using `bkcvenv 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
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions