gen_windows.ps1 10.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275
  1. #!powershell
  2. $ErrorActionPreference = "Stop"
  3. function amdGPUs {
  4. if ($env:AMDGPU_TARGETS) {
  5. return $env:AMDGPU_TARGETS
  6. }
  7. # TODO - load from some common data file for linux + windows build consistency
  8. $GPU_LIST = @(
  9. "gfx900"
  10. "gfx906:xnack-"
  11. "gfx908:xnack-"
  12. "gfx90a:xnack+"
  13. "gfx90a:xnack-"
  14. "gfx1010"
  15. "gfx1012"
  16. "gfx1030"
  17. "gfx1100"
  18. "gfx1101"
  19. "gfx1102"
  20. )
  21. $GPU_LIST -join ';'
  22. }
  23. function init_vars {
  24. # Verify the environment is a Developer Shell for MSVC 2019
  25. write-host $env:VSINSTALLDIR
  26. if (($env:VSINSTALLDIR -eq $null)) {
  27. 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"
  28. exit 1
  29. }
  30. $script:SRC_DIR = $(resolve-path "..\..\")
  31. $script:llamacppDir = "../llama.cpp"
  32. $script:cmakeDefs = @(
  33. "-DBUILD_SHARED_LIBS=on",
  34. "-DLLAMA_NATIVE=off"
  35. )
  36. $script:cmakeTargets = @("ext_server")
  37. $script:ARCH = "amd64" # arm not yet supported.
  38. if ($env:CGO_CFLAGS -contains "-g") {
  39. $script:cmakeDefs += @("-DCMAKE_VERBOSE_MAKEFILE=on", "-DLLAMA_SERVER_VERBOSE=on", "-DCMAKE_BUILD_TYPE=RelWithDebInfo")
  40. $script:config = "RelWithDebInfo"
  41. } else {
  42. $script:cmakeDefs += @("-DLLAMA_SERVER_VERBOSE=off", "-DCMAKE_BUILD_TYPE=Release")
  43. $script:config = "Release"
  44. }
  45. if ($null -ne $env:CMAKE_SYSTEM_VERSION) {
  46. $script:cmakeDefs += @("-DCMAKE_SYSTEM_VERSION=${env:CMAKE_SYSTEM_VERSION}")
  47. }
  48. # Try to find the CUDA dir
  49. if ($env:CUDA_LIB_DIR -eq $null) {
  50. $d=(get-command -ea 'silentlycontinue' nvcc).path
  51. if ($d -ne $null) {
  52. $script:CUDA_LIB_DIR=($d| split-path -parent)
  53. $script:CUDA_INCLUDE_DIR=($script:CUDA_LIB_DIR|split-path -parent)+"\include"
  54. }
  55. } else {
  56. $script:CUDA_LIB_DIR=$env:CUDA_LIB_DIR
  57. }
  58. $script:GZIP=(get-command -ea 'silentlycontinue' gzip).path
  59. $script:DUMPBIN=(get-command -ea 'silentlycontinue' dumpbin).path
  60. if ($null -eq $env:CMAKE_CUDA_ARCHITECTURES) {
  61. $script:CMAKE_CUDA_ARCHITECTURES="50;52;61;70;75;80"
  62. } else {
  63. $script:CMAKE_CUDA_ARCHITECTURES=$env:CMAKE_CUDA_ARCHITECTURES
  64. }
  65. # Note: 10 Windows Kit signtool crashes with GCP's plugin
  66. ${script:SignTool}="C:\Program Files (x86)\Windows Kits\8.1\bin\x64\signtool.exe"
  67. if ("${env:KEY_CONTAINER}") {
  68. ${script:OLLAMA_CERT}=$(resolve-path "${script:SRC_DIR}\ollama_inc.crt")
  69. }
  70. }
  71. function git_module_setup {
  72. # TODO add flags to skip the init/patch logic to make it easier to mod llama.cpp code in-repo
  73. & git submodule init
  74. if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
  75. & git submodule update --force "${script:llamacppDir}"
  76. if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
  77. }
  78. function apply_patches {
  79. # Wire up our CMakefile
  80. if (!(Select-String -Path "${script:llamacppDir}/examples/server/CMakeLists.txt" -Pattern 'ollama')) {
  81. Add-Content -Path "${script:llamacppDir}/examples/server/CMakeLists.txt" -Value 'include (../../../ext_server/CMakeLists.txt) # ollama'
  82. }
  83. # Apply temporary patches until fix is upstream
  84. $patches = Get-ChildItem "../patches/*.diff"
  85. foreach ($patch in $patches) {
  86. # Extract file paths from the patch file
  87. $filePaths = Get-Content $patch.FullName | Where-Object { $_ -match '^\+\+\+ ' } | ForEach-Object {
  88. $parts = $_ -split ' '
  89. ($parts[1] -split '/', 2)[1]
  90. }
  91. # Checkout each file
  92. Set-Location -Path ${script:llamacppDir}
  93. foreach ($file in $filePaths) {
  94. git checkout $file
  95. }
  96. }
  97. # Apply each patch
  98. foreach ($patch in $patches) {
  99. Set-Location -Path ${script:llamacppDir}
  100. git apply $patch.FullName
  101. }
  102. # Avoid duplicate main symbols when we link into the cgo binary
  103. $content = Get-Content -Path "${script:llamacppDir}/examples/server/server.cpp"
  104. $content = $content -replace 'int main\(', 'int __main('
  105. Set-Content -Path "${script:llamacppDir}/examples/server/server.cpp" -Value $content
  106. }
  107. function build {
  108. write-host "generating config with: cmake -S ${script:llamacppDir} -B $script:buildDir $script:cmakeDefs"
  109. & cmake --version
  110. & cmake -S "${script:llamacppDir}" -B $script:buildDir $script:cmakeDefs
  111. if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
  112. write-host "building with: cmake --build $script:buildDir --config $script:config ($script:cmakeTargets | ForEach-Object { "--target", $_ })"
  113. & cmake --build $script:buildDir --config $script:config ($script:cmakeTargets | ForEach-Object { "--target", $_ })
  114. if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
  115. }
  116. function install {
  117. rm -ea 0 -recurse -force -path "${script:buildDir}/lib"
  118. md "${script:buildDir}/lib" -ea 0 > $null
  119. cp "${script:buildDir}/bin/${script:config}/ext_server.dll" "${script:buildDir}/lib"
  120. cp "${script:buildDir}/bin/${script:config}/llama.dll" "${script:buildDir}/lib"
  121. # Display the dll dependencies in the build log
  122. if ($script:DUMPBIN -ne $null) {
  123. & "$script:DUMPBIN" /dependents "${script:buildDir}/bin/${script:config}/ext_server.dll" | select-string ".dll"
  124. }
  125. }
  126. function sign {
  127. if ("${env:KEY_CONTAINER}") {
  128. write-host "Signing ${script:buildDir}/lib/*.dll"
  129. foreach ($file in (get-childitem "${script:buildDir}/lib/*.dll")){
  130. & "${script:SignTool}" sign /v /fd sha256 /t http://timestamp.digicert.com /f "${script:OLLAMA_CERT}" `
  131. /csp "Google Cloud KMS Provider" /kc "${env:KEY_CONTAINER}" $file
  132. if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
  133. }
  134. }
  135. }
  136. function compress_libs {
  137. if ($script:GZIP -eq $null) {
  138. write-host "gzip not installed, not compressing files"
  139. return
  140. }
  141. write-host "Compressing dlls..."
  142. $libs = dir "${script:buildDir}/lib/*.dll"
  143. foreach ($file in $libs) {
  144. & "$script:GZIP" --best -f $file
  145. }
  146. }
  147. function cleanup {
  148. $patches = Get-ChildItem "../patches/*.diff"
  149. foreach ($patch in $patches) {
  150. # Extract file paths from the patch file
  151. $filePaths = Get-Content $patch.FullName | Where-Object { $_ -match '^\+\+\+ ' } | ForEach-Object {
  152. $parts = $_ -split ' '
  153. ($parts[1] -split '/', 2)[1]
  154. }
  155. # Checkout each file
  156. Set-Location -Path ${script:llamacppDir}
  157. foreach ($file in $filePaths) {
  158. git checkout $file
  159. }
  160. }
  161. Set-Location "${script:llamacppDir}/examples/server"
  162. git checkout CMakeLists.txt server.cpp
  163. }
  164. init_vars
  165. git_module_setup
  166. apply_patches
  167. # -DLLAMA_AVX -- 2011 Intel Sandy Bridge & AMD Bulldozer
  168. # -DLLAMA_F16C -- 2012 Intel Ivy Bridge & AMD 2011 Bulldozer (No significant improvement over just AVX)
  169. # -DLLAMA_AVX2 -- 2013 Intel Haswell & 2015 AMD Excavator / 2017 AMD Zen
  170. # -DLLAMA_FMA (FMA3) -- 2013 Intel Haswell & 2012 AMD Piledriver
  171. $script:commonCpuDefs = @("-DCMAKE_POSITION_INDEPENDENT_CODE=on")
  172. init_vars
  173. $script:cmakeDefs = $script:commonCpuDefs + @("-A", "x64", "-DLLAMA_AVX=off", "-DLLAMA_AVX2=off", "-DLLAMA_AVX512=off", "-DLLAMA_FMA=off", "-DLLAMA_F16C=off") + $script:cmakeDefs
  174. $script:buildDir="${script:llamacppDir}/build/windows/${script:ARCH}/cpu"
  175. write-host "Building LCD CPU"
  176. build
  177. install
  178. sign
  179. compress_libs
  180. init_vars
  181. $script:cmakeDefs = $script:commonCpuDefs + @("-A", "x64", "-DLLAMA_AVX=on", "-DLLAMA_AVX2=off", "-DLLAMA_AVX512=off", "-DLLAMA_FMA=off", "-DLLAMA_F16C=off") + $script:cmakeDefs
  182. $script:buildDir="${script:llamacppDir}/build/windows/${script:ARCH}/cpu_avx"
  183. write-host "Building AVX CPU"
  184. build
  185. install
  186. sign
  187. compress_libs
  188. init_vars
  189. $script:cmakeDefs = $script:commonCpuDefs + @("-A", "x64", "-DLLAMA_AVX=on", "-DLLAMA_AVX2=on", "-DLLAMA_AVX512=off", "-DLLAMA_FMA=on", "-DLLAMA_F16C=on") + $script:cmakeDefs
  190. $script:buildDir="${script:llamacppDir}/build/windows/${script:ARCH}/cpu_avx2"
  191. write-host "Building AVX2 CPU"
  192. build
  193. install
  194. sign
  195. compress_libs
  196. if ($null -ne $script:CUDA_LIB_DIR) {
  197. # Then build cuda as a dynamically loaded library
  198. $nvcc = "$script:CUDA_LIB_DIR\nvcc.exe"
  199. $script:CUDA_VERSION=(get-item ($nvcc | split-path | split-path)).Basename
  200. if ($null -ne $script:CUDA_VERSION) {
  201. $script:CUDA_VARIANT="_"+$script:CUDA_VERSION
  202. }
  203. init_vars
  204. $script:buildDir="${script:llamacppDir}/build/windows/${script:ARCH}/cuda$script:CUDA_VARIANT"
  205. $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}")
  206. write-host "Building CUDA"
  207. build
  208. install
  209. sign
  210. compress_libs
  211. }
  212. if ($null -ne $env:HIP_PATH) {
  213. $script:ROCM_VERSION=(get-item $env:HIP_PATH).Basename
  214. if ($null -ne $script:ROCM_VERSION) {
  215. $script:ROCM_VARIANT="_v"+$script:ROCM_VERSION
  216. }
  217. init_vars
  218. $script:buildDir="${script:llamacppDir}/build/windows/${script:ARCH}/rocm$script:ROCM_VARIANT"
  219. $script:cmakeDefs += @(
  220. "-G", "Ninja",
  221. "-DCMAKE_C_COMPILER=clang.exe",
  222. "-DCMAKE_CXX_COMPILER=clang++.exe",
  223. "-DLLAMA_HIPBLAS=on",
  224. "-DLLAMA_AVX=on",
  225. "-DLLAMA_AVX2=off",
  226. "-DCMAKE_POSITION_INDEPENDENT_CODE=on",
  227. "-DAMDGPU_TARGETS=$(amdGPUs)",
  228. "-DGPU_TARGETS=$(amdGPUs)"
  229. )
  230. # Make sure the ROCm binary dir is first in the path
  231. $env:PATH="$env:HIP_PATH\bin;$env:VSINSTALLDIR\Common7\IDE\CommonExtensions\Microsoft\CMake\Ninja;$env:PATH"
  232. # We have to clobber the LIB var from the developer shell for clang to work properly
  233. $env:LIB=""
  234. write-host "Building ROCm"
  235. build
  236. # Ninja doesn't prefix with config name
  237. ${script:config}=""
  238. install
  239. if ($null -ne $script:DUMPBIN) {
  240. & "$script:DUMPBIN" /dependents "${script:buildDir}/bin/${script:config}/ext_server.dll" | select-string ".dll"
  241. }
  242. sign
  243. compress_libs
  244. }
  245. cleanup
  246. write-host "`ngo generate completed"