build_windows.ps1 9.9 KB
Newer Older
1
2
3
4
5
6
7
8
9
#!powershell
#
# powershell -ExecutionPolicy Bypass -File .\scripts\build_windows.ps1
#
# gcloud auth application-default login

$ErrorActionPreference = "Stop"

function checkEnv() {
10
11
12
13
14
15
16
17
18
19
20
    if ($null -ne $env:ARCH ) {
        $script:ARCH = $env:ARCH
    } else {
        $arch=([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)
        if ($null -ne $arch) {
            $script:ARCH = ($arch.ToString().ToLower()).Replace("x64", "amd64")
        } else {
            write-host "WARNING: old powershell detected, assuming amd64 architecture - set `$env:ARCH to override"
            $script:ARCH="amd64"
        }
    }
21
    $script:TARGET_ARCH=$script:ARCH
22
    Write-host "Building for ${script:TARGET_ARCH}"
23
24
    write-host "Locating required tools and paths"
    $script:SRC_DIR=$PWD
25
    if ($null -eq $env:VCToolsRedistDir) {
26
27
28
        $MSVC_INSTALL=(Get-CimInstance MSFT_VSInstance -Namespace root/cimv2/vs)[0].InstallLocation
        $env:VCToolsRedistDir=(get-item "${MSVC_INSTALL}\VC\Redist\MSVC\*")[0]
    }
29
30
31
32
    # Locate CUDA versions
    # Note: this assumes every version found will be built
    $cudaList=(get-item "C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v*\bin\" -ea 'silentlycontinue')
    if ($cudaList.length -eq 0) {
33
        $d=(get-command -ea 'silentlycontinue' nvcc).path
34
35
        if ($null -ne $d) {
            $script:CUDA_DIRS=@($d| split-path -parent)
36
37
        }
    } else {
38
        $script:CUDA_DIRS=$cudaList
39
40
    }
    
41
42
43
44
    $inoSetup=(get-item "C:\Program Files*\Inno Setup*\")
    if ($inoSetup.length -gt 0) {
        $script:INNO_SETUP_DIR=$inoSetup[0]
    }
45

46
    $script:DIST_DIR="${script:SRC_DIR}\dist\windows-${script:TARGET_ARCH}"
47
    $env:CGO_ENABLED="1"
48
    Write-Output "Checking version"
49
50
51
52
53
54
55
56
57
    if (!$env:VERSION) {
        $data=(git describe --tags --first-parent --abbrev=7 --long --dirty --always)
        $pattern="v(.+)"
        if ($data -match $pattern) {
            $script:VERSION=$matches[1]
        }
    } else {
        $script:VERSION=$env:VERSION
    }
58
    $pattern = "(\d+[.]\d+[.]\d+).*"
59
    if ($script:VERSION -match $pattern) {
60
        $script:PKG_VERSION=$matches[1]
61
    } else {
62
        $script:PKG_VERSION="0.0.0"
63
64
65
    }
    write-host "Building Ollama $script:VERSION with package version $script:PKG_VERSION"

66
67
68
69
70
71
    # Note: Windows Kits 10 signtool crashes with GCP's plugin
    if ($null -eq $env:SIGN_TOOL) {
        ${script:SignTool}="C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool.exe"
    } else {
        ${script:SignTool}=${env:SIGN_TOOL}
    }
72
    if ("${env:KEY_CONTAINER}") {
73
        ${script:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt")
74
75
76
77
78
79
80
81
        Write-host "Code signing enabled"
    } else {
        write-host "Code signing disabled - please set KEY_CONTAINERS to sign and copy ollama_inc.crt to the top of the source tree"
    }
}


function buildOllama() {
82
    if ($null -eq ${env:OLLAMA_SKIP_GENERATE}) {
83
        Remove-Item -ea 0 -recurse -force -path "${script:SRC_DIR}\dist\windows-${script:ARCH}"
Michael Yang's avatar
Michael Yang committed
84
85
86
87
88
89
90
        New-Item "${script:SRC_DIR}\dist\windows-${script:ARCH}\lib\ollama\" -ItemType Directory -ea 0


        # Default first, then conditionall ROCm and cuda v11
        write-host "Building Default native backend libraries"
         $env:CMAKE_GENERATOR="ninja"
        & cmake --preset Default
91
        if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
Michael Yang's avatar
Michael Yang committed
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
        & cmake --build --preset Default -j 12
        if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
        & cmake --install build -j 12
        
        # TODO - add steps for v11 and ROCm
        #
        # if ("$script:CUDA_DIRS".Contains("v11") -and "$script:CUDA_DIRS".Contains("v12")) {
        #     # We assume the default is v12, so override for v11
        #     $origCUDA_PATH=$env:CUDA_PATH
        #     $hashEnv = @{}
        #     Get-ChildItem env: | foreach { $hashEnv[$_.Name] = $_.Value }
        #     $hashEnv.Keys | foreach { if ($_.Contains("CUDA_PATH_V11")) { $v11="$_" }}
        #     write-host "$v11"
        #     # $env:CUDA_PATH=$hashEnv[$v11]
        #     # $env:CUDACXX=$hashEnv[$v11]+"\bin\nvcc.exe"
        #     $env:CUDAToolkit_ROOT=$hashEnv[$v11]
        #     # ls env:
        #     write-host "Building CUDA v11 backend libraries"
        #     & cmake --preset "CUDA 11"
        #     $env:CUDA_PATH=$origCUDA_PATH
        #     exit(1)
        #     if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
        #     # & cmake --build --preset "CUDA 11" -j 12
        #     # if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
        # }

        # if ($env:HIP_PATH) {
        #     write-host "Building ROCm backend libraries"
        #     $env:HIPCXX="${env:HIP_PATH}\bin\clang++.exe"
        #     $env:HIP_PLATFORM="amd"
        #     $env:CMAKE_PREFIX_PATH="${env:HIP_PATH}"
        #     & cmake --preset "ROCm"
        #     $env:HIPCXX=""
        #     $env:HIP_PLATFORM=""
        #     $env:CMAKE_PREFIX_PATH=""
        #     if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
        #     & cmake --build --preset "ROCm" -j 12
        #     if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
        # }
131
132
133
    } else {
        write-host "Skipping generate step with OLLAMA_SKIP_GENERATE set"
    }
134
    write-host "Building ollama CLI"
135
    & go build -trimpath -ldflags "-s -w -X=github.com/ollama/ollama/version.Version=$script:VERSION -X=github.com/ollama/ollama/server.mode=release" .
136
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
Michael Yang's avatar
Michael Yang committed
137
    cp .\ollama.exe "${script:DIST_DIR}\"
138
139
140
141
142
}

function buildApp() {
    write-host "Building Ollama App"
    cd "${script:SRC_DIR}\app"
143
    & windres -l 0 -o ollama.syso ollama.rc
144
    & go build -trimpath -ldflags "-s -w -H windowsgui -X=github.com/ollama/ollama/version.Version=$script:VERSION -X=github.com/ollama/ollama/server.mode=release" -o "${script:SRC_DIR}\dist\windows-${script:TARGET_ARCH}-app.exe" .
145
146
147
148
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
}

function gatherDependencies() {
149
150
151
152
153
    if ($null -eq $env:VCToolsRedistDir) {
        write-error "Unable to locate VC Install location - please use a Developer shell"
        exit 1
    }
    write-host "Gathering runtime dependencies from $env:VCToolsRedistDir"
154
    cd "${script:SRC_DIR}"
155
    md "${script:DIST_DIR}\lib\ollama" -ea 0 > $null
156
157
158

    # TODO - this varies based on host build system and MSVC version - drive from dumpbin output
    # currently works for Win11 + MSVC 2019 + Cuda V11
159
160
161
162
163
    if ($script:TARGET_ARCH -eq "amd64") {
        $depArch="x64"
    } else {
        $depArch=$script:TARGET_ARCH
    }
164
    if ($depArch -eq "x64") {
165
166
167
168
169
170
171
172
173
174
175
        cp "${env:VCToolsRedistDir}\${depArch}\Microsoft.VC*.CRT\msvcp140*.dll" "${script:DIST_DIR}\lib\ollama\"
        cp "${env:VCToolsRedistDir}\${depArch}\Microsoft.VC*.CRT\vcruntime140.dll" "${script:DIST_DIR}\lib\ollama\"
        cp "${env:VCToolsRedistDir}\${depArch}\Microsoft.VC*.CRT\vcruntime140_1.dll" "${script:DIST_DIR}\lib\ollama\"
        $llvmCrtDir="$env:VCToolsRedistDir\..\..\..\Tools\Llvm\${depArch}\bin"
        foreach ($part in $("runtime", "stdio", "filesystem", "math", "convert", "heap", "string", "time", "locale", "environment")) {
            write-host "cp ${llvmCrtDir}\api-ms-win-crt-${part}*.dll ${script:DIST_DIR}\lib\ollama\"
            cp "${llvmCrtDir}\api-ms-win-crt-${part}*.dll" "${script:DIST_DIR}\lib\ollama\"
        }
    } else {
        # Carying the dll's doesn't seem to work, so use the redist installer
        copy-item -path "${env:VCToolsRedistDir}\vc_redist.arm64.exe" -destination "${script:DIST_DIR}" -verbose
Daniel Hiltgen's avatar
Daniel Hiltgen committed
176
    }
177
178

    cp "${script:SRC_DIR}\app\ollama_welcome.ps1" "${script:SRC_DIR}\dist\"
179
180
181
}

function sign() {
182
    if ("${env:KEY_CONTAINER}") {
183
184
185
186
187
188
189
190
        write-host "Signing Ollama executables, scripts and libraries"
        & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" `
            /csp "Google Cloud KMS Provider" /kc ${env:KEY_CONTAINER} `
            $(get-childitem -path "${script:SRC_DIR}\dist" -r -include @('ollama_welcome.ps1')) `
            $(get-childitem -path "${script:SRC_DIR}\dist\windows-*" -r -include @('*.exe', '*.dll'))
        if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
    } else {
        write-host "Signing not enabled"
191
192
193
194
    }
}

function buildInstaller() {
195
196
197
198
    if ($null -eq ${script:INNO_SETUP_DIR}) {
        write-host "Inno Setup not present, skipping installer build"
        return
    }
199
200
201
202
    write-host "Building Ollama Installer"
    cd "${script:SRC_DIR}\app"
    $env:PKG_VERSION=$script:PKG_VERSION
    if ("${env:KEY_CONTAINER}") {
203
        & "${script:INNO_SETUP_DIR}\ISCC.exe" /DARCH=$script:TARGET_ARCH /SMySignTool="${script:SignTool} sign /fd sha256 /t http://timestamp.digicert.com /f ${script:OLLAMA_CERT} /csp `$qGoogle Cloud KMS Provider`$q /kc ${env:KEY_CONTAINER} `$f" .\ollama.iss
204
    } else {
205
        & "${script:INNO_SETUP_DIR}\ISCC.exe" /DARCH=$script:TARGET_ARCH .\ollama.iss
206
207
208
209
    }
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
}

210
function distZip() {
Michael Yang's avatar
Michael Yang committed
211
212
213
214
215
216
217
218
219
    if (Test-Path -Path "${script:SRC_DIR}\dist\windows-amd64") {
        write-host "Generating stand-alone distribution zip file ${script:SRC_DIR}\dist\ollama-windows-amd64.zip"
        Compress-Archive -Path "${script:SRC_DIR}\dist\windows-amd64\*" -DestinationPath "${script:SRC_DIR}\dist\ollama-windows-amd64.zip" -Force
    }

    if (Test-Path -Path "${script:SRC_DIR}\dist\windows-arm64") {
        write-host "Generating stand-alone distribution zip file ${script:SRC_DIR}\dist\ollama-windows-arm64.zip"
        Compress-Archive -Path "${script:SRC_DIR}\dist\windows-arm64\*" -DestinationPath "${script:SRC_DIR}\dist\ollama-windows-arm64.zip" -Force
    }
220
221
}

222
checkEnv
223
try {
224
225
226
227
    if ($($args.count) -eq 0) {
        buildOllama
        buildApp
        gatherDependencies
228
        sign
229
230
231
232
233
234
235
236
        buildInstaller
        distZip
    } else {
        for ( $i = 0; $i -lt $args.count; $i++ ) {
            write-host "performing $($args[$i])"
            & $($args[$i])
        } 
    }
237
238
239
240
241
242
} catch {
    write-host "Build Failed"
    write-host $_
} finally {
    set-location $script:SRC_DIR
    $env:PKG_VERSION=""
243
}