Skip to content

Commit 47eb6dd

Browse files
authored
Merge pull request #348 from tannevaled/feat/bklibcvenv
feat(libexec): bklibcvenv — extract glibc wrapper-script pattern from pantry@5354c73f
2 parents 2e18552 + 9ed9496 commit 47eb6dd

2 files changed

Lines changed: 151 additions & 0 deletions

File tree

libexec/bklibcvenv

Lines changed: 131 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,131 @@
1+
#!/usr/bin/env -S pkgx +nixos.org/patchelf bash
2+
# bklibcvenv — hermetic libc bundler for relocatable libc bottles.
3+
#
4+
# Mirror of libexec/bkpyvenv. Recipe-side helper that makes a libc
5+
# bottle (glibc, eventually musl etc.) ship its bin/* + sbin/* as
6+
# POSIX-sh wrappers that route through the bundled ld.so by relative
7+
# path, so the bottle is fully relocatable.
8+
#
9+
# Usage:
10+
# bklibcvenv seal <prefix> <libdir-name>
11+
#
12+
# Where:
13+
# <prefix> install root (e.g. {{prefix}})
14+
# <libdir-name> subdir of <prefix>/lib/ containing libc.so.6 + ld.so
15+
# (e.g. "glibc-2.43"). The script derives:
16+
# LIBC_NAME = libdir-name up to the first '-'
17+
# (so "glibc-2.43" → "glibc")
18+
# LIBC_NAME is used as the libexec subdir prefix
19+
# (libexec/<LIBC_NAME>-bin/, libexec/<LIBC_NAME>-sbin/)
20+
# so multiple libc bottles can coexist without colliding.
21+
#
22+
# Effect: for each ELF in <prefix>/{bin,sbin}/* that has a PT_INTERP,
23+
# - move it to <prefix>/libexec/<LIBC_NAME>-<dir>/
24+
# - replace <prefix>/<dir>/<name> with a POSIX sh wrapper that:
25+
# * resolves its own bindir (handles invocation by path or PATH)
26+
# * climbs to prefix
27+
# * invokes <prefix>/lib/<libdir-name>/<LDSO> --library-path …
28+
# <prefix>/libexec/<LIBC_NAME>-<dir>/<name> "$@"
29+
#
30+
# LDSO is auto-detected from `uname -m`. Override via LDSO env var
31+
# if needed (cross-arch host, exotic loader name, etc.).
32+
#
33+
# Refs: pkgxdev/brewkit#344 (RFC), pkgxdev/pantry@5354c73f (the
34+
# inline-in-glibc-recipe origin of this pattern by @jhheider).
35+
36+
set -eo pipefail
37+
38+
if [ $# -lt 1 ]; then
39+
echo "bklibcvenv: missing subcommand" >&2
40+
echo "usage: $0 seal <prefix> <libdir-name>" >&2
41+
exit 64
42+
fi
43+
44+
CMD=$1
45+
shift
46+
47+
# Optional debug tracing — opt-in via env to avoid log noise.
48+
[ -n "${BKLIBCVENV_DEBUG:-}" ] && set -x
49+
50+
# sed-replacement-safe escape. Backslashes, ampersands, and the
51+
# `|` delimiter need to be quoted in the replacement-half of an
52+
# `s|…|…|g`. Without escaping a value like `foo&bar` would be
53+
# replaced by sed's match-back-reference; `foo\1bar` similarly
54+
# breaks. In practice our values are tightly controlled (LDSO,
55+
# LIBDIR_NAME etc. come from arch/version, never user input), so
56+
# this is defense in depth.
57+
sed_escape() {
58+
printf '%s\n' "$1" | sed -e 's/[\\&|]/\\&/g'
59+
}
60+
61+
case "$CMD" in
62+
seal)
63+
if [ $# -lt 2 ]; then
64+
echo "bklibcvenv seal: missing args" >&2
65+
echo "usage: $0 seal <prefix> <libdir-name>" >&2
66+
exit 64
67+
fi
68+
69+
PREFIX=$1
70+
LIBDIR_NAME=$2
71+
72+
# Auto-detect ld.so name from arch. Override-able via LDSO env.
73+
if [ -z "${LDSO:-}" ]; then
74+
case "$(uname -m)" in
75+
x86_64) LDSO=ld-linux-x86-64.so.2 ;;
76+
aarch64|arm64) LDSO=ld-linux-aarch64.so.1 ;;
77+
armv7*|armhf) LDSO=ld-linux-armhf.so.3 ;;
78+
i686|i386) LDSO=ld-linux.so.2 ;;
79+
*) echo "bklibcvenv: unsupported arch $(uname -m); set LDSO env" >&2; exit 1 ;;
80+
esac
81+
fi
82+
83+
# libc name from libdir's first dash-separated component.
84+
LIBC_NAME=${LIBDIR_NAME%%-*}
85+
86+
# Locate the wrapper template (share/brewkit/libcvenv-wrapper.sh).
87+
SELF_DIR=$(CDPATH= cd "$(dirname "$0")" && pwd)
88+
TEMPLATE="$SELF_DIR/../share/brewkit/libcvenv-wrapper.sh"
89+
if [ ! -f "$TEMPLATE" ]; then
90+
echo "bklibcvenv: wrapper template not found at $TEMPLATE" >&2
91+
exit 2
92+
fi
93+
94+
# Escape sed-replacement values once up-front.
95+
LDSO_ESC=$(sed_escape "$LDSO")
96+
LIBDIR_ESC=$(sed_escape "$LIBDIR_NAME")
97+
LIBC_ESC=$(sed_escape "$LIBC_NAME")
98+
99+
for dir in bin sbin; do
100+
[ -d "$PREFIX/$dir" ] || continue
101+
mkdir -p "$PREFIX/libexec/$LIBC_NAME-$dir"
102+
103+
for f in "$PREFIX/$dir"/*; do
104+
[ -f "$f" ] && [ ! -L "$f" ] || continue
105+
# Skip non-ELF (shell scripts, etc.) — patchelf exits non-zero
106+
# when the file isn't an ELF with a PT_INTERP.
107+
patchelf --print-interpreter "$f" >/dev/null 2>&1 || continue
108+
109+
name=$(basename "$f")
110+
mv "$f" "$PREFIX/libexec/$LIBC_NAME-$dir/"
111+
112+
DIR_ESC=$(sed_escape "$dir")
113+
sed \
114+
-e "s|@LDSO@|$LDSO_ESC|g" \
115+
-e "s|@LIBDIR@|$LIBDIR_ESC|g" \
116+
-e "s|@LIBC_NAME@|$LIBC_ESC|g" \
117+
-e "s|@DIR@|$DIR_ESC|g" \
118+
"$TEMPLATE" > "$f"
119+
chmod 755 "$f"
120+
121+
echo "wrapped $f"
122+
done
123+
done
124+
;;
125+
126+
*)
127+
echo "bklibcvenv: unknown subcommand '$CMD'" >&2
128+
echo "usage: $0 seal <prefix> <libdir-name>" >&2
129+
exit 64
130+
;;
131+
esac

share/brewkit/libcvenv-wrapper.sh

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
#!/bin/sh
2+
# Template for bklibcvenv-generated wrappers. Pure POSIX sh — no
3+
# `--` end-of-options markers (POSIX doesn't specify them for `cd`
4+
# or `command -v`; some old /bin/sh implementations reject them).
5+
#
6+
# Replaced by `bklibcvenv seal`:
7+
# @LDSO@ e.g. ld-linux-x86-64.so.2
8+
# @LIBDIR@ e.g. glibc-2.43 (subdir of $prefix/lib/)
9+
# @LIBC_NAME@ e.g. glibc (prefix for libexec/<libc>-<dir>/)
10+
# @DIR@ e.g. bin (or sbin)
11+
12+
case "$0" in
13+
*/*) bindir=${0%/*} ;;
14+
*) bindir=$(command -v "$0"); bindir=${bindir%/*} ;;
15+
esac
16+
17+
prefix=$(CDPATH= cd "$bindir/.." && pwd)
18+
libdir="$prefix/lib/@LIBDIR@"
19+
20+
exec "$libdir/@LDSO@" --library-path "$libdir" "$prefix/libexec/@LIBC_NAME@-@DIR@/$(basename "$0")" "$@"

0 commit comments

Comments
 (0)