build(package): trim bundled runtime libraries
This commit is contained in:
33
Dockerfile
33
Dockerfile
@@ -162,29 +162,14 @@ RUN set -xe && \
|
||||
# 收集 glibc 运行时依赖(动态探测,避免固定版本)
|
||||
RUN set -xe && \
|
||||
mkdir -p /runtime-libs && \
|
||||
ldd /src/subconverter /usr/lib/libmihomo.so | \
|
||||
awk '{for (i=1; i<=NF; i++) if ($i ~ "^/") print $i}' | \
|
||||
sort -u | \
|
||||
while read -r lib; do \
|
||||
if [ -e "$lib" ]; then \
|
||||
mkdir -p "/runtime-libs$(dirname "$lib")" && \
|
||||
cp -aL "$lib" "/runtime-libs$lib"; \
|
||||
fi; \
|
||||
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 && \
|
||||
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" \
|
||||
bash /src/scripts/ci/copy-elf-runtime-deps.sh /runtime-libs \
|
||||
/src/subconverter \
|
||||
/usr/lib/libmihomo.so \
|
||||
libnss_dns.so.2 \
|
||||
libnss_files.so.2 \
|
||||
libnss_compat.so.2 \
|
||||
libresolv.so.2 && \
|
||||
if [ -f /etc/nsswitch.conf ]; then \
|
||||
mkdir -p /runtime-libs/etc && \
|
||||
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/base /base/
|
||||
COPY --from=builder /usr/lib/libmihomo.so /usr/lib/
|
||||
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
|
||||
|
||||
@@ -184,15 +184,14 @@ RUN set -xe && \
|
||||
ln -snf /usr/share/zoneinfo/Asia/Shanghai /runtime-root/etc/localtime && \
|
||||
echo Asia/Shanghai > /runtime-root/etc/timezone && \
|
||||
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 \
|
||||
if [ -d "$dir" ]; then \
|
||||
find "$dir" -maxdepth 1 \( -name '*.so' -o -name '*.so.*' \) -print | \
|
||||
while read -r lib; do \
|
||||
dest="/runtime-root/usr/lib/arm-linux-gnueabihf/$(basename "$lib")"; \
|
||||
cp -aL "$lib" "$dest"; \
|
||||
done; \
|
||||
fi; \
|
||||
done
|
||||
READELF=arm-linux-gnueabihf-readelf \
|
||||
ELF_LIBRARY_PATH="/usr/lib/arm-linux-gnueabihf:/lib/arm-linux-gnueabihf:/usr/arm-linux-gnueabihf/lib:/usr/lib:/lib" \
|
||||
bash /src/scripts/ci/copy-elf-runtime-deps.sh /runtime-root \
|
||||
/src/subconverter \
|
||||
libnss_dns.so.2 \
|
||||
libnss_files.so.2 \
|
||||
libnss_compat.so.2 \
|
||||
libresolv.so.2
|
||||
|
||||
# ========== FINAL STAGE ==========
|
||||
FROM --platform=$TARGETPLATFORM mirror.gcr.io/library/debian:trixie-slim
|
||||
|
||||
126
scripts/ci/copy-elf-runtime-deps.sh
Normal file
126
scripts/ci/copy-elf-runtime-deps.sh
Normal 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
|
||||
@@ -25,7 +25,6 @@ chmod +x ./subconverter
|
||||
case "${MODE}" in
|
||||
shared)
|
||||
docker cp "${CID}:/runtime-libs" ./runtime-libs
|
||||
docker cp "${CID}:/usr/lib/libmihomo.so" ./libmihomo.so
|
||||
;;
|
||||
root)
|
||||
docker cp "${CID}:/runtime-root" ./runtime-root
|
||||
|
||||
@@ -27,11 +27,6 @@ mkdir -p "${PACKAGE_DIR}"
|
||||
install -m755 subconverter "${PACKAGE_DIR}/subconverter"
|
||||
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-root
|
||||
|
||||
|
||||
Reference in New Issue
Block a user