support/scripts/fix-rpath: parallelize patching files

Using "xargs" instead of "while read" loop allows for the patching of
files to be parallelized. This significantly reduces the amount of
time it takes to fix all the paths.  On a larger RFS(~300MB) this
script was taking 5 minutes, it now only takes about 30s on a 12 core
machine.

Signed-off-by: Victor Dumas <dumasv.dev@gmail.com>
[Thomas: take into account the suggestion of Quentin Schulz to pass
PARALLEL_JOBS through the environment down to the fix-rpath script]
Signed-off-by: Thomas Petazzoni <thomas.petazzoni@bootlin.com>
This commit is contained in:
Victor Dumas 2022-10-20 13:55:12 +02:00 committed by Thomas Petazzoni
parent 552a054d45
commit 134900401f
2 changed files with 47 additions and 30 deletions

View File

@ -594,8 +594,12 @@ world: target-post-image
.PHONY: prepare-sdk .PHONY: prepare-sdk
prepare-sdk: world prepare-sdk: world
@$(call MESSAGE,"Rendering the SDK relocatable") @$(call MESSAGE,"Rendering the SDK relocatable")
PER_PACKAGE_DIR=$(PER_PACKAGE_DIR) $(TOPDIR)/support/scripts/fix-rpath host PARALLEL_JOBS=$(PARALLEL_JOBS) \
PER_PACKAGE_DIR=$(PER_PACKAGE_DIR) $(TOPDIR)/support/scripts/fix-rpath staging PER_PACKAGE_DIR=$(PER_PACKAGE_DIR) \
$(TOPDIR)/support/scripts/fix-rpath host
PARALLEL_JOBS=$(PARALLEL_JOBS) \
PER_PACKAGE_DIR=$(PER_PACKAGE_DIR) \
$(TOPDIR)/support/scripts/fix-rpath staging
$(INSTALL) -m 755 $(TOPDIR)/support/misc/relocate-sdk.sh $(HOST_DIR)/relocate-sdk.sh $(INSTALL) -m 755 $(TOPDIR)/support/misc/relocate-sdk.sh $(HOST_DIR)/relocate-sdk.sh
mkdir -p $(HOST_DIR)/share/buildroot mkdir -p $(HOST_DIR)/share/buildroot
echo $(HOST_DIR) > $(HOST_DIR)/share/buildroot/sdk-location echo $(HOST_DIR) > $(HOST_DIR)/share/buildroot/sdk-location
@ -765,7 +769,9 @@ endif
ln -sf ../usr/lib/os-release $(TARGET_DIR)/etc ln -sf ../usr/lib/os-release $(TARGET_DIR)/etc
@$(call MESSAGE,"Sanitizing RPATH in target tree") @$(call MESSAGE,"Sanitizing RPATH in target tree")
PER_PACKAGE_DIR=$(PER_PACKAGE_DIR) $(TOPDIR)/support/scripts/fix-rpath target PARALLEL_JOBS=$(PARALLEL_JOBS) \
PER_PACKAGE_DIR=$(PER_PACKAGE_DIR) \
$(TOPDIR)/support/scripts/fix-rpath target
# For a merged /usr, ensure that /lib, /bin and /sbin and their /usr # For a merged /usr, ensure that /lib, /bin and /sbin and their /usr
# counterparts are appropriately setup as symlinks ones to the others. # counterparts are appropriately setup as symlinks ones to the others.

View File

@ -46,6 +46,8 @@ Environment:
TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR TOOLCHAIN_EXTERNAL_DOWNLOAD_INSTALL_DIR
(default HOST_DIR/opt/ext-toolchain) (default HOST_DIR/opt/ext-toolchain)
PARALLEL_JOBS number of parallel jobs to run
Returns: 0 if success or 1 in case of error Returns: 0 if success or 1 in case of error
EOF EOF
@ -58,6 +60,38 @@ HOST_EXCLUDEPATHS="/share/terminfo"
STAGING_EXCLUDEPATHS="/usr/include /usr/share/terminfo" STAGING_EXCLUDEPATHS="/usr/include /usr/share/terminfo"
TARGET_EXCLUDEPATHS="/lib/firmware" TARGET_EXCLUDEPATHS="/lib/firmware"
patch_file() {
PATCHELF="${1}"
rootdir="${2}"
sanitize_extra_args="${3}"
file="${4}"
# check if it's an ELF file
rpath=$(${PATCHELF} --print-rpath "${file}" 2>&1)
if test $? -ne 0 ; then
return 0
fi
# make files writable if necessary
changed=$(chmod -c u+w "${file}")
# With per-package directory support, most RPATH of host
# binaries will point to per-package directories. This won't
# work with the --make-rpath-relative ${rootdir} invocation as
# the per-package host directory is not within ${rootdir}. So,
# we rewrite all RPATHs pointing to per-package directories so
# that they point to the global host directry.
changed_rpath=$(echo ${rpath} | sed "s@${PER_PACKAGE_DIR}/[^/]\+/host@${HOST_DIR}@")
if test "${rpath}" != "${changed_rpath}" ; then
${PATCHELF} --set-rpath ${changed_rpath} "${file}"
fi
# call patchelf to sanitize the rpath
${PATCHELF} --make-rpath-relative "${rootdir}" ${sanitize_extra_args[@]} "${file}"
# restore the original permission
test "${changed}" != "" && chmod u-w "${file}"
}
main() { main() {
local rootdir local rootdir
local tree="${1}" local tree="${1}"
@ -123,34 +157,11 @@ main() {
;; ;;
esac esac
find_args+=( "-type" "f" "-print" ) find_args+=( "-type" "f" "-print0" )
while read file ; do export -f patch_file
# check if it's an ELF file # Limit the number of cores used
rpath=$(${PATCHELF} --print-rpath "${file}" 2>&1) find "${rootdir}" ${find_args[@]} | xargs -0 -r -P ${PARALLEL_JOBS} -I {} bash -c "patch_file '${PATCHELF}' '${rootdir}' '${sanitize_extra_args}' $@" _ {}
if test $? -ne 0 ; then
continue
fi
# make files writable if necessary
changed=$(chmod -c u+w "${file}")
# With per-package directory support, most RPATH of host
# binaries will point to per-package directories. This won't
# work with the --make-rpath-relative ${rootdir} invocation as
# the per-package host directory is not within ${rootdir}. So,
# we rewrite all RPATHs pointing to per-package directories so
# that they point to the global host directry.
changed_rpath=$(echo ${rpath} | sed "s@${PER_PACKAGE_DIR}/[^/]\+/host@${HOST_DIR}@")
if test "${rpath}" != "${changed_rpath}" ; then
${PATCHELF} --set-rpath ${changed_rpath} "${file}"
fi
# call patchelf to sanitize the rpath
${PATCHELF} --make-rpath-relative "${rootdir}" ${sanitize_extra_args[@]} "${file}"
# restore the original permission
test "${changed}" != "" && chmod u-w "${file}"
done < <(find "${rootdir}" ${find_args[@]})
# Restore patched patchelf utility # Restore patched patchelf utility
test "${tree}" = "host" && mv "${PATCHELF}.__to_be_patched" "${PATCHELF}" test "${tree}" = "host" && mv "${PATCHELF}.__to_be_patched" "${PATCHELF}"