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>
This commit is contained in:
parent
a736ca31c5
commit
1086f093a9
|
@ -332,7 +332,16 @@ stdenv.mkDerivation {
|
|||
setupHooks = [
|
||||
../setup-hooks/role.bash
|
||||
] ++ lib.optional (cc.langC or true) ./setup-hook.sh
|
||||
++ lib.optional (cc.langFortran or false) ./fortran-hook.sh;
|
||||
++ lib.optional (cc.langFortran or false) ./fortran-hook.sh
|
||||
++ lib.optional (targetPlatform.isWindows) (stdenv.mkDerivation {
|
||||
name = "win-dll-hook.sh";
|
||||
dontUnpack = true;
|
||||
installPhase = ''
|
||||
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib" > $out
|
||||
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib64" >> $out
|
||||
echo addToSearchPath "LINK_DLL_FOLDERS" "${cc_solib}/lib32" >> $out
|
||||
'';
|
||||
});
|
||||
|
||||
postFixup =
|
||||
# Ensure flags files exists, as some other programs cat them. (That these
|
||||
|
|
|
@ -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.
|
||||
# (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"
|
||||
addEnvHooks "$targetOffset" linkDLLGetFolders
|
||||
|
||||
# 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))
|
||||
done
|
||||
done
|
||||
echo "Created $linkCount DLL link(s) in $prefix/bin"
|
||||
)
|
||||
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.
|
||||
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
|
||||
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"
|
||||
)
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue