···3838declare -Ag autoPatchelfCachedDepsAssoc
3939declare -ag autoPatchelfCachedDeps
40404141-4241addToDepCache() {
4342 if [[ ${autoPatchelfCachedDepsAssoc[$1]+f} ]]; then return; fi
4443···5453declare -gi doneRecursiveSearch=0
5554declare -g foundDependency
56555757-getDepsFromSo() {
5858- ldd "$1" 2> /dev/null | sed -n -e 's/[^=]*=> *\(.\+\) \+([^)]*)$/\1/p'
5656+getDepsFromElfBinary() {
5757+ # NOTE: This does not use runPatchelf because it may encounter non-ELF
5858+ # files. Caller is expected to check the return code if needed.
5959+ patchelf --print-needed "$1" 2> /dev/null
5960}
60616161-populateCacheWithRecursiveDeps() {
6262- local so found foundso
6363- for so in "${autoPatchelfCachedDeps[@]}"; do
6464- for found in $(getDepsFromSo "$so"); do
6565- local base="${found##*/}"
6666- local soname="${base%.so*}"
6767- for foundso in "${found%/*}/$soname".so*; do
6262+getRpathFromElfBinary() {
6363+ # NOTE: This does not use runPatchelf because it may encounter non-ELF
6464+ # files. Caller is expected to check the return code if needed.
6565+ local rpath
6666+ rpath="$(patchelf --print-rpath "$1" 2> /dev/null)" || return $?
6767+6868+ local IFS=':'
6969+ printf "%s\n" $rpath
7070+}
7171+7272+populateCacheForDep() {
7373+ local so="$1"
7474+ local rpath found
7575+ rpath="$(getRpathFromElfBinary "$so")" || return 1
7676+7777+ for found in $(getDepsFromElfBinary "$so"); do
7878+ local rpathElem
7979+ for rpathElem in $rpath; do
8080+ # Ignore empty element or $ORIGIN magic variable which should be
8181+ # deterministically resolved by adding this package's library
8282+ # files early anyway.
8383+ #
8484+ # shellcheck disable=SC2016
8585+ # (Expressions don't expand in single quotes, use double quotes for
8686+ # that.)
8787+ if [[ -z "$rpathElem" || "$rpathElem" == *'$ORIGIN'* ]]; then
8888+ continue
8989+ fi
9090+9191+ local soname="${found%.so*}"
9292+ local foundso=
9393+ for foundso in "$rpathElem/$soname".so*; do
6894 addToDepCache "$foundso"
6995 done
9696+9797+ # Found in this element of the rpath, no need to check others.
9898+ if [ -n "$foundso" ]; then
9999+ break
100100+ fi
70101 done
71102 done
103103+104104+ # Not found in any rpath element.
105105+ return 1
106106+}
107107+108108+populateCacheWithRecursiveDeps() {
109109+ # Dependencies may add more to the end of this array, so we use a counter
110110+ # with while instead of a regular for loop here.
111111+ local -i i=0
112112+ while [ $i -lt ${#autoPatchelfCachedDeps[@]} ]; do
113113+ populateCacheForDep "${autoPatchelfCachedDeps[$i]}"
114114+ i=$i+1
115115+ done
72116}
7311774118getSoArch() {
7575- objdump -f "$1" | sed -ne 's/^architecture: *\([^,]\+\).*/\1/p'
119119+ $OBJDUMP -f "$1" | sed -ne 's/^architecture: *\([^,]\+\).*/\1/p'
76120}
7712178122# NOTE: If you want to use this function outside of the autoPatchelf function,
···130174 fi
131175 fi
132176177177+ local libcLib
178178+ libcLib="$(< "$NIX_CC/nix-support/orig-libc")/lib"
179179+133180 echo "searching for dependencies of $toPatch" >&2
134181135135- # We're going to find all dependencies based on ldd output, so we need to
136136- # clear the RPATH first.
137137- runPatchelf --remove-rpath "$toPatch"
138138-139139- # If the file is not a dynamic executable, ldd/sed will fail,
140140- # in which case we return, since there is nothing left to do.
141182 local missing
142142- missing="$(
143143- ldd "$toPatch" 2> /dev/null | \
144144- sed -n -e 's/^[\t ]*\([^ ]\+\) => not found.*/\1/p'
145145- )" || return 0
183183+ missing="$(getDepsFromElfBinary "$toPatch")" || return 0
146184147185 # This ensures that we get the output of all missing dependencies instead
148186 # of failing at the first one, because it's more useful when working on a
149187 # new package where you don't yet know its dependencies.
150188151189 for dep in $missing; do
190190+ # Check whether this library exists in libc. If so, we don't need to do
191191+ # any futher searching -- it will be resolved correctly by the linker.
192192+ if [ -f "$libcLib/$dep" ]; then
193193+ continue
194194+ fi
195195+152196 echo -n " $dep -> " >&2
153197 if findDependency "$dep" "$(getSoArch "$toPatch")"; then
154198 rpath="$rpath${rpath:+:}${foundDependency%/*}"
···185229 done
186230187231 while IFS= read -r -d '' file; do
188188- addToDepCache "$file"
232232+ addToDepCache "$file"
189233 done < <(find "$@" "${findOpts[@]}" \! -type d \
190234 \( -name '*.so' -o -name '*.so.*' \) -print0)
191235}
···221265 segmentHeaders="$(LANG=C $READELF -l "$file")"
222266 # Skip if the ELF file doesn't have segment headers (eg. object files).
223267 # not using grep -q, because it can cause Broken pipe
224224- [ -n "$(echo "$segmentHeaders" | grep '^Program Headers:')" ] || continue
268268+ grep -q '^Program Headers:' <<<"$segmentHeaders" || continue
225269 if isExecutable "$file"; then
226270 # Skip if the executable is statically linked.
227227- [ -n "$(echo "$segmentHeaders" | grep "^ *INTERP\\>")" ] || continue
271271+ grep -q "^ *INTERP\\>" <<<"$segmentHeaders" || continue
228272 fi
229273 # Jump file if patchelf is unable to parse it
230274 # Some programs contain binary blobs for testing,
···256300# So what we do here is basically run in postFixup and emulate the same
257301# behaviour as fixupOutputHooks because the setup hook for patchelf is run in
258302# fixupOutput and the postFixup hook runs later.
303303+#
304304+# shellcheck disable=SC2016
305305+# (Expressions don't expand in single quotes, use double quotes for that.)
259306postFixupHooks+=('
260307 if [ -z "${dontAutoPatchelf-}" ]; then
261308 autoPatchelf -- $(for output in $outputs; do