summary refs log tree commit diff
path: root/pkgs/build-support/setup-hooks/win-dll-link.sh
blob: 14594bcba93703906bbd3f301162f1e125b2217d (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
fixupOutputHooks+=(_linkDLLs)

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.
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"
    )
}