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>

authored by brano543 marius david and committed by Artturin 1086f093 a736ca31

+90 -37
+10 -1
pkgs/build-support/cc-wrapper/default.nix
··· 332 setupHooks = [ 333 ../setup-hooks/role.bash 334 ] ++ lib.optional (cc.langC or true) ./setup-hook.sh 335 - ++ lib.optional (cc.langFortran or false) ./fortran-hook.sh; 336 337 postFixup = 338 # Ensure flags files exists, as some other programs cat them. (That these
··· 332 setupHooks = [ 333 ../setup-hooks/role.bash 334 ] ++ lib.optional (cc.langC or true) ./setup-hook.sh 335 + ++ lib.optional (cc.langFortran or false) ./fortran-hook.sh 336 + ++ lib.optional (targetPlatform.isWindows) (stdenv.mkDerivation { 337 + name = "win-dll-hook.sh"; 338 + dontUnpack = true; 339 + installPhase = '' 340 + echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib" > $out 341 + echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib64" >> $out 342 + echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib32" >> $out 343 + ''; 344 + }); 345 346 postFixup = 347 # Ensure flags files exists, as some other programs cat them. (That these
+80 -36
pkgs/build-support/setup-hooks/win-dll-link.sh
··· 1 2 - fixupOutputHooks+=(_linkDLLs) 3 4 - # For every *.{exe,dll} in $output/bin/ we try to find all (potential) 5 - # transitive dependencies and symlink those DLLs into $output/bin 6 - # so they are found on invocation. 7 # (DLLs are first searched in the directory of the running exe file.) 8 # The links are relative, so relocating whole /nix/store won't break them. 9 - _linkDLLs() { 10 - ( 11 - if [ ! -d "$prefix/bin" ]; then exit; fi 12 - cd "$prefix/bin" 13 14 - # Compose path list where DLLs should be located: 15 - # prefix $PATH by currently-built outputs 16 - local DLLPATH="" 17 - local outName 18 - for outName in $(getAllOutputNames); do 19 - addToSearchPath DLLPATH "${!outName}/bin" 20 - done 21 - DLLPATH="$DLLPATH:$PATH" 22 23 - echo DLLPATH="'$DLLPATH'" 24 25 - linkCount=0 26 - # Iterate over any DLL that we depend on. 27 - local dll 28 - for dll in $($OBJDUMP -p *.{exe,dll} | sed -n 's/.*DLL Name: \(.*\)/\1/p' | sort -u); do 29 - if [ -e "./$dll" ]; then continue; fi 30 - # Locate the DLL - it should be an *executable* file on $DLLPATH. 31 - local dllPath="$(PATH="$DLLPATH" type -P "$dll")" 32 - if [ -z "$dllPath" ]; then continue; fi 33 - # That DLL might have its own (transitive) dependencies, 34 - # so add also all DLLs from its directory to be sure. 35 - local dllPath2 36 - for dllPath2 in "$dllPath" "$(dirname $(readlink "$dllPath" || echo "$dllPath"))"/*.dll; do 37 - if [ -e ./"$(basename "$dllPath2")" ]; then continue; fi 38 - CYGWIN+=\ winsymlinks:nativestrict ln -sr "$dllPath2" . 39 - linkCount=$(($linkCount+1)) 40 done 41 - done 42 - echo "Created $linkCount DLL link(s) in $prefix/bin" 43 - ) 44 - } 45
··· 1 + fixupOutputHooks+=(_linkDLLs) 2 + 3 + addEnvHooks "$targetOffset" linkDLLGetFolders 4 + 5 + linkDLLGetFolders() { 6 + addToSearchPath "LINK_DLL_FOLDERS" "$1/lib" 7 + addToSearchPath "LINK_DLL_FOLDERS" "$1/bin" 8 + } 9 10 + _linkDLLs() { 11 + linkDLLsInfolder "$prefix/bin" 12 + } 13 14 + # Try to links every known dependency of exe/dll in the folder of the 1str input 15 + # into said folder, so they are found on invocation. 16 # (DLLs are first searched in the directory of the running exe file.) 17 # The links are relative, so relocating whole /nix/store won't break them. 18 + linkDLLsInfolder() { 19 + ( 20 + local folder 21 + folder="$1" 22 + if [ ! -d "$folder" ]; then 23 + echo "Not linking DLLs in the non-existent folder $folder" 24 + return 25 + fi 26 + cd "$folder" || exit 27 28 + # Use associative arrays as set 29 + local filesToChecks 30 + local filesDone 31 + declare -A filesToChecks # files that still needs to have their dependancies checked 32 + declare -A filesDone # files that had their dependancies checked and who is copied to the bin folder if found 33 34 + markFileAsDone() { 35 + if [ ! "${filesDone[$1]+a}" ]; then filesDone[$1]=a; fi 36 + if [ "${filesToChecks[$1]+a}" ]; then unset 'filesToChecks[$1]'; fi 37 + } 38 39 + addFileToLink() { 40 + if [ "${filesDone[$1]+a}" ]; then return; fi 41 + if [ ! "${filesToChecks[$1]+a}" ]; then filesToChecks[$1]=a; fi 42 + } 43 + 44 + # Compose path list where DLLs should be located: 45 + # prefix $PATH by currently-built outputs 46 + local DLLPATH="" 47 + local outName 48 + for outName in $(getAllOutputNames); do 49 + addToSearchPath DLLPATH "${!outName}/bin" 50 + done 51 + DLLPATH="$DLLPATH:$LINK_DLL_FOLDERS" 52 + 53 + echo DLLPATH="'$DLLPATH'" 54 + 55 + for peFile in *.{exe,dll}; do 56 + if [ -e "./$peFile" ]; then 57 + addFileToLink "$peFile" 58 + fi 59 done 60 61 + local searchPaths 62 + readarray -td: searchPaths < <(printf -- "%s" "$DLLPATH") 63 + 64 + local linkCount=0 65 + while [ ${#filesToChecks[*]} -gt 0 ]; do 66 + local listOfDlls=("${!filesToChecks[@]}") 67 + local file=${listOfDlls[0]} 68 + markFileAsDone "$file" 69 + if [ ! -e "./$file" ]; then 70 + local pathsFound 71 + readarray -d '' pathsFound < <(find "${searchPaths[@]}" -name "$file" -type f -print0) 72 + if [ ${#pathsFound[@]} -eq 0 ]; then continue; fi 73 + local dllPath 74 + dllPath="${pathsFound[0]}" 75 + CYGWIN+=" winsymlinks:nativestrict" ln -sr "$dllPath" . 76 + echo "linking $dllPath" 77 + file="$dllPath" 78 + linkCount=$((linkCount + 1)) 79 + fi 80 + # local dep_file 81 + # Look at the file’s dependancies 82 + for dep_file in $($OBJDUMP -p "$file" | sed -n 's/.*DLL Name: \(.*\)/\1/p' | sort -u); do 83 + addFileToLink "$dep_file" 84 + done 85 + done 86 + 87 + echo "Created $linkCount DLL link(s) in $folder" 88 + ) 89 + }