[source] build: rework library bundling

LEDE Commits lede-commits at lists.infradead.org
Tue Jan 10 03:27:35 PST 2017


jow pushed a commit to source.git, branch master:
https://git.lede-project.org/72d751cba9cda9ce3ae46d5e6ab962d2f675e970

commit 72d751cba9cda9ce3ae46d5e6ab962d2f675e970
Author: Jo-Philipp Wich <jo at mein.io>
AuthorDate: Tue Jan 10 11:37:47 2017 +0100

    build: rework library bundling
    
    Rework the bundle-libraries.sh implementation to use a more robust approach
    for executing host binaries through the shipped ELF loader and libraries.
    
    The previous approach relied on symlinks pointing to a wrapper script which
    caused various issues, especially with multicall binaries as the original
    argv[0] name was not preserved through the ld.so invocation. Another down-
    side was the fact that the actual binaries got moved into another directory
    which caused executables to fail looking up resources with paths relative
    to the executable location.
    
    The new library wrapper implements the following improvements:
    
     - Instead of symlinks pointing to a common wrapper, each ELF executable
       is now replaced by a unqiue shell script which retains the original
       program name getting called
    
     - Instead of letting ld.so invoke the ELF executable directly, launch
       the final ELF binary through a helper program which fixes up the argv[0]
       argument for the target program
    
     - Support sharing a common location for the bundled libraries instead of
       having one copy in each directory containing wrapped binaries
    
    Finally modify the SDK build to wrap the staging_dir and toolchain binaries
    which allows to use the SDK on systems with a different glibc version.
    
    Signed-off-by: Jo-Philipp Wich <jo at mein.io>
---
 scripts/bundle-libraries.sh  | 102 +++++++++++++++++++++++++++++++------------
 target/imagebuilder/Makefile |  12 +++--
 target/sdk/Makefile          |   4 ++
 3 files changed, 87 insertions(+), 31 deletions(-)

diff --git a/scripts/bundle-libraries.sh b/scripts/bundle-libraries.sh
index aba1cd6..dfc2b85 100755
--- a/scripts/bundle-libraries.sh
+++ b/scripts/bundle-libraries.sh
@@ -2,7 +2,7 @@
 #
 #   Script to install host system binaries along with required libraries.
 #
-#   Copyright (C) 2012-2013 Jo-Philipp Wich <jo at mein.io>
+#   Copyright (C) 2012-2017 Jo-Philipp Wich <jo at mein.io>
 #
 #   This program is free software; you can redistribute it and/or modify
 #   it under the terms of the GNU General Public License as published by
@@ -27,6 +27,13 @@ _cp() {
 	}
 }
 
+_mv() {
+	mv ${VERBOSE:+-v} "$1" "$2" || {
+		echo "mv($1 $2) failed" >&2
+		exit 1
+	}
+}
+
 _md() {
 	mkdir ${VERBOSE:+-v} -p "$1" || {
 		echo "mkdir($1) failed" >&2
@@ -41,6 +48,52 @@ _ln() {
 	}
 }
 
+_relpath() {
+	local base="$(readlink -f "$1")"
+	local dest="$(readlink -f "$2")"
+	local up
+
+	[ -d "$base" ] || base="${base%/*}"
+	[ -d "$dest" ] || dest="${dest%/*}"
+
+	while true; do
+		case "$base"
+			in "$dest"/*)
+				echo "$up/${base#$dest/}"
+				break
+			;;
+			*)
+				dest="${dest%/*}"
+				up="${up:+$up/}.."
+			;;
+		esac
+	done
+}
+
+_wrapper() {
+	cat <<-EOT | ${CC:-gcc} -x c -o "$1" -
+		#include <unistd.h>
+		#include <stdio.h>
+
+		int main(int argc, char **argv) {
+			const char *self   = argv[0];
+			const char *target = argv[1];
+
+			if (argc < 3) {
+				fprintf(stderr, "Usage: %s executable arg0 [args...]\n", self);
+				return 1;
+			}
+
+			return execv(target, argv + 2);
+		}
+	EOT
+
+	[ -x "$1" ] || {
+		echo "compiling wrapper failed" >&2
+		exit 5
+	}
+}
+
 for LDD in ${PATH//://ldd }/ldd; do
 	"$LDD" --version >/dev/null 2>/dev/null && break
 	LDD=""
@@ -49,29 +102,31 @@ done
 [ -n "$LDD" -a -x "$LDD" ] || LDD=
 
 for BIN in "$@"; do
-	[ -n "$BIN" -a -x "$BIN" -a -n "$DIR" ] || {
+	[ -n "$BIN" -a -n "$DIR" ] || {
 		echo "Usage: $0 <destdir> <executable> ..." >&2
 		exit 1
 	}
 
-	[ ! -d "$DIR/bundled/lib" ] && {
-		_md "$DIR/bundled/lib"
-		_md "$DIR/bundled/usr"
-		_ln "../lib" "$DIR/bundled/usr/lib"
+	[ ! -d "$DIR/lib" ] && {
+		_md "$DIR/lib"
+		_md "$DIR/usr"
+		_ln "../lib" "$DIR/usr/lib"
+	}
+
+	[ ! -x "$DIR/lib/runas" ] && {
+		_wrapper "$DIR/lib/runas"
 	}
 
 	LDSO=""
 
-	echo "Bundling ${BIN##*/}"
-	[ -n "$LDD" ] && {
+	[ -n "$LDD" ] && [ -x "$BIN" ] && file "$BIN" | grep -sqE "ELF.*executable" && {
 		for token in $("$LDD" "$BIN" 2>/dev/null); do
 			case "$token" in */*.so*)
 				case "$token" in
 					*ld-*.so*) LDSO="${token##*/}" ;;
-					*) echo " * lib: ${token##*/}" ;;
 				esac
 
-				dest="$DIR/bundled/lib/${token##*/}"
+				dest="$DIR/lib/${token##*/}"
 				ddir="${dest%/*}"
 
 				[ -f "$token" -a ! -f "$dest" ] && {
@@ -82,29 +137,22 @@ for BIN in "$@"; do
 		done
 	}
 
-	_md "$DIR"
-
 	# is a dynamically linked executable
 	if [ -n "$LDSO" ]; then
-		_cp "$BIN" "$DIR/bundled/${BIN##*/}"
+		echo "Bundling ${BIN##*/}"
 
+		RUNDIR="$(readlink -f "$BIN")"; RUNDIR="${RUNDIR%/*}"
 		RUN="${LDSO#ld-}"; RUN="run-${RUN%%.so*}.sh"
+		REL="$(_relpath "$DIR/lib" "$BIN")"
 
-		[ -x "$DIR/bundled/$RUN" ] || {
-			cat <<-EOF > "$DIR/bundled/$RUN"
-				#!/usr/bin/env bash
-				dir="\$(dirname "\$0")"
-				bin="\$(basename "\$0")"
-				exec -a "\$0" "\$dir/bundled/lib/$LDSO" --library-path "\$dir/bundled/lib" "\$dir/bundled/\$bin" "\$@"
-			EOF
-			chmod ${VERBOSE:+-v} 0755 "$DIR/bundled/$RUN"
-		}
+		_mv "$BIN" "$RUNDIR/.${BIN##*/}.bin"
 
-		_ln "./bundled/$RUN" "$DIR/${BIN##*/}"
+		cat <<-EOF > "$BIN"
+			#!/usr/bin/env bash
+			dir="\$(dirname "\$0")"
+			exec "\$dir/${REL:+$REL/}$LDSO" --library-path "\$dir/${REL:+$REL/}" "\$dir/${REL:+$REL/}runas" "\$dir/.${BIN##*/}.bin" "\$0" "\$@"
+		EOF
 
-	# is a static executable or non-elf binary
-	else
-		[ -n "$LDD" ] && echo " * not dynamically linked"
-		_cp "$BIN" "$DIR/${BIN##*/}"
+		chmod ${VERBOSE:+-v} 0755 "$BIN"
 	fi
 done
diff --git a/target/imagebuilder/Makefile b/target/imagebuilder/Makefile
index b43662b..8a7c209 100644
--- a/target/imagebuilder/Makefile
+++ b/target/imagebuilder/Makefile
@@ -66,16 +66,20 @@ endif
 		$(PKG_BUILD_DIR)/target/linux/*/patches{,-*}
 	-cp $(KERNEL_BUILD_DIR)/* $(IB_KDIR)/ # don't copy subdirectories here
 	-cp $(LINUX_DIR)/.config $(IB_LDIR)/
-	-$(SCRIPT_DIR)/bundle-libraries.sh $(IB_LDIR)/scripts/dtc \
-	  $(LINUX_DIR)/scripts/dtc/dtc
+	if [ -x $(LINUX_DIR)/scripts/dtc/dtc ]; then \
+		$(INSTALL_DIR) $(IB_LDIR)/scripts/dtc; \
+		$(INSTALL_BIN) $(LINUX_DIR)/scripts/dtc/dtc $(IB_LDIR)/scripts/dtc/dtc; \
+	fi
 	if [ -d $(LINUX_DIR)/arch/$(ARCH)/boot/dts ]; then \
 		$(CP) $(LINUX_DIR)/arch/$(ARCH)/boot/dts/* $(IB_DTSDIR); \
 	fi
 	$(SED) 's,^# REVISION:=.*,REVISION:=$(REVISION),g' $(PKG_BUILD_DIR)/include/version.mk
 	find $(PKG_BUILD_DIR) -name CVS -o -name .git -o -name .svn \
 	  | $(XARGS) rm -rf
-	find $(STAGING_DIR_HOST)/bin -maxdepth 1 -type f -perm -u=x \
-	  | $(XARGS) $(SCRIPT_DIR)/bundle-libraries.sh $(PKG_BUILD_DIR)/staging_dir/host/bin/
+	$(INSTALL_DIR) $(PKG_BUILD_DIR)/staging_dir/host/bin
+	$(CP) $(STAGING_DIR_HOST)/bin/* $(PKG_BUILD_DIR)/staging_dir/host/bin/
+	(cd $(PKG_BUILD_DIR); find staging_dir/host/bin/ $(IB_LDIR)/scripts/dtc/ -type f | \
+		$(XARGS) $(SCRIPT_DIR)/bundle-libraries.sh $(PKG_BUILD_DIR)/staging_dir/host)
 	STRIP=sstrip $(SCRIPT_DIR)/rstrip.sh $(PKG_BUILD_DIR)/staging_dir/host/bin/
 	$(TAR) -cf - -C $(BUILD_DIR) $(IB_NAME) | xz -zc -7e > $@
 
diff --git a/target/sdk/Makefile b/target/sdk/Makefile
index de77d1a..c1eca73 100644
--- a/target/sdk/Makefile
+++ b/target/sdk/Makefile
@@ -76,6 +76,10 @@ $(BIN_DIR)/$(SDK_NAME).tar.xz: clean
 		$(SDK_DIRS) $(KERNEL_FILES) | \
 		$(TAR) -xf - -C $(SDK_BUILD_DIR)
 
+	(cd $(SDK_BUILD_DIR); find $(STAGING_SUBDIR_HOST)/bin $(STAGING_SUBDIR_HOST)/usr/bin \
+		$(STAGING_SUBDIR_TOOLCHAIN)/bin $(STAGING_SUBDIR_TOOLCHAIN)/*/bin $(STAGING_SUBDIR_TOOLCHAIN)/libexec \
+		-type f | $(XARGS) $(SCRIPT_DIR)/bundle-libraries.sh $(SDK_BUILD_DIR)/$(STAGING_SUBDIR_HOST))
+
 	@-( \
 		find \
 			$(SDK_BUILD_DIR)/$(STAGING_SUBDIR_HOST)/bin \



More information about the lede-commits mailing list