···38declare -Ag autoPatchelfCachedDepsAssoc
39declare -ag autoPatchelfCachedDeps
4041-42addToDepCache() {
43 if [[ ${autoPatchelfCachedDepsAssoc[$1]+f} ]]; then return; fi
44···54declare -gi doneRecursiveSearch=0
55declare -g foundDependency
5657-getDepsFromSo() {
58- ldd "$1" 2> /dev/null | sed -n -e 's/[^=]*=> *\(.\+\) \+([^)]*)$/\1/p'
0059}
6061-populateCacheWithRecursiveDeps() {
62- local so found foundso
63- for so in "${autoPatchelfCachedDeps[@]}"; do
64- for found in $(getDepsFromSo "$so"); do
65- local base="${found##*/}"
66- local soname="${base%.so*}"
67- for foundso in "${found%/*}/$soname".so*; do
000000000000000000000000068 addToDepCache "$foundso"
69 done
0000070 done
71 done
000000000000072}
7374getSoArch() {
75- objdump -f "$1" | sed -ne 's/^architecture: *\([^,]\+\).*/\1/p'
76}
7778# NOTE: If you want to use this function outside of the autoPatchelf function,
···130 fi
131 fi
132000133 echo "searching for dependencies of $toPatch" >&2
134135- # We're going to find all dependencies based on ldd output, so we need to
136- # clear the RPATH first.
137- runPatchelf --remove-rpath "$toPatch"
138-139- # If the file is not a dynamic executable, ldd/sed will fail,
140- # in which case we return, since there is nothing left to do.
141 local missing
142- missing="$(
143- ldd "$toPatch" 2> /dev/null | \
144- sed -n -e 's/^[\t ]*\([^ ]\+\) => not found.*/\1/p'
145- )" || return 0
146147 # This ensures that we get the output of all missing dependencies instead
148 # of failing at the first one, because it's more useful when working on a
149 # new package where you don't yet know its dependencies.
150151 for dep in $missing; do
000000152 echo -n " $dep -> " >&2
153 if findDependency "$dep" "$(getSoArch "$toPatch")"; then
154 rpath="$rpath${rpath:+:}${foundDependency%/*}"
···185 done
186187 while IFS= read -r -d '' file; do
188- addToDepCache "$file"
189 done < <(find "$@" "${findOpts[@]}" \! -type d \
190 \( -name '*.so' -o -name '*.so.*' \) -print0)
191}
···221 segmentHeaders="$(LANG=C $READELF -l "$file")"
222 # Skip if the ELF file doesn't have segment headers (eg. object files).
223 # not using grep -q, because it can cause Broken pipe
224- [ -n "$(echo "$segmentHeaders" | grep '^Program Headers:')" ] || continue
225 if isExecutable "$file"; then
226 # Skip if the executable is statically linked.
227- [ -n "$(echo "$segmentHeaders" | grep "^ *INTERP\\>")" ] || continue
228 fi
229 # Jump file if patchelf is unable to parse it
230 # Some programs contain binary blobs for testing,
···256# So what we do here is basically run in postFixup and emulate the same
257# behaviour as fixupOutputHooks because the setup hook for patchelf is run in
258# fixupOutput and the postFixup hook runs later.
000259postFixupHooks+=('
260 if [ -z "${dontAutoPatchelf-}" ]; then
261 autoPatchelf -- $(for output in $outputs; do
···38declare -Ag autoPatchelfCachedDepsAssoc
39declare -ag autoPatchelfCachedDeps
40041addToDepCache() {
42 if [[ ${autoPatchelfCachedDepsAssoc[$1]+f} ]]; then return; fi
43···53declare -gi doneRecursiveSearch=0
54declare -g foundDependency
5556+getDepsFromElfBinary() {
57+ # NOTE: This does not use runPatchelf because it may encounter non-ELF
58+ # files. Caller is expected to check the return code if needed.
59+ patchelf --print-needed "$1" 2> /dev/null
60}
6162+getRpathFromElfBinary() {
63+ # NOTE: This does not use runPatchelf because it may encounter non-ELF
64+ # files. Caller is expected to check the return code if needed.
65+ local rpath
66+ rpath="$(patchelf --print-rpath "$1" 2> /dev/null)" || return $?
67+68+ local IFS=':'
69+ printf "%s\n" $rpath
70+}
71+72+populateCacheForDep() {
73+ local so="$1"
74+ local rpath found
75+ rpath="$(getRpathFromElfBinary "$so")" || return 1
76+77+ for found in $(getDepsFromElfBinary "$so"); do
78+ local rpathElem
79+ for rpathElem in $rpath; do
80+ # Ignore empty element or $ORIGIN magic variable which should be
81+ # deterministically resolved by adding this package's library
82+ # files early anyway.
83+ #
84+ # shellcheck disable=SC2016
85+ # (Expressions don't expand in single quotes, use double quotes for
86+ # that.)
87+ if [[ -z "$rpathElem" || "$rpathElem" == *'$ORIGIN'* ]]; then
88+ continue
89+ fi
90+91+ local soname="${found%.so*}"
92+ local foundso=
93+ for foundso in "$rpathElem/$soname".so*; do
94 addToDepCache "$foundso"
95 done
96+97+ # Found in this element of the rpath, no need to check others.
98+ if [ -n "$foundso" ]; then
99+ break
100+ fi
101 done
102 done
103+104+ # Not found in any rpath element.
105+ return 1
106+}
107+108+populateCacheWithRecursiveDeps() {
109+ # Dependencies may add more to the end of this array, so we use a counter
110+ # with while instead of a regular for loop here.
111+ local -i i=0
112+ while [ $i -lt ${#autoPatchelfCachedDeps[@]} ]; do
113+ populateCacheForDep "${autoPatchelfCachedDeps[$i]}"
114+ i=$i+1
115+ done
116}
117118getSoArch() {
119+ $OBJDUMP -f "$1" | sed -ne 's/^architecture: *\([^,]\+\).*/\1/p'
120}
121122# NOTE: If you want to use this function outside of the autoPatchelf function,
···174 fi
175 fi
176177+ local libcLib
178+ libcLib="$(< "$NIX_CC/nix-support/orig-libc")/lib"
179+180 echo "searching for dependencies of $toPatch" >&2
181000000182 local missing
183+ missing="$(getDepsFromElfBinary "$toPatch")" || return 0
000184185 # This ensures that we get the output of all missing dependencies instead
186 # of failing at the first one, because it's more useful when working on a
187 # new package where you don't yet know its dependencies.
188189 for dep in $missing; do
190+ # Check whether this library exists in libc. If so, we don't need to do
191+ # any futher searching -- it will be resolved correctly by the linker.
192+ if [ -f "$libcLib/$dep" ]; then
193+ continue
194+ fi
195+196 echo -n " $dep -> " >&2
197 if findDependency "$dep" "$(getSoArch "$toPatch")"; then
198 rpath="$rpath${rpath:+:}${foundDependency%/*}"
···229 done
230231 while IFS= read -r -d '' file; do
232+ addToDepCache "$file"
233 done < <(find "$@" "${findOpts[@]}" \! -type d \
234 \( -name '*.so' -o -name '*.so.*' \) -print0)
235}
···265 segmentHeaders="$(LANG=C $READELF -l "$file")"
266 # Skip if the ELF file doesn't have segment headers (eg. object files).
267 # not using grep -q, because it can cause Broken pipe
268+ grep -q '^Program Headers:' <<<"$segmentHeaders" || continue
269 if isExecutable "$file"; then
270 # Skip if the executable is statically linked.
271+ grep -q "^ *INTERP\\>" <<<"$segmentHeaders" || continue
272 fi
273 # Jump file if patchelf is unable to parse it
274 # Some programs contain binary blobs for testing,
···300# So what we do here is basically run in postFixup and emulate the same
301# behaviour as fixupOutputHooks because the setup hook for patchelf is run in
302# fixupOutput and the postFixup hook runs later.
303+#
304+# shellcheck disable=SC2016
305+# (Expressions don't expand in single quotes, use double quotes for that.)
306postFixupHooks+=('
307 if [ -z "${dontAutoPatchelf-}" ]; then
308 autoPatchelf -- $(for output in $outputs; do