diff options
author | DavHau <hsngrmpf+github@gmail.com> | 2020-10-20 19:09:32 +0700 |
---|---|---|
committer | DavHau <hsngrmpf+github@gmail.com> | 2020-10-20 19:09:32 +0700 |
commit | 5c382b7f0e4705f447ac554dcfc7069849766710 (patch) | |
tree | 69757663d8c9dd6c605b1ef9f4de835863669e30 /pkgs/build-support | |
parent | a2ee5cbb0513ee0623bc93aa1af74f172080ce6b (diff) | |
download | nixlib-5c382b7f0e4705f447ac554dcfc7069849766710.tar nixlib-5c382b7f0e4705f447ac554dcfc7069849766710.tar.gz nixlib-5c382b7f0e4705f447ac554dcfc7069849766710.tar.bz2 nixlib-5c382b7f0e4705f447ac554dcfc7069849766710.tar.lz nixlib-5c382b7f0e4705f447ac554dcfc7069849766710.tar.xz nixlib-5c382b7f0e4705f447ac554dcfc7069849766710.tar.zst nixlib-5c382b7f0e4705f447ac554dcfc7069849766710.zip |
autoPatchelfHook: optimize performance, better error handling
Diffstat (limited to 'pkgs/build-support')
-rw-r--r-- | pkgs/build-support/setup-hooks/auto-patchelf.sh | 72 |
1 files changed, 45 insertions, 27 deletions
diff --git a/pkgs/build-support/setup-hooks/auto-patchelf.sh b/pkgs/build-support/setup-hooks/auto-patchelf.sh index 4f7c0c14304c..7df454f4f017 100644 --- a/pkgs/build-support/setup-hooks/auto-patchelf.sh +++ b/pkgs/build-support/setup-hooks/auto-patchelf.sh @@ -1,9 +1,16 @@ declare -a autoPatchelfLibs +declare -Ag autoPatchelfFailedDeps gatherLibraries() { autoPatchelfLibs+=("$1/lib") } +# wrapper around patchelf to raise proper error messages +# containing the tried file name and command +runPatchelf() { + patchelf $@ || (echo "Command failed: patchelf $@" && exit 1) +} + addEnvHooks "$targetOffset" gatherLibraries isExecutable() { @@ -23,14 +30,19 @@ isExecutable() { # We cache dependencies so that we don't need to search through all of them on # every consecutive call to findDependency. -declare -a cachedDependencies +declare -Ag autoPatchelfCachedDepsAssoc +declare -ag autoPatchelfCachedDeps + addToDepCache() { - local existing - for existing in "${cachedDependencies[@]}"; do - if [ "$existing" = "$1" ]; then return; fi - done - cachedDependencies+=("$1") + if [[ ${autoPatchelfCachedDepsAssoc[$1]+f} ]]; then return; fi + + # store deps in an assoc. array for efficient lookups + # otherwise findDependency would have quadratic complexity + autoPatchelfCachedDepsAssoc["$1"]="" + + # also store deps in normal array to maintian their order + autoPatchelfCachedDeps+=("$1") } declare -gi depCacheInitialised=0 @@ -43,7 +55,7 @@ getDepsFromSo() { populateCacheWithRecursiveDeps() { local so found foundso - for so in "${cachedDependencies[@]}"; do + for so in "${autoPatchelfCachedDeps[@]}"; do for found in $(getDepsFromSo "$so"); do local libdir="${found%/*}" local base="${found##*/}" @@ -76,7 +88,7 @@ findDependency() { depCacheInitialised=1 fi - for dep in "${cachedDependencies[@]}"; do + for dep in "${autoPatchelfCachedDeps[@]}"; do if [ "$filename" = "${dep##*/}" ]; then if [ "$(getSoArch "$dep")" = "$arch" ]; then foundDependency="$dep" @@ -103,7 +115,7 @@ autoPatchelfFile() { local interpreter="$(< "$NIX_CC/nix-support/dynamic-linker")" if isExecutable "$toPatch"; then - patchelf --set-interpreter "$interpreter" "$toPatch" + runPatchelf --set-interpreter "$interpreter" "$toPatch" if [ -n "$runtimeDependencies" ]; then for dep in $runtimeDependencies; do rpath="$rpath${rpath:+:}$dep/lib" @@ -115,7 +127,7 @@ autoPatchelfFile() { # We're going to find all dependencies based on ldd output, so we need to # clear the RPATH first. - patchelf --remove-rpath "$toPatch" + runPatchelf --remove-rpath "$toPatch" local missing="$( ldd "$toPatch" 2> /dev/null | \ @@ -134,18 +146,13 @@ autoPatchelfFile() { echo "found: $foundDependency" >&2 else echo "not found!" >&2 - depNotFound=1 + autoPatchelfFailedDeps["$dep"]="" fi done - # This makes sure the builder fails if we didn't find a dependency, because - # the stdenv setup script is run with set -e. The actual error is emitted - # earlier in the previous loop. - [ $depNotFound -eq 0 -o -n "$autoPatchelfIgnoreMissingDeps" ] - if [ -n "$rpath" ]; then echo "setting RPATH to: $rpath" >&2 - patchelf --set-rpath "$rpath" "$toPatch" + runPatchelf --set-rpath "$rpath" "$toPatch" fi } @@ -168,10 +175,10 @@ addAutoPatchelfSearchPath() { esac done - cachedDependencies+=( - $(find "$@" "${findOpts[@]}" \! -type d \ - \( -name '*.so' -o -name '*.so.*' \)) - ) + for file in \ + $(find "$@" "${findOpts[@]}" \! -type d \ + \( -name '*.so' -o -name '*.so.*' \)) + do addToDepCache "$file"; done } autoPatchelf() { @@ -197,14 +204,9 @@ autoPatchelf() { echo "automatically fixing dependencies for ELF files" >&2 # Add all shared objects of the current output path to the start of - # cachedDependencies so that it's choosen first in findDependency. + # autoPatchelfCachedDeps so that it's choosen first in findDependency. addAutoPatchelfSearchPath ${norecurse:+--no-recurse} -- "$@" - # Here we actually have a subshell, which also means that - # $cachedDependencies is final at this point, so whenever we want to run - # findDependency outside of this, the dependency cache needs to be rebuilt - # from scratch, so keep this in mind if you want to run findDependency - # outside of this function. while IFS= read -r -d $'\0' file; do isELF "$file" || continue segmentHeaders="$(LANG=C $READELF -l "$file")" @@ -215,8 +217,24 @@ autoPatchelf() { # Skip if the executable is statically linked. [ -n "$(echo "$segmentHeaders" | grep "^ *INTERP\\>")" ] || continue fi + # Jump file if patchelf is unable to parse it + # Some programs contain binary blobs for testing, + # which are identified as ELF but fail to be parsed by patchelf + patchelf $file || continue autoPatchelfFile "$file" done < <(find "$@" ${norecurse:+-maxdepth 1} -type f -print0) + + # fail if any dependencies were not found and + # autoPatchelfIgnoreMissingDeps is not set + local depsMissing=0 + for failedDep in "${!autoPatchelfFailedDeps[@]}"; do + echo "autoPatchelfHook could not satisfy dependency $failedDep" + depsMissing=1 + done + if [ $depsMissing == 1 -a -z "$autoPatchelfIgnoreMissingDeps" ]; then + echo "Add the missing dependencies to the build inputs or set autoPatchelfIgnoreMissingDeps=true" + exit 1 + fi } # XXX: This should ultimately use fixupOutputHooks but we currently don't have |