gen_windows.ps1 13.4 KB
Newer Older
1
2
3
4
#!powershell

$ErrorActionPreference = "Stop"

Daniel Hiltgen's avatar
Daniel Hiltgen committed
5
6
7
8
9
10
11
12
13
14
15
function amdGPUs {
    if ($env:AMDGPU_TARGETS) {
        return $env:AMDGPU_TARGETS
    }
    # TODO - load from some common data file for linux + windows build consistency
    $GPU_LIST = @(
        "gfx900"
        "gfx906:xnack-"
        "gfx908:xnack-"
        "gfx90a:xnack+"
        "gfx90a:xnack-"
16
17
18
        "gfx940"
        "gfx941"
        "gfx942"
Daniel Hiltgen's avatar
Daniel Hiltgen committed
19
20
21
22
23
24
25
26
27
28
        "gfx1010"
        "gfx1012"
        "gfx1030"
        "gfx1100"
        "gfx1101"
        "gfx1102"
    )
    $GPU_LIST -join ';'
}

29
30
$script:cmakeTargets = @("ollama_llama_server")

31
function init_vars {
32
33
34
35
36
37
    if (!$script:SRC_DIR) {
        $script:SRC_DIR = $(resolve-path "..\..\")
    }
    if (!$script:llamacppDir) {
        $script:llamacppDir = "../llama.cpp"
    }
Daniel Hiltgen's avatar
Daniel Hiltgen committed
38
39
40
41
    $script:cmakeDefs = @(
        "-DBUILD_SHARED_LIBS=on",
        "-DLLAMA_NATIVE=off"
        )
42
    $script:commonCpuDefs = @("-DCMAKE_POSITION_INDEPENDENT_CODE=on")
43
    $script:ARCH = "amd64" # arm not yet supported.
44
    $script:DIST_BASE = "${script:SRC_DIR}\dist\windows-${script:ARCH}\ollama_runners"
45
    if ($env:CGO_CFLAGS -contains "-g") {
Daniel Hiltgen's avatar
Daniel Hiltgen committed
46
        $script:cmakeDefs += @("-DCMAKE_VERBOSE_MAKEFILE=on", "-DLLAMA_SERVER_VERBOSE=on", "-DCMAKE_BUILD_TYPE=RelWithDebInfo")
Daniel Hiltgen's avatar
Daniel Hiltgen committed
47
        $script:config = "RelWithDebInfo"
48
    } else {
Daniel Hiltgen's avatar
Daniel Hiltgen committed
49
        $script:cmakeDefs += @("-DLLAMA_SERVER_VERBOSE=off", "-DCMAKE_BUILD_TYPE=Release")
Daniel Hiltgen's avatar
Daniel Hiltgen committed
50
        $script:config = "Release"
51
    }
Daniel Hiltgen's avatar
Daniel Hiltgen committed
52
53
54
    if ($null -ne $env:CMAKE_SYSTEM_VERSION) {
        $script:cmakeDefs += @("-DCMAKE_SYSTEM_VERSION=${env:CMAKE_SYSTEM_VERSION}")
    }
55
56
57
58
59
    # Try to find the CUDA dir
    if ($env:CUDA_LIB_DIR -eq $null) {
        $d=(get-command -ea 'silentlycontinue' nvcc).path
        if ($d -ne $null) {
            $script:CUDA_LIB_DIR=($d| split-path -parent)
60
            $script:CUDA_INCLUDE_DIR=($script:CUDA_LIB_DIR|split-path -parent)+"\include"
61
62
63
64
65
        }
    } else {
        $script:CUDA_LIB_DIR=$env:CUDA_LIB_DIR
    }
    $script:DUMPBIN=(get-command -ea 'silentlycontinue' dumpbin).path
66
67
68
69
70
    if ($null -eq $env:CMAKE_CUDA_ARCHITECTURES) {
        $script:CMAKE_CUDA_ARCHITECTURES="50;52;61;70;75;80"
    } else {
        $script:CMAKE_CUDA_ARCHITECTURES=$env:CMAKE_CUDA_ARCHITECTURES
    }
71
72
73
74
75
76
    # 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}
    }
77
78
79
    if ("${env:KEY_CONTAINER}") {
        ${script:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt")
    }
80
81
82
83
84
}

function git_module_setup {
    # TODO add flags to skip the init/patch logic to make it easier to mod llama.cpp code in-repo
    & git submodule init
Daniel Hiltgen's avatar
Daniel Hiltgen committed
85
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
86
    & git submodule update --force "${script:llamacppDir}"
Daniel Hiltgen's avatar
Daniel Hiltgen committed
87
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
88
89
90
}

function apply_patches {
91
    # Wire up our CMakefile
92
93
    if (!(Select-String -Path "${script:llamacppDir}/CMakeLists.txt" -Pattern 'ollama')) {
        Add-Content -Path "${script:llamacppDir}/CMakeLists.txt" -Value 'add_subdirectory(../ext_server ext_server) # ollama'
94
    }
95
96
97
98
99
100
101
102
103
104
105
106

    # Apply temporary patches until fix is upstream
    $patches = Get-ChildItem "../patches/*.diff"
    foreach ($patch in $patches) {
        # Extract file paths from the patch file
        $filePaths = Get-Content $patch.FullName | Where-Object { $_ -match '^\+\+\+ ' } | ForEach-Object {
            $parts = $_ -split ' '
            ($parts[1] -split '/', 2)[1]
        }

        # Checkout each file
        foreach ($file in $filePaths) {
107
            git -C "${script:llamacppDir}" checkout $file
108
109
110
111
112
        }
    }

    # Apply each patch
    foreach ($patch in $patches) {
113
        git -C "${script:llamacppDir}" apply $patch.FullName
114
    }
115
116
117
}

function build {
118
    write-host "generating config with: cmake -S ${script:llamacppDir} -B $script:buildDir $script:cmakeDefs"
119
    & cmake --version
120
    & cmake -S "${script:llamacppDir}" -B $script:buildDir $script:cmakeDefs
Daniel Hiltgen's avatar
Daniel Hiltgen committed
121
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
122
    write-host "building with: cmake --build $script:buildDir --config $script:config $($script:cmakeTargets | ForEach-Object { `"--target`", $_ })"
123
    & cmake --build $script:buildDir --config $script:config ($script:cmakeTargets | ForEach-Object { "--target", $_ })
Daniel Hiltgen's avatar
Daniel Hiltgen committed
124
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
125
126
127
128
    # Rearrange output to be consistent between different generators
    if ($null -ne ${script:config} -And (test-path -path "${script:buildDir}/bin/${script:config}" ) ) {
        mv -force "${script:buildDir}/bin/${script:config}/*" "${script:buildDir}/bin/"
        remove-item "${script:buildDir}/bin/${script:config}"
129
130
131
    }
}

132
133
function sign {
    if ("${env:KEY_CONTAINER}") {
134
135
136
        write-host "Signing ${script:buildDir}/bin/*.exe  ${script:buildDir}/bin/*.dll"
        foreach ($file in @(get-childitem "${script:buildDir}/bin/*.exe") + @(get-childitem "${script:buildDir}/bin/*.dll")){
            & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" `
137
138
139
140
141
142
                /csp "Google Cloud KMS Provider" /kc "${env:KEY_CONTAINER}" $file
            if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
        }
    }
}

143
144
145
function install {
    write-host "Installing binaries to dist dir ${script:distDir}"
    mkdir ${script:distDir} -ErrorAction SilentlyContinue
146
147
    $binaries = dir "${script:buildDir}/bin/*.exe"
    foreach ($file in $binaries) {
148
        copy-item -Path $file -Destination ${script:distDir} -Force
149
150
    }

151
    write-host "Installing dlls to dist dir ${script:distDir}"
mofanke's avatar
mofanke committed
152
    $dlls = dir "${script:buildDir}/bin/*.dll"
153
    foreach ($file in $dlls) {
154
        copy-item -Path $file -Destination ${script:distDir} -Force
155
    }
156
157
}

158
function cleanup {
159
160
161
162
163
164
165
166
167
168
    $patches = Get-ChildItem "../patches/*.diff"
    foreach ($patch in $patches) {
        # Extract file paths from the patch file
        $filePaths = Get-Content $patch.FullName | Where-Object { $_ -match '^\+\+\+ ' } | ForEach-Object {
            $parts = $_ -split ' '
            ($parts[1] -split '/', 2)[1]
        }

        # Checkout each file
        foreach ($file in $filePaths) {            
169
            git -C "${script:llamacppDir}" checkout $file
170
        }
171
        git -C "${script:llamacppDir}" checkout CMakeLists.txt
172
    }
173
174
}

Daniel Hiltgen's avatar
Daniel Hiltgen committed
175

176
177
178
179
# -DLLAMA_AVX -- 2011 Intel Sandy Bridge & AMD Bulldozer
# -DLLAMA_AVX2 -- 2013 Intel Haswell & 2015 AMD Excavator / 2017 AMD Zen
# -DLLAMA_FMA (FMA3) -- 2013 Intel Haswell & 2012 AMD Piledriver

180

181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
function build_static() {
    if ($null -eq ${env:OLLAMA_SKIP_CPU_GENERATE}) {
        # GCC build for direct linking into the Go binary
        init_vars
        # cmake will silently fallback to msvc compilers if mingw isn't in the path, so detect and fail fast
        # as we need this to be compiled by gcc for golang to be able to link with itx
        write-host "Checking for MinGW..."
        # error action ensures we exit on failure
        get-command gcc
        get-command mingw32-make
        $script:cmakeTargets = @("llama", "ggml")
        $script:cmakeDefs = @(
            "-G", "MinGW Makefiles"
            "-DCMAKE_C_COMPILER=gcc.exe",
            "-DCMAKE_CXX_COMPILER=g++.exe",
            "-DBUILD_SHARED_LIBS=off",
            "-DLLAMA_NATIVE=off",
            "-DLLAMA_AVX=off",
            "-DLLAMA_AVX2=off",
            "-DLLAMA_AVX512=off",
            "-DLLAMA_F16C=off",
            "-DLLAMA_FMA=off")
        $script:buildDir="../build/windows/${script:ARCH}_static"
        write-host "Building static library"
        build
    } else {
        write-host "Skipping CPU generation step as requested"
    }
209
}
Daniel Hiltgen's avatar
Daniel Hiltgen committed
210

211
212
213
214
215
216
217
218
219
220
221
222
223
function build_cpu() {
    if ($null -eq ${env:OLLAMA_SKIP_CPU_GENERATE}) {
        # remaining llama.cpp builds use MSVC 
        init_vars
        $script:cmakeDefs = $script:commonCpuDefs + @("-A", "x64", "-DLLAMA_AVX=off", "-DLLAMA_AVX2=off", "-DLLAMA_AVX512=off", "-DLLAMA_FMA=off", "-DLLAMA_F16C=off") + $script:cmakeDefs
        $script:buildDir="../build/windows/${script:ARCH}/cpu"
        $script:distDir="$script:DIST_BASE\cpu"
        write-host "Building LCD CPU"
        build
        sign
        install
    } else {
        write-host "Skipping CPU generation step as requested"
224
    }
225
226
227
228
229
230
231
232
233
234
235
236
237
238
}

function build_cpu_avx() {
    if ($null -eq ${env:OLLAMA_SKIP_CPU_GENERATE}) {
        init_vars
        $script:cmakeDefs = $script:commonCpuDefs + @("-A", "x64", "-DLLAMA_AVX=on", "-DLLAMA_AVX2=off", "-DLLAMA_AVX512=off", "-DLLAMA_FMA=off", "-DLLAMA_F16C=off") + $script:cmakeDefs
        $script:buildDir="../build/windows/${script:ARCH}/cpu_avx"
        $script:distDir="$script:DIST_BASE\cpu_avx"
        write-host "Building AVX CPU"
        build
        sign
        install
    } else {
        write-host "Skipping CPU generation step as requested"
Jeremy's avatar
Jeremy committed
239
    }
240
}
241

242
243
244
245
246
247
248
249
250
251
252
253
254
function build_cpu_avx2() {
    if ($null -eq ${env:OLLAMA_SKIP_CPU_GENERATE}) {
        init_vars
        $script:cmakeDefs = $script:commonCpuDefs + @("-A", "x64", "-DLLAMA_AVX=on", "-DLLAMA_AVX2=on", "-DLLAMA_AVX512=off", "-DLLAMA_FMA=on", "-DLLAMA_F16C=on") + $script:cmakeDefs
        $script:buildDir="../build/windows/${script:ARCH}/cpu_avx2"
        $script:distDir="$script:DIST_BASE\cpu_avx2"
        write-host "Building AVX2 CPU"
        build
        sign
        install
    } else {
        write-host "Skipping CPU generation step as requested"
    }
255
}
256

257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
function build_cuda() {
    if ($null -ne $script:CUDA_LIB_DIR) {
        # Then build cuda as a dynamically loaded library
        $nvcc = "$script:CUDA_LIB_DIR\nvcc.exe"
        $script:CUDA_VERSION=(get-item ($nvcc | split-path | split-path)).Basename
        if ($null -ne $script:CUDA_VERSION) {
            $script:CUDA_VARIANT="_"+$script:CUDA_VERSION
        }
        init_vars
        $script:buildDir="../build/windows/${script:ARCH}/cuda$script:CUDA_VARIANT"
        $script:distDir="$script:DIST_BASE\cuda$script:CUDA_VARIANT"
        $script:cmakeDefs += @("-A", "x64", "-DLLAMA_CUDA=ON", "-DLLAMA_AVX=on", "-DLLAMA_AVX2=off", "-DCUDAToolkit_INCLUDE_DIR=$script:CUDA_INCLUDE_DIR", "-DCMAKE_CUDA_ARCHITECTURES=${script:CMAKE_CUDA_ARCHITECTURES}")
        if ($null -ne $env:OLLAMA_CUSTOM_CUDA_DEFS) {
            write-host "OLLAMA_CUSTOM_CUDA_DEFS=`"${env:OLLAMA_CUSTOM_CUDA_DEFS}`""
            $script:cmakeDefs +=@("${env:OLLAMA_CUSTOM_CUDA_DEFS}")
            write-host "building custom CUDA GPU"
        }
        build
        sign
        install

        write-host "copying CUDA dependencies to ${script:SRC_DIR}\dist\windows-${script:ARCH}\"
        cp "${script:CUDA_LIB_DIR}\cudart64_*.dll" "${script:SRC_DIR}\dist\windows-${script:ARCH}\"
        cp "${script:CUDA_LIB_DIR}\cublas64_*.dll" "${script:SRC_DIR}\dist\windows-${script:ARCH}\"
        cp "${script:CUDA_LIB_DIR}\cublasLt64_*.dll" "${script:SRC_DIR}\dist\windows-${script:ARCH}\"
Daniel Hiltgen's avatar
Daniel Hiltgen committed
282
    }
283
}
Daniel Hiltgen's avatar
Daniel Hiltgen committed
284

285
286
287
288
289
290
function build_rocm() {
    if ($null -ne $env:HIP_PATH) {
        $script:ROCM_VERSION=(get-item $env:HIP_PATH).Basename
        if ($null -ne $script:ROCM_VERSION) {
            $script:ROCM_VARIANT="_v"+$script:ROCM_VERSION
        }
Daniel Hiltgen's avatar
Daniel Hiltgen committed
291

292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
        init_vars
        $script:buildDir="../build/windows/${script:ARCH}/rocm$script:ROCM_VARIANT"
        $script:distDir="$script:DIST_BASE\rocm$script:ROCM_VARIANT"
        $script:cmakeDefs += @(
            "-G", "Ninja", 
            "-DCMAKE_C_COMPILER=clang.exe",
            "-DCMAKE_CXX_COMPILER=clang++.exe",
            "-DLLAMA_HIPBLAS=on",
            "-DHIP_PLATFORM=amd",
            "-DLLAMA_AVX=on",
            "-DLLAMA_AVX2=off",
            "-DCMAKE_POSITION_INDEPENDENT_CODE=on",
            "-DAMDGPU_TARGETS=$(amdGPUs)",
            "-DGPU_TARGETS=$(amdGPUs)"
            )
Daniel Hiltgen's avatar
Daniel Hiltgen committed
307

308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
        # Make sure the ROCm binary dir is first in the path
        $env:PATH="$env:HIP_PATH\bin;$env:PATH"

        # We have to clobber the LIB var from the developer shell for clang to work properly
        $env:LIB=""
        if ($null -ne $env:OLLAMA_CUSTOM_ROCM_DEFS) {
            write-host "OLLAMA_CUSTOM_ROCM_DEFS=`"${env:OLLAMA_CUSTOM_ROCM_DEFS}`""
            $script:cmakeDefs += @("${env:OLLAMA_CUSTOM_ROCM_DEFS}")
            write-host "building custom ROCM GPU"
        }
        write-host "Building ROCm"
        build
        # Ninja doesn't prefix with config name
        ${script:config}=""
        if ($null -ne $script:DUMPBIN) {
            & "$script:DUMPBIN" /dependents "${script:buildDir}/bin/ollama_llama_server.exe" | select-string ".dll"
        }
        sign
        install
327

328
329
330
331
332
333
334
335
        # Assumes v5.7, may need adjustments for v6
        rm -ea 0 -recurse -force -path "${script:SRC_DIR}\dist\windows-${script:ARCH}\rocm\"
        md "${script:SRC_DIR}\dist\windows-${script:ARCH}\rocm\rocblas\library\" -ea 0 > $null
        cp "${env:HIP_PATH}\bin\hipblas.dll" "${script:SRC_DIR}\dist\windows-${script:ARCH}\rocm\"
        cp "${env:HIP_PATH}\bin\rocblas.dll" "${script:SRC_DIR}\dist\windows-${script:ARCH}\rocm\"
        # amdhip64.dll dependency comes from the driver and must be installed on the host to use AMD GPUs
        cp "${env:HIP_PATH}\bin\rocblas\library\*" "${script:SRC_DIR}\dist\windows-${script:ARCH}\rocm\rocblas\library\"
    }
Daniel Hiltgen's avatar
Daniel Hiltgen committed
336
}
337

338
339
340
341
342
init_vars
if ($($args.count) -eq 0) {
    git_module_setup
    apply_patches
    build_static
343
    build_cpu
344
345
346
347
    build_cpu_avx
    build_cpu_avx2
    build_cuda
    build_rocm
348

349
350
351
352
353
354
355
356
    cleanup
    write-host "`ngo generate completed.  LLM runners: $(get-childitem -path $script:DIST_BASE)"
} else {
    for ( $i = 0; $i -lt $args.count; $i++ ) {
        write-host "performing $($args[$i])"
        & $($args[$i])
    } 
}