build(package): trim bundled runtime libraries

This commit is contained in:
Aethersailor
2026-06-01 18:56:10 +08:00
parent 9b65b07710
commit b9e8dea1b0
5 changed files with 142 additions and 40 deletions

View File

@@ -162,29 +162,14 @@ RUN set -xe && \
# 收集 glibc 运行时依赖(动态探测,避免固定版本) # 收集 glibc 运行时依赖(动态探测,避免固定版本)
RUN set -xe && \ RUN set -xe && \
mkdir -p /runtime-libs && \ mkdir -p /runtime-libs && \
ldd /src/subconverter /usr/lib/libmihomo.so | \ ELF_LIBRARY_PATH="/usr/lib:/lib/x86_64-linux-gnu:/usr/lib/x86_64-linux-gnu:/lib/aarch64-linux-gnu:/usr/lib/aarch64-linux-gnu:/lib64" \
awk '{for (i=1; i<=NF; i++) if ($i ~ "^/") print $i}' | \ bash /src/scripts/ci/copy-elf-runtime-deps.sh /runtime-libs \
sort -u | \ /src/subconverter \
while read -r lib; do \ /usr/lib/libmihomo.so \
if [ -e "$lib" ]; then \ libnss_dns.so.2 \
mkdir -p "/runtime-libs$(dirname "$lib")" && \ libnss_files.so.2 \
cp -aL "$lib" "/runtime-libs$lib"; \ libnss_compat.so.2 \
fi; \ libresolv.so.2 && \
done && \
for loader in /lib64/ld-linux-x86-64.so.2 /lib/x86_64-linux-gnu/ld-linux-x86-64.so.2 /lib/ld-linux-aarch64.so.1 /lib/aarch64-linux-gnu/ld-linux-aarch64.so.1; do \
if [ -e "$loader" ]; then \
mkdir -p "/runtime-libs$(dirname "$loader")" && \
cp -aL "$loader" "/runtime-libs$loader"; \
fi; \
done && \
libc_path="$(ldd /src/subconverter | awk '$1 == "libc.so.6" {print $3; exit}')" && \
libc_dir="$(dirname "${libc_path:-/lib/x86_64-linux-gnu/libc.so.6}")" && \
for extra in libnss_dns.so.2 libnss_files.so.2 libnss_compat.so.2 libresolv.so.2; do \
if [ -e "$libc_dir/$extra" ]; then \
mkdir -p "/runtime-libs$libc_dir" && \
cp -aL "$libc_dir/$extra" "/runtime-libs$libc_dir/$extra"; \
fi; \
done && \
if [ -f /etc/nsswitch.conf ]; then \ if [ -f /etc/nsswitch.conf ]; then \
mkdir -p /runtime-libs/etc && \ mkdir -p /runtime-libs/etc && \
cp -aL /etc/nsswitch.conf /runtime-libs/etc/nsswitch.conf; \ cp -aL /etc/nsswitch.conf /runtime-libs/etc/nsswitch.conf; \
@@ -215,9 +200,7 @@ RUN apk add --no-cache ca-certificates tzdata && \
COPY --from=builder /src/subconverter /usr/bin/subconverter COPY --from=builder /src/subconverter /usr/bin/subconverter
COPY --from=builder /src/base /base/ COPY --from=builder /src/base /base/
COPY --from=builder /usr/lib/libmihomo.so /usr/lib/
COPY --from=builder /runtime-libs/ / COPY --from=builder /runtime-libs/ /
COPY --from=builder /etc/nsswitch.conf /etc/nsswitch.conf
# 确保二进制和库可执行 # 确保二进制和库可执行
RUN chmod +x /usr/bin/subconverter && chmod +x /usr/lib/libmihomo.so RUN chmod +x /usr/bin/subconverter && chmod +x /usr/lib/libmihomo.so

View File

@@ -184,15 +184,14 @@ RUN set -xe && \
ln -snf /usr/share/zoneinfo/Asia/Shanghai /runtime-root/etc/localtime && \ ln -snf /usr/share/zoneinfo/Asia/Shanghai /runtime-root/etc/localtime && \
echo Asia/Shanghai > /runtime-root/etc/timezone && \ echo Asia/Shanghai > /runtime-root/etc/timezone && \
if [ -f /etc/nsswitch.conf ]; then cp -aL /etc/nsswitch.conf /runtime-root/etc/nsswitch.conf; fi && \ if [ -f /etc/nsswitch.conf ]; then cp -aL /etc/nsswitch.conf /runtime-root/etc/nsswitch.conf; fi && \
for dir in /lib/arm-linux-gnueabihf /usr/lib/arm-linux-gnueabihf /usr/arm-linux-gnueabihf/lib; do \ READELF=arm-linux-gnueabihf-readelf \
if [ -d "$dir" ]; then \ ELF_LIBRARY_PATH="/usr/lib/arm-linux-gnueabihf:/lib/arm-linux-gnueabihf:/usr/arm-linux-gnueabihf/lib:/usr/lib:/lib" \
find "$dir" -maxdepth 1 \( -name '*.so' -o -name '*.so.*' \) -print | \ bash /src/scripts/ci/copy-elf-runtime-deps.sh /runtime-root \
while read -r lib; do \ /src/subconverter \
dest="/runtime-root/usr/lib/arm-linux-gnueabihf/$(basename "$lib")"; \ libnss_dns.so.2 \
cp -aL "$lib" "$dest"; \ libnss_files.so.2 \
done; \ libnss_compat.so.2 \
fi; \ libresolv.so.2
done
# ========== FINAL STAGE ========== # ========== FINAL STAGE ==========
FROM --platform=$TARGETPLATFORM mirror.gcr.io/library/debian:trixie-slim FROM --platform=$TARGETPLATFORM mirror.gcr.io/library/debian:trixie-slim

View File

@@ -0,0 +1,126 @@
#!/usr/bin/env bash
set -euo pipefail
DEST_ROOT="${1:?destination root is required}"
shift
READELF="${READELF:-readelf}"
ELF_LIBRARY_PATH="${ELF_LIBRARY_PATH:-}"
declare -a SEARCH_DIRS=()
if [ -n "${ELF_LIBRARY_PATH}" ]; then
IFS=':' read -r -a SEARCH_DIRS <<< "${ELF_LIBRARY_PATH}"
fi
SEARCH_DIRS+=(
/lib
/usr/lib
/lib64
/usr/lib64
/lib/x86_64-linux-gnu
/usr/lib/x86_64-linux-gnu
/lib/aarch64-linux-gnu
/usr/lib/aarch64-linux-gnu
/lib/arm-linux-gnueabihf
/usr/lib/arm-linux-gnueabihf
/usr/arm-linux-gnueabihf/lib
)
declare -A COPIED=()
declare -A SCANNED=()
declare -a QUEUE=()
canonical_path() {
local path="$1"
if command -v realpath >/dev/null 2>&1; then
realpath "$path"
else
readlink -f "$path"
fi
}
copy_runtime_file() {
local source="$1"
local logical="$source"
local resolved
resolved="$(canonical_path "$source")"
if [ -n "${COPIED[$logical]:-}" ]; then
return
fi
local dest="${DEST_ROOT}${logical}"
mkdir -p "$(dirname "$dest")"
cp -aL "$source" "$dest"
COPIED["$logical"]=1
QUEUE+=("$resolved")
}
resolve_soname() {
local soname="$1"
if [[ "$soname" == */* ]] && [ -e "$soname" ]; then
printf '%s\n' "$soname"
return 0
fi
local dir candidate
for dir in "${SEARCH_DIRS[@]}"; do
[ -n "$dir" ] || continue
candidate="${dir}/${soname}"
if [ -e "$candidate" ]; then
printf '%s\n' "$candidate"
return 0
fi
done
return 1
}
copy_needed_by() {
local elf="$1"
if [ -n "${SCANNED[$elf]:-}" ]; then
return
fi
SCANNED["$elf"]=1
if ! "$READELF" -h "$elf" >/dev/null 2>&1; then
return
fi
local interp
interp="$("$READELF" -l "$elf" 2>/dev/null | sed -n 's/.*Requesting program interpreter: \(.*\)\]/\1/p' | head -n 1)"
if [ -n "$interp" ] && [ -e "$interp" ]; then
copy_runtime_file "$interp"
fi
local needed resolved
while IFS= read -r needed; do
[ -n "$needed" ] || continue
if resolved="$(resolve_soname "$needed")"; then
copy_runtime_file "$resolved"
else
echo "warning: could not resolve ELF dependency '$needed' required by $elf" >&2
fi
done < <("$READELF" -d "$elf" 2>/dev/null | sed -n 's/.*Shared library: \[\(.*\)\].*/\1/p')
}
for input in "$@"; do
if [ -e "$input" ]; then
case "$(basename "$input")" in
*.so|*.so.*|ld-*.so*|ld-linux*.so*) copy_runtime_file "$input" ;;
esac
copy_needed_by "$(canonical_path "$input")"
elif resolved="$(resolve_soname "$input")"; then
copy_runtime_file "$resolved"
else
echo "warning: could not resolve requested runtime file '$input'" >&2
fi
done
while [ "${#QUEUE[@]}" -gt 0 ]; do
current="${QUEUE[0]}"
QUEUE=("${QUEUE[@]:1}")
copy_needed_by "$current"
done

View File

@@ -25,7 +25,6 @@ chmod +x ./subconverter
case "${MODE}" in case "${MODE}" in
shared) shared)
docker cp "${CID}:/runtime-libs" ./runtime-libs docker cp "${CID}:/runtime-libs" ./runtime-libs
docker cp "${CID}:/usr/lib/libmihomo.so" ./libmihomo.so
;; ;;
root) root)
docker cp "${CID}:/runtime-root" ./runtime-root docker cp "${CID}:/runtime-root" ./runtime-root

View File

@@ -27,11 +27,6 @@ mkdir -p "${PACKAGE_DIR}"
install -m755 subconverter "${PACKAGE_DIR}/subconverter" install -m755 subconverter "${PACKAGE_DIR}/subconverter"
cp -a base "${PACKAGE_DIR}/" cp -a base "${PACKAGE_DIR}/"
if [ -f libmihomo.so ]; then
mkdir -p "${PACKAGE_DIR}/usr/lib"
install -m755 libmihomo.so "${PACKAGE_DIR}/usr/lib/libmihomo.so"
fi
copy_dir_contents runtime-libs copy_dir_contents runtime-libs
copy_dir_contents runtime-root copy_dir_contents runtime-root