Merge pull request #50802 from aszlig/autopatchelf-improvements

autoPatchelfHook: Fixes/improvements for Android SDK emulator
This commit is contained in:
Jörg Thalheim 2018-11-27 10:25:26 +00:00 committed by GitHub
commit afbdeb7b9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 83 additions and 15 deletions

View File

@ -2428,12 +2428,31 @@ addEnvHooks "$hostOffset" myBashFunction
<para> <para>
This is a special setup hook which helps in packaging proprietary This is a special setup hook which helps in packaging proprietary
software in that it automatically tries to find missing shared library software in that it automatically tries to find missing shared library
dependencies of ELF files. All packages within the dependencies of ELF files based on the given
<envar>runtimeDependencies</envar> environment variable are <varname>buildInputs</varname> and <varname>nativeBuildInputs</varname>.
unconditionally added to executables, which is useful for programs that </para>
use <citerefentry> <para>
<refentrytitle>dlopen</refentrytitle> You can also specify a <envar>runtimeDependencies</envar> environment
<manvolnum>3</manvolnum> </citerefentry> to load libraries at runtime. 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> </para>
</listitem> </listitem>
</varlistentry> </varlistentry>

View File

@ -147,15 +147,56 @@ autoPatchelfFile() {
fi 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() { 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 echo "automatically fixing dependencies for ELF files" >&2
# Add all shared objects of the current output path to the start of # Add all shared objects of the current output path to the start of
# cachedDependencies so that it's choosen first in findDependency. # cachedDependencies so that it's choosen first in findDependency.
cachedDependencies+=( addAutoPatchelfSearchPath ${norecurse:+--no-recurse} -- "$@"
$(find "$prefix" \! -type d \( -name '*.so' -o -name '*.so.*' \))
)
local elffile
# Here we actually have a subshell, which also means that # Here we actually have a subshell, which also means that
# $cachedDependencies is final at this point, so whenever we want to run # $cachedDependencies is final at this point, so whenever we want to run
@ -164,12 +205,15 @@ autoPatchelf() {
# outside of this function. # outside of this function.
while IFS= read -r -d $'\0' file; do while IFS= read -r -d $'\0' file; do
isELF "$file" || continue 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 if isExecutable "$file"; then
# Skip if the executable is statically linked. # Skip if the executable is statically linked.
LANG=C readelf -l "$file" | grep -q "^ *INTERP\\>" || continue echo "$segmentHeaders" | grep -q "^ *INTERP\\>" || continue
fi fi
autoPatchelfFile "$file" 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 # 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 # 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 # behaviour as fixupOutputHooks because the setup hook for patchelf is run in
# fixupOutput and the postFixup hook runs later. # fixupOutput and the postFixup hook runs later.
postFixupHooks+=( postFixupHooks+=('
'for output in $outputs; do prefix="${!output}" autoPatchelf; done' if [ -z "$dontAutoPatchelf" ]; then
) autoPatchelf -- $(for output in $outputs; do
[ -e "${!output}" ] || continue
echo "${!output}"
done)
fi
')