cygwin-dll-link: improve symlink handling

This commit is contained in:
David McFarland
2026-02-08 19:47:26 -04:00
parent cbb96285de
commit dcebaab623
@@ -28,20 +28,24 @@ declare -Ag _linkDeps_visited
_linkDeps() {
local target="$1" dir="$2"
# canonicalise these for the dictionary
target=$(realpath -s "$target")
dir=$(realpath -s "$dir")
if [[ -v _linkDeps_visited[$target] ]]; then
echo "_linkDeps: $target was already linked." 1>&2
return
fi
if [[ ! -f "$target" || ! -x "$target" ]]; then
if [[ ! -f $target || ! -x $target ]]; then
echo "_linkDeps: $target is not an executable file, skipping." 1>&2
return
fi
local realTarget output inOutput
realTarget="$(readlink -f "$target")"
local output inOutput
for output in $outputs ; do
if [[ $realTarget == "${!output}"* ]]; then
echo "_linkDeps: $target ($realTarget) is in $output (${!output})." 1>&2
if [[ $target == "${!output}"* && ! -L $target ]]; then
echo "_linkDeps: $target is in $output (${!output})." 1>&2
inOutput=1
break
fi
@@ -51,25 +55,32 @@ _linkDeps() {
local dll
while read -r dll; do
echo ' dll:' "$dll"
if [[ -v _linkDeps_visited[$dir/$dll] ]]; then
local dllPath=$dir/$dll
if [[ -v _linkDeps_visited[$dllPath] ]]; then
echo "_linkDeps: $dll was already linked into $dir." 1>&2
continue
fi
if [[ -L "$dir/$dll" || -e "$dir/$dll" ]]; then
echo ' already exists'
_linkDeps "$dir/$dll" "$dir"
if [[ -L $dllPath ]]; then
echo ' already linked'
dllPath=$(realpath -s "$(readlink "$dllPath")")
_linkDeps "$dllPath" "$dir"
elif [[ -e $dllPath ]]; then
echo ' already exits'
_linkDeps "$dllPath" "$dir"
else
local dllPath
if [[ $dll = cygwin1.dll ]]; then
dllPath=/bin/cygwin1.dll
else
local searchPath
searchPath=$(dirname "$target"):$_linkDeps_outputPath:$_linkDeps_inputPath:$HOST_PATH
# Locate the DLL - it should be an *executable* file on $HOST_PATH.
# This intentionally doesn't use $dir because we want to prefer dependencies
# that are already linked next to the target.
if ! dllPath="$(PATH="$searchPath" type -P "$dll")"; then
if [[ -z "$inOutput" || -n "${allowedImpureDLLsMap[$dll]}" ]]; then
# This intentionally doesn't use $dir because we want to prefer
# dependencies that are already linked next to the target.
local searchPath realTarget
searchPath=$_linkDeps_outputPath:$_linkDeps_inputPath:$HOST_PATH
if [[ -L $target ]]; then
searchPath=$searchPath:$(dirname "$(readlink "$target")")
fi
searchPath=$(dirname "$target"):$searchPath
if ! dllPath=$(PATH="$searchPath" type -P "$dll"); then
if [[ -z $inOutput || -n ${allowedImpureDLLsMap[$dll]} ]]; then
continue
fi
echo unable to find "$dll" in "$searchPath" >&2
@@ -82,6 +93,7 @@ _linkDeps() {
fi
_linkDeps_visited[$dir/$dll]=1
done < <(_dllDeps "$target")
wait $!
}
# linkDLLsDir can be used to override the destination path for links. This is
@@ -94,7 +106,7 @@ linkDLLs() {
# shellcheck disable=SC2154
(
set -e
shopt -s globstar nullglob
shopt -s globstar nullglob dotglob
local -a allowedImpureDLLsArray
concatTo allowedImpureDLLsArray allowedImpureDLLs