diff options
author | Jörg Thalheim <Mic92@users.noreply.github.com> | 2018-11-27 10:25:26 +0000 |
---|---|---|
committer | GitHub <noreply@github.com> | 2018-11-27 10:25:26 +0000 |
commit | afbdeb7b9b0dab1fd502407103958608c9ba1e1e (patch) | |
tree | 8bfc9d5c364a46d6461af210ade54ff234c41727 | |
parent | f12bd000b9a7f72965c726012fd0d6cca6d4c629 (diff) | |
parent | 4a6e3e4185dcbe53c3d5eceaf2570d51516ad2b4 (diff) |
Merge pull request #50802 from aszlig/autopatchelf-improvements
autoPatchelfHook: Fixes/improvements for Android SDK emulator
-rw-r--r-- | doc/stdenv.xml | 31 | ||||
-rw-r--r-- | pkgs/build-support/setup-hooks/auto-patchelf.sh | 67 |
2 files changed, 83 insertions, 15 deletions
diff --git a/doc/stdenv.xml b/doc/stdenv.xml index 40ff17aafa09..4c19b2867b5a 100644 --- a/doc/stdenv.xml +++ b/doc/stdenv.xml @@ -2428,12 +2428,31 @@ addEnvHooks "$hostOffset" myBashFunction <para> This is a special setup hook which helps in packaging proprietary software in that it automatically tries to find missing shared library - dependencies of ELF files. All packages within the - <envar>runtimeDependencies</envar> environment variable are - unconditionally added to executables, which is useful for programs that - use <citerefentry> - <refentrytitle>dlopen</refentrytitle> - <manvolnum>3</manvolnum> </citerefentry> to load libraries at runtime. + dependencies of ELF files based on the given + <varname>buildInputs</varname> and <varname>nativeBuildInputs</varname>. + </para> + <para> + You can also specify a <envar>runtimeDependencies</envar> environment + variable which lists dependencies that are unconditionally added to all + executables. + </para> + <para> + This is useful for programs that use <citerefentry> + <refentrytitle>dlopen</refentrytitle> + <manvolnum>3</manvolnum> + </citerefentry> to load libraries at runtime. + </para> + <para> + In certain situations you may want to run the main command + (<command>autoPatchelf</command>) of the setup hook on a file or a set + of directories instead of unconditionally patching all outputs. This + can be done by setting the <envar>dontAutoPatchelf</envar> environment + variable to a non-empty value. + </para> + <para> + The <command>autoPatchelf</command> command also recognizes a + <parameter class="command">--no-recurse</parameter> command line flag, + which prevents it from recursing into subdirectories. </para> </listitem> </varlistentry> diff --git a/pkgs/build-support/setup-hooks/auto-patchelf.sh b/pkgs/build-support/setup-hooks/auto-patchelf.sh index d1ae317ff9a4..5bedd1a9f9ca 100644 --- a/pkgs/build-support/setup-hooks/auto-patchelf.sh +++ b/pkgs/build-support/setup-hooks/auto-patchelf.sh @@ -147,15 +147,56 @@ autoPatchelfFile() { fi } +# Can be used to manually add additional directories with shared object files +# to be included for the next autoPatchelf invocation. +addAutoPatchelfSearchPath() { + local -a findOpts=() + + # XXX: Somewhat similar to the one in the autoPatchelf function, maybe make + # it DRY someday... + while [ $# -gt 0 ]; do + case "$1" in + --) shift; break;; + --no-recurse) shift; findOpts+=("-maxdepth" 1);; + --*) + echo "addAutoPatchelfSearchPath: ERROR: Invalid command line" \ + "argument: $1" >&2 + return 1;; + *) break;; + esac + done + + cachedDependencies+=( + $(find "$@" "${findOpts[@]}" \! -type d \ + \( -name '*.so' -o -name '*.so.*' \)) + ) +} + autoPatchelf() { + local norecurse= + + while [ $# -gt 0 ]; do + case "$1" in + --) shift; break;; + --no-recurse) shift; norecurse=1;; + --*) + echo "autoPatchelf: ERROR: Invalid command line" \ + "argument: $1" >&2 + return 1;; + *) break;; + esac + done + + if [ $# -eq 0 ]; then + echo "autoPatchelf: No paths to patch specified." >&2 + return 1 + fi + 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. - cachedDependencies+=( - $(find "$prefix" \! -type d \( -name '*.so' -o -name '*.so.*' \)) - ) - local elffile + 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 @@ -164,12 +205,15 @@ autoPatchelf() { # outside of this function. while IFS= read -r -d $'\0' file; do isELF "$file" || continue + segmentHeaders="$(LANG=C readelf -l "$file")" + # Skip if the ELF file doesn't have segment headers (eg. object files). + echo "$segmentHeaders" | grep -q '^Program Headers:' || continue if isExecutable "$file"; then # Skip if the executable is statically linked. - LANG=C readelf -l "$file" | grep -q "^ *INTERP\\>" || continue + echo "$segmentHeaders" | grep -q "^ *INTERP\\>" || continue fi autoPatchelfFile "$file" - done < <(find "$prefix" -type f -print0) + done < <(find "$@" ${norecurse:+-maxdepth 1} -type f -print0) } # XXX: This should ultimately use fixupOutputHooks but we currently don't have @@ -180,6 +224,11 @@ autoPatchelf() { # So what we do here is basically run in postFixup and emulate the same # behaviour as fixupOutputHooks because the setup hook for patchelf is run in # fixupOutput and the postFixup hook runs later. -postFixupHooks+=( - 'for output in $outputs; do prefix="${!output}" autoPatchelf; done' -) +postFixupHooks+=(' + if [ -z "$dontAutoPatchelf" ]; then + autoPatchelf -- $(for output in $outputs; do + [ -e "${!output}" ] || continue + echo "${!output}" + done) + fi +') |