Merge pull request #50802 from aszlig/autopatchelf-improvements
autoPatchelfHook: Fixes/improvements for Android SDK emulator
This commit is contained in:
commit
afbdeb7b9b
2 changed files with 83 additions and 15 deletions
|
@ -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>
|
||||
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.
|
||||
<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>
|
||||
|
|
|
@ -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
|
||||
')
|
||||
|
|
Loading…
Reference in a new issue