about summary refs log tree commit diff
path: root/pkgs/build-support/setup-hooks
diff options
context:
space:
mode:
authorbrano543 <brano.masar@gmail.com>2023-08-31 01:40:11 +0200
committerArtturin <Artturin@artturin.com>2023-08-31 21:47:48 +0300
commit1086f093a94d57e5ce1db60407a7fdcf1ea047d2 (patch)
tree6b9c8d14b2af4bb0d7c01938180956f4dd9c5099 /pkgs/build-support/setup-hooks
parenta736ca31c5e31fe91adc3951ffd894a7f3a0ee71 (diff)
win-dll-links: also copy dll from dependencies
Fixes running `pkgsCross.mingwW64._7zz` in wine.

Fixes issue 38451

```
tree result/bin
result/bin
├── 7zz.exe
└── mcfgthread-12.dll -> ../../wmgj476qjfw26f9aij1d64lxrjfv6kk0-mcfgthreads-x86_64-w64-mingw32-git/bin/mcfgthread-12.dll
```

Co-authored-by: marius david <marius@mariusdavid.fr>
Diffstat (limited to 'pkgs/build-support/setup-hooks')
-rw-r--r--pkgs/build-support/setup-hooks/win-dll-link.sh122
1 files changed, 83 insertions, 39 deletions
diff --git a/pkgs/build-support/setup-hooks/win-dll-link.sh b/pkgs/build-support/setup-hooks/win-dll-link.sh
index ca4cbb349b6c0..14594bcba9370 100644
--- a/pkgs/build-support/setup-hooks/win-dll-link.sh
+++ b/pkgs/build-support/setup-hooks/win-dll-link.sh
@@ -1,45 +1,89 @@
-
 fixupOutputHooks+=(_linkDLLs)
 
-# For every *.{exe,dll} in $output/bin/ we try to find all (potential)
-# transitive dependencies and symlink those DLLs into $output/bin
-# so they are found on invocation.
+addEnvHooks "$targetOffset" linkDLLGetFolders
+
+linkDLLGetFolders() {
+    addToSearchPath "LINK_DLL_FOLDERS" "$1/lib"
+    addToSearchPath "LINK_DLL_FOLDERS" "$1/bin"
+}
+
+_linkDLLs() {
+    linkDLLsInfolder "$prefix/bin"
+}
+
+# Try to links every known dependency of exe/dll in the folder of the 1str input
+# into said folder, so they are found on invocation.
 # (DLLs are first searched in the directory of the running exe file.)
 # The links are relative, so relocating whole /nix/store won't break them.
-_linkDLLs() {
-(
-    if [ ! -d "$prefix/bin" ]; then exit; fi
-    cd "$prefix/bin"
-
-    # Compose path list where DLLs should be located:
-    #   prefix $PATH by currently-built outputs
-    local DLLPATH=""
-    local outName
-    for outName in $(getAllOutputNames); do
-        addToSearchPath DLLPATH "${!outName}/bin"
-    done
-    DLLPATH="$DLLPATH:$PATH"
-
-    echo DLLPATH="'$DLLPATH'"
-
-    linkCount=0
-    # Iterate over any DLL that we depend on.
-    local dll
-    for dll in $($OBJDUMP -p *.{exe,dll} | sed -n 's/.*DLL Name: \(.*\)/\1/p' | sort -u); do
-        if [ -e "./$dll" ]; then continue; fi
-        # Locate the DLL - it should be an *executable* file on $DLLPATH.
-        local dllPath="$(PATH="$DLLPATH" type -P "$dll")"
-        if [ -z "$dllPath" ]; then continue; fi
-        # That DLL might have its own (transitive) dependencies,
-        # so add also all DLLs from its directory to be sure.
-        local dllPath2
-        for dllPath2 in "$dllPath" "$(dirname $(readlink "$dllPath" || echo "$dllPath"))"/*.dll; do
-            if [ -e ./"$(basename "$dllPath2")" ]; then continue; fi
-            CYGWIN+=\ winsymlinks:nativestrict ln -sr "$dllPath2" .
-            linkCount=$(($linkCount+1))
+linkDLLsInfolder() {
+    (
+        local folder
+        folder="$1"
+        if [ ! -d "$folder" ]; then
+            echo "Not linking DLLs in the non-existent folder $folder"
+            return
+        fi
+        cd "$folder" || exit
+
+        # Use associative arrays as set
+        local filesToChecks
+        local filesDone
+        declare -A filesToChecks # files that still needs to have their dependancies checked
+        declare -A filesDone     # files that had their dependancies checked and who is copied to the bin folder if found
+
+        markFileAsDone() {
+            if [ ! "${filesDone[$1]+a}" ]; then filesDone[$1]=a; fi
+            if [ "${filesToChecks[$1]+a}" ]; then unset 'filesToChecks[$1]'; fi
+        }
+
+        addFileToLink() {
+            if [ "${filesDone[$1]+a}" ]; then return; fi
+            if [ ! "${filesToChecks[$1]+a}" ]; then filesToChecks[$1]=a; fi
+        }
+
+        # Compose path list where DLLs should be located:
+        #   prefix $PATH by currently-built outputs
+        local DLLPATH=""
+        local outName
+        for outName in $(getAllOutputNames); do
+            addToSearchPath DLLPATH "${!outName}/bin"
         done
-    done
-    echo "Created $linkCount DLL link(s) in $prefix/bin"
-)
-}
+        DLLPATH="$DLLPATH:$LINK_DLL_FOLDERS"
+
+        echo DLLPATH="'$DLLPATH'"
+
+        for peFile in *.{exe,dll}; do
+            if [ -e "./$peFile" ]; then
+                addFileToLink "$peFile"
+            fi
+        done
+
+        local searchPaths
+        readarray -td: searchPaths < <(printf -- "%s" "$DLLPATH")
 
+        local linkCount=0
+        while [ ${#filesToChecks[*]} -gt 0 ]; do
+            local listOfDlls=("${!filesToChecks[@]}")
+            local file=${listOfDlls[0]}
+            markFileAsDone "$file"
+            if [ ! -e "./$file" ]; then
+                local pathsFound
+                readarray -d '' pathsFound < <(find "${searchPaths[@]}" -name "$file" -type f -print0)
+                if [ ${#pathsFound[@]} -eq 0 ]; then continue; fi
+                local dllPath
+                dllPath="${pathsFound[0]}"
+                CYGWIN+=" winsymlinks:nativestrict" ln -sr "$dllPath" .
+                echo "linking $dllPath"
+                file="$dllPath"
+                linkCount=$((linkCount + 1))
+            fi
+            # local dep_file
+            # Look at the file’s dependancies
+            for dep_file in $($OBJDUMP -p "$file" | sed -n 's/.*DLL Name: \(.*\)/\1/p' | sort -u); do
+                addFileToLink "$dep_file"
+            done
+        done
+
+        echo "Created $linkCount DLL link(s) in $folder"
+    )
+}