Commit dcebaab6 authored by David McFarland's avatar David McFarland
Browse files

cygwin-dll-link: improve symlink handling

parent cbb96285
Loading
Loading
Loading
Loading
+30 −18
Original line number Diff line number Diff line
@@ -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