build(package): trim bundled runtime libraries
This commit is contained in:
33
Dockerfile
33
Dockerfile
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
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
|
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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user