gen_windows.ps1 10.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
16
17
18
19
20
21
22
23
24
25
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-"
        "gfx1010"
        "gfx1012"
        "gfx1030"
        "gfx1100"
        "gfx1101"
        "gfx1102"
    )
    $GPU_LIST -join ';'
}

26
function init_vars {
Daniel Hiltgen's avatar
Daniel Hiltgen committed
27
28
29
30
31
32
    # Verify the environment is a Developer Shell for MSVC 2019
    write-host $env:VSINSTALLDIR
    if (($env:VSINSTALLDIR -eq $null)) {
        Write-Error "`r`nBUILD ERROR - YOUR DEVELOPMENT ENVIRONMENT IS NOT SET UP CORRECTLY`r`nTo build Ollama you must run from an MSVC Developer Shell`r`nSee .\docs\development.md for instructions to set up your dev environment"
        exit 1
    }
33
    $script:SRC_DIR = $(resolve-path "..\..\")
34
    $script:llamacppDir = "../llama.cpp"
Daniel Hiltgen's avatar
Daniel Hiltgen committed
35
36
37
38
    $script:cmakeDefs = @(
        "-DBUILD_SHARED_LIBS=on",
        "-DLLAMA_NATIVE=off"
        )
39
40
    $script:cmakeTargets = @("ext_server")
    $script:ARCH = "amd64" # arm not yet supported.
41
    if ($env:CGO_CFLAGS -contains "-g") {
Daniel Hiltgen's avatar
Daniel Hiltgen committed
42
        $script:cmakeDefs += @("-DCMAKE_VERBOSE_MAKEFILE=on", "-DLLAMA_SERVER_VERBOSE=on", "-DCMAKE_BUILD_TYPE=RelWithDebInfo")
Daniel Hiltgen's avatar
Daniel Hiltgen committed
43
        $script:config = "RelWithDebInfo"
44
    } else {
Daniel Hiltgen's avatar
Daniel Hiltgen committed
45
        $script:cmakeDefs += @("-DLLAMA_SERVER_VERBOSE=off", "-DCMAKE_BUILD_TYPE=Release")
Daniel Hiltgen's avatar
Daniel Hiltgen committed
46
        $script:config = "Release"
47
    }
Daniel Hiltgen's avatar
Daniel Hiltgen committed
48
49
50
    if ($null -ne $env:CMAKE_SYSTEM_VERSION) {
        $script:cmakeDefs += @("-DCMAKE_SYSTEM_VERSION=${env:CMAKE_SYSTEM_VERSION}")
    }
51
52
53
54
55
    # 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)
56
            $script:CUDA_INCLUDE_DIR=($script:CUDA_LIB_DIR|split-path -parent)+"\include"
57
58
59
60
        }
    } else {
        $script:CUDA_LIB_DIR=$env:CUDA_LIB_DIR
    }
61
    $script:GZIP=(get-command -ea 'silentlycontinue' gzip).path
62
    $script:DUMPBIN=(get-command -ea 'silentlycontinue' dumpbin).path
63
64
65
66
67
    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
    }
68
69
70
71
72
73
    # 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}
    }
74
75
76
    if ("${env:KEY_CONTAINER}") {
        ${script:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt")
    }
77
78
79
80
81
}

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
82
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
83
    & git submodule update --force "${script:llamacppDir}"
Daniel Hiltgen's avatar
Daniel Hiltgen committed
84
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
85
86
87
}

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

    # 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
103
        Set-Location -Path ${script:llamacppDir}
104
105
106
107
108
109
110
111
112
113
114
        foreach ($file in $filePaths) {
            git checkout $file
        }
    }

    # Apply each patch
    foreach ($patch in $patches) {
        Set-Location -Path ${script:llamacppDir}
        git apply $patch.FullName
    }

115
    # Avoid duplicate main symbols when we link into the cgo binary
116
    $content = Get-Content -Path "${script:llamacppDir}/examples/server/server.cpp"
117
    $content = $content -replace 'int main\(', 'int __main('
118
    Set-Content -Path "${script:llamacppDir}/examples/server/server.cpp" -Value $content
119
120
121
}

function build {
122
    write-host "generating config with: cmake -S ${script:llamacppDir} -B $script:buildDir $script:cmakeDefs"
123
    & cmake --version
124
    & cmake -S "${script:llamacppDir}" -B $script:buildDir $script:cmakeDefs
Daniel Hiltgen's avatar
Daniel Hiltgen committed
125
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
126
127
    write-host "building with: cmake --build $script:buildDir --config $script:config ($script:cmakeTargets | ForEach-Object { "--target", $_ })"
    & cmake --build $script:buildDir --config $script:config ($script:cmakeTargets | ForEach-Object { "--target", $_ })
Daniel Hiltgen's avatar
Daniel Hiltgen committed
128
    if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
129
130
}

131
132
133
function install {
    rm -ea 0 -recurse -force -path "${script:buildDir}/lib"
    md "${script:buildDir}/lib" -ea 0 > $null
134
    cp "${script:buildDir}/bin/${script:config}/ext_server.dll" "${script:buildDir}/lib"
135
    cp "${script:buildDir}/bin/${script:config}/llama.dll" "${script:buildDir}/lib"
136
    # Display the dll dependencies in the build log
137
138
139
140
141
    if ($script:DUMPBIN -ne $null) {
        & "$script:DUMPBIN" /dependents "${script:buildDir}/bin/${script:config}/ext_server.dll" | select-string ".dll"
    }
}

142
143
144
145
function sign {
    if ("${env:KEY_CONTAINER}") {
        write-host "Signing ${script:buildDir}/lib/*.dll"
        foreach ($file in (get-childitem "${script:buildDir}/lib/*.dll")){
146
            & "${script:SignTool}" sign /v /debug /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" `
147
148
149
150
151
152
                /csp "Google Cloud KMS Provider" /kc "${env:KEY_CONTAINER}" $file
            if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
        }
    }
}

153
function compress_libs {
154
155
    if ($script:GZIP -eq $null) {
        write-host "gzip not installed, not compressing files"
156
157
158
159
160
        return
    }
    write-host "Compressing dlls..."
    $libs = dir "${script:buildDir}/lib/*.dll"
    foreach ($file in $libs) {
Jeffrey Morgan's avatar
Jeffrey Morgan committed
161
        & "$script:GZIP" --best -f $file
162
    }
163
164
}

165
function cleanup {
166
167
168
169
170
171
172
173
174
175
176
177
178
179
    $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
        Set-Location -Path ${script:llamacppDir}
        foreach ($file in $filePaths) {            
            git checkout $file
        }
    }
180
    Set-Location "${script:llamacppDir}/examples/server"
181
    git checkout CMakeLists.txt server.cpp
182

183
184
185
186
187
}

init_vars
git_module_setup
apply_patches
Daniel Hiltgen's avatar
Daniel Hiltgen committed
188

189
190
191
192
193
# -DLLAMA_AVX -- 2011 Intel Sandy Bridge & AMD Bulldozer
# -DLLAMA_F16C -- 2012 Intel Ivy Bridge & AMD 2011 Bulldozer (No significant improvement over just AVX)
# -DLLAMA_AVX2 -- 2013 Intel Haswell & 2015 AMD Excavator / 2017 AMD Zen
# -DLLAMA_FMA (FMA3) -- 2013 Intel Haswell & 2012 AMD Piledriver

194
$script:commonCpuDefs = @("-DCMAKE_POSITION_INDEPENDENT_CODE=on")
195

196
if ($null -eq ${env:OLLAMA_SKIP_CPU_GENERATE}) {
197

198
199
200
201
202
203
204
205
    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="${script:llamacppDir}/build/windows/${script:ARCH}/cpu"
    write-host "Building LCD CPU"
    build
    install
    sign
    compress_libs
Daniel Hiltgen's avatar
Daniel Hiltgen committed
206

207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
    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="${script:llamacppDir}/build/windows/${script:ARCH}/cpu_avx"
    write-host "Building AVX CPU"
    build
    install
    sign
    compress_libs

    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="${script:llamacppDir}/build/windows/${script:ARCH}/cpu_avx2"
    write-host "Building AVX2 CPU"
    build
    install
    sign
    compress_libs
} else {
    write-host "Skipping CPU generation step as requested"
}
Daniel Hiltgen's avatar
Daniel Hiltgen committed
227

228
229
if ($null -ne $script:CUDA_LIB_DIR) {
    # Then build cuda as a dynamically loaded library
230
231
    $nvcc = "$script:CUDA_LIB_DIR\nvcc.exe"
    $script:CUDA_VERSION=(get-item ($nvcc | split-path | split-path)).Basename
232
233
234
235
236
    if ($null -ne $script:CUDA_VERSION) {
        $script:CUDA_VARIANT="_"+$script:CUDA_VERSION
    }
    init_vars
    $script:buildDir="${script:llamacppDir}/build/windows/${script:ARCH}/cuda$script:CUDA_VARIANT"
Daniel Hiltgen's avatar
Daniel Hiltgen committed
237
238
    $script:cmakeDefs += @("-A", "x64", "-DLLAMA_CUBLAS=ON", "-DLLAMA_AVX=on", "-DLLAMA_AVX2=off", "-DCUDAToolkit_INCLUDE_DIR=$script:CUDA_INCLUDE_DIR", "-DCMAKE_CUDA_ARCHITECTURES=${script:CMAKE_CUDA_ARCHITECTURES}")
    write-host "Building CUDA"
239
240
    build
    install
241
    sign
242
243
    compress_libs
}
244

Daniel Hiltgen's avatar
Daniel Hiltgen committed
245
246
247
248
249
250
251
252
253
254
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
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
    }

    init_vars
    $script:buildDir="${script:llamacppDir}/build/windows/${script:ARCH}/rocm$script:ROCM_VARIANT"
    $script:cmakeDefs += @(
        "-G", "Ninja", 
        "-DCMAKE_C_COMPILER=clang.exe",
        "-DCMAKE_CXX_COMPILER=clang++.exe",
        "-DLLAMA_HIPBLAS=on",
        "-DLLAMA_AVX=on",
        "-DLLAMA_AVX2=off",
        "-DCMAKE_POSITION_INDEPENDENT_CODE=on",
        "-DAMDGPU_TARGETS=$(amdGPUs)",
        "-DGPU_TARGETS=$(amdGPUs)"
        )

    # Make sure the ROCm binary dir is first in the path
    $env:PATH="$env:HIP_PATH\bin;$env:VSINSTALLDIR\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;$env:PATH"

    # We have to clobber the LIB var from the developer shell for clang to work properly
    $env:LIB=""

    write-host "Building ROCm"
    build
    # Ninja doesn't prefix with config name
    ${script:config}=""
    install
    if ($null -ne $script:DUMPBIN) {
        & "$script:DUMPBIN" /dependents "${script:buildDir}/bin/${script:config}/ext_server.dll" | select-string ".dll"
    }
    sign
    compress_libs
}
282
283

cleanup
284
write-host "`ngo generate completed.  LLM runners: $(get-childitem -path ${script:SRC_DIR}\llm\llama.cpp\build\windows\${script:ARCH})"