Skip to content

Commit 1086f09

Browse files
brano543marius851000
authored andcommitted
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>
1 parent a736ca3 commit 1086f09

2 files changed

Lines changed: 93 additions & 40 deletions

File tree

pkgs/build-support/cc-wrapper/default.nix

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -332,7 +332,16 @@ stdenv.mkDerivation {
332332
setupHooks = [
333333
../setup-hooks/role.bash
334334
] ++ lib.optional (cc.langC or true) ./setup-hook.sh
335-
++ lib.optional (cc.langFortran or false) ./fortran-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+
});
336345

337346
postFixup =
338347
# Ensure flags files exists, as some other programs cat them. (That these
Lines changed: 83 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -1,45 +1,89 @@
1-
21
fixupOutputHooks+=(_linkDLLs)
32

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.
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.
716
# (DLLs are first searched in the directory of the running exe file.)
817
# 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))
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"
4050
done
41-
done
42-
echo "Created $linkCount DLL link(s) in $prefix/bin"
43-
)
44-
}
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")
4563

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+
}

0 commit comments

Comments
 (0)