cygwin-dll-link: allow linkDLLs to be used on individual dirs/files

This commit is contained in:
David McFarland
2026-02-08 19:47:26 -04:00
parent f5353dd50e
commit cbb96285de
@@ -24,39 +24,74 @@ _dllDeps() {
| sort -u
}
declare -Ag _linkDeps_visited
_linkDeps() {
local target="$1" dir="$2" check="$3"
[[ ! -x "$target" ]] && echo "_linkDeps: $target is not executable, skipping." 1>&2 && return
local target="$1" dir="$2"
if [[ -v _linkDeps_visited[$target] ]]; then
echo "_linkDeps: $target was already linked." 1>&2
return
fi
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")"
for output in $outputs ; do
if [[ $realTarget == "${!output}"* ]]; then
echo "_linkDeps: $target ($realTarget) is in $output (${!output})." 1>&2
inOutput=1
break
fi
done
echo 'target:' "$target"
local dll
_dllDeps "$target" | while read -r dll; do
while read -r dll; do
echo ' dll:' "$dll"
if [[ -L "$dir/$dll" || -e "$dir/$dll" ]]; then continue; fi
if [[ $dll = cygwin1.dll ]]; then
CYGWIN+=\ winsymlinks:nativestrict ln -sr /bin/cygwin1.dll "$dir"
if [[ -v _linkDeps_visited[$dir/$dll] ]]; then
echo "_linkDeps: $dll was already linked into $dir." 1>&2
continue
fi
# Locate the DLL - it should be an *executable* file on $HOST_PATH.
local dllPath searchPath
searchPath=$(dirname "$target"):$_linkDeps_outputPath:$_linkDeps_inputPath:$HOST_PATH
if ! dllPath="$(PATH="$searchPath" type -P "$dll")"; then
if [[ -z "$check" || -n "${allowedImpureDLLsMap[$dll]}" ]]; then
continue
if [[ -L "$dir/$dll" || -e "$dir/$dll" ]]; then
echo ' already exists'
_linkDeps "$dir/$dll" "$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
continue
fi
echo unable to find "$dll" in "$searchPath" >&2
exit 1
fi
fi
echo unable to find "$dll" in "$searchPath" >&2
exit 1
echo ' linking to:' "$dllPath"
CYGWIN+=\ winsymlinks:nativestrict ln -sr "$dllPath" "$dir"
_linkDeps "$dllPath" "$dir"
fi
echo ' linking to:' "$dllPath"
CYGWIN+=\ winsymlinks:nativestrict ln -sr "$dllPath" "$dir"
# That DLL might have its own (transitive) dependencies,
# so add also all DLLs from its directory to be sure.
_linkDeps "$dllPath" "$dir" ""
done
_linkDeps_visited[$dir/$dll]=1
done < <(_dllDeps "$target")
}
# linkDLLsDir can be used to override the destination path for links. This is
# useful if you're trying to link dependencies of libraries into the directory
# containing an executable.
#
# Arguments can be a file or directory path. Directories are searched
# recursively.
linkDLLs() {
# shellcheck disable=SC2154
if [ ! -d "$prefix" ]; then return; fi
(
set -e
shopt -s globstar nullglob
@@ -70,15 +105,26 @@ linkDLLs() {
allowedImpureDLLsMap[$dll]=1
done
cd "$prefix"
# Iterate over any DLL that we depend on.
local target
for target in {bin,lib,libexec}/**/*.{exe,dll}; do
[[ ! -f "$target" || ! -x "$target" ]] ||
_linkDeps "$target" "$(dirname "$target")" "1"
local target file
for target in "$@"; do
# Iterate over any DLL that we depend on.
if [[ -f "$target" ]]; then
_linkDeps "$target" "${linkDLLsDir-$(dirname "$target")}"
elif [[ -d "$target" ]]; then
for file in "${target%/}"/**/*.{exe,dll}; do
_linkDeps "$file" "${linkDLLsDir-$(dirname "$file")}"
done
else
echo "linkDLLs: $target is not a file or directory, skipping." 1>&2
fi
done
)
}
fixupOutputHooks+=(linkDLLs)
_linkDLLs() {
# shellcheck disable=SC2154
if [[ ! -d $prefix || ${dontLinkDLLs-} ]]; then return; fi
linkDLLs "$prefix"/{bin,lib,libexec}/
}
fixupOutputHooks+=(_linkDLLs)