mirror of
https://github.com/ollama/ollama.git
synced 2026-07-23 09:10:53 -05:00
win: support CUDA on Windows ARM64 (#16931)
This commit is contained in:
15
.github/workflows/release.yaml
vendored
15
.github/workflows/release.yaml
vendored
@@ -124,6 +124,21 @@ jobs:
|
||||
- '"nvvm"'
|
||||
- '"nvptxcompiler"'
|
||||
cuda-version: '13.0'
|
||||
- os: windows
|
||||
arch: amd64
|
||||
preset: 'CUDA 13 ARM64'
|
||||
build-steps: cuda13Arm64Cross
|
||||
install: https://packages.nvidia.com/prerelease/cuda/13.4.0/local_installers/cuda_13.4.0_windows_x86_64.exe
|
||||
cuda-components:
|
||||
- '"cudart_cross"'
|
||||
- '"nvcc"'
|
||||
- '"nvcc_cross"'
|
||||
- '"cublas_cross"'
|
||||
- '"cublas_dev"'
|
||||
- '"crt"'
|
||||
- '"nvvm"'
|
||||
- '"nvptxcompiler"'
|
||||
cuda-version: '13.4'
|
||||
- os: windows
|
||||
arch: amd64
|
||||
preset: 'ROCm 7'
|
||||
|
||||
15
.github/workflows/test-llamacpp-update.yaml
vendored
15
.github/workflows/test-llamacpp-update.yaml
vendored
@@ -321,6 +321,21 @@ jobs:
|
||||
- '"nvvm"'
|
||||
- '"nvptxcompiler"'
|
||||
cuda-version: '13.0'
|
||||
- os: windows
|
||||
arch: amd64
|
||||
preset: 'CUDA 13 ARM64'
|
||||
build-steps: cuda13Arm64Cross
|
||||
install: https://packages.nvidia.com/prerelease/cuda/13.4.0/local_installers/cuda_13.4.0_windows_x86_64.exe
|
||||
cuda-components:
|
||||
- '"cudart_cross"'
|
||||
- '"nvcc"'
|
||||
- '"nvcc_cross"'
|
||||
- '"cublas_cross"'
|
||||
- '"cublas_dev"'
|
||||
- '"crt"'
|
||||
- '"nvvm"'
|
||||
- '"nvptxcompiler"'
|
||||
cuda-version: '13.4'
|
||||
- os: windows
|
||||
arch: amd64
|
||||
preset: 'ROCm 7'
|
||||
|
||||
@@ -437,11 +437,25 @@ if(OLLAMA_RUNNER_DIR)
|
||||
# Bundle GPU runtime libraries (cublas, cudart, rocblas, etc.)
|
||||
# These are needed at runtime by the GPU backend .so
|
||||
if(GGML_CUDA AND CUDAToolkit_FOUND)
|
||||
if(DEFINED OLLAMA_WINDOWS_RUNTIME_ARCH)
|
||||
string(TOLOWER "${OLLAMA_WINDOWS_RUNTIME_ARCH}" _cuda_redist_arch)
|
||||
if(_cuda_redist_arch MATCHES "^(x64|amd64|x86_64)$")
|
||||
set(_cuda_redist_arch "x64")
|
||||
elseif(_cuda_redist_arch MATCHES "^(arm64|aarch64)$")
|
||||
set(_cuda_redist_arch "arm64")
|
||||
endif()
|
||||
elseif(CMAKE_SYSTEM_PROCESSOR MATCHES "^(ARM64|arm64|aarch64)$")
|
||||
set(_cuda_redist_arch "arm64")
|
||||
else()
|
||||
set(_cuda_redist_arch "x64")
|
||||
endif()
|
||||
set(_cuda_redist_dir "${CUDAToolkit_BIN_DIR}/${_cuda_redist_arch}")
|
||||
|
||||
# Find the actual ggml-cuda target to get its runtime dependencies
|
||||
if(TARGET ggml-cuda)
|
||||
install(TARGETS ggml-cuda
|
||||
RUNTIME_DEPENDENCIES
|
||||
DIRECTORIES ${CUDAToolkit_BIN_DIR} ${CUDAToolkit_BIN_DIR}/x64 ${CUDAToolkit_LIBRARY_DIR}
|
||||
DIRECTORIES ${_cuda_redist_dir} ${CUDAToolkit_BIN_DIR} ${CUDAToolkit_LIBRARY_DIR}
|
||||
PRE_INCLUDE_REGEXES cublas cublasLt cudart
|
||||
PRE_EXCLUDE_REGEXES ".*"
|
||||
RUNTIME DESTINATION "${_base_dest}/${OLLAMA_RUNNER_DIR}" COMPONENT llama-server
|
||||
|
||||
@@ -111,6 +111,17 @@
|
||||
"CMAKE_CUDA_ARCHITECTURES": "75-virtual;80-virtual;86-virtual;89-virtual;100-virtual;120-virtual"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "llama_cuda_v13_windows_arm64",
|
||||
"inherits": ["llama_cuda_v13_base"],
|
||||
"binaryDir": "${sourceDir}/../../build/llama-server-cuda_v13_arm64",
|
||||
"cacheVariables": {
|
||||
"CMAKE_CUDA_ARCHITECTURES": "121",
|
||||
"GGML_CPU": "OFF",
|
||||
"CMAKE_CUDA_FLAGS": "-target-dir=arm64 -t 4",
|
||||
"OLLAMA_WINDOWS_RUNTIME_ARCH": "arm64"
|
||||
}
|
||||
},
|
||||
{
|
||||
"name": "llama_cuda_v13_user_arch",
|
||||
"inherits": ["llama_cuda_v13_base"],
|
||||
@@ -267,6 +278,11 @@
|
||||
"configurePreset": "llama_cuda_v13_windows",
|
||||
"targets": ["ggml-cuda"]
|
||||
},
|
||||
{
|
||||
"name": "llama_cuda_v13_windows_arm64",
|
||||
"configurePreset": "llama_cuda_v13_windows_arm64",
|
||||
"targets": ["ggml-cuda"]
|
||||
},
|
||||
{
|
||||
"name": "llama_cuda_v13_user_arch",
|
||||
"configurePreset": "llama_cuda_v13_user_arch",
|
||||
|
||||
@@ -64,6 +64,16 @@ function normalizePathForCompare {
|
||||
return ([IO.Path]::GetFullPath($Path).TrimEnd('\')).Replace('/', '\').ToLowerInvariant()
|
||||
}
|
||||
|
||||
function convertToCMakePath {
|
||||
param([string]$Path)
|
||||
|
||||
if (-not $Path) {
|
||||
return $Path
|
||||
}
|
||||
|
||||
return ([IO.Path]::GetFullPath($Path)).Replace('\', '/')
|
||||
}
|
||||
|
||||
function newCompilerPair($name, $cc, $cxx) {
|
||||
if ((Test-Path $cc) -and (Test-Path $cxx)) {
|
||||
return [pscustomobject]@{
|
||||
@@ -99,33 +109,115 @@ function findWindowsCPUCompiler {
|
||||
return $null
|
||||
}
|
||||
|
||||
function msvcArchName {
|
||||
param([string]$Arch)
|
||||
|
||||
switch -Regex ($Arch) {
|
||||
"^(arm64|aarch64)$" { return "arm64" }
|
||||
"^(amd64|x64|x86_64)$" { return "x64" }
|
||||
default { return $Arch }
|
||||
}
|
||||
}
|
||||
|
||||
function hostMsvcArchName {
|
||||
try {
|
||||
if ((Get-CimInstance Win32_Processor | Select-Object -First 1).Architecture -eq 12) {
|
||||
return "arm64"
|
||||
}
|
||||
} catch {
|
||||
return "x64"
|
||||
}
|
||||
return "x64"
|
||||
}
|
||||
|
||||
function ensureMsvcForNinja {
|
||||
param(
|
||||
[string]$TargetArch = $script:ARCH,
|
||||
[switch]$Optional
|
||||
)
|
||||
|
||||
if ($env:CMAKE_GENERATOR -notlike "Ninja*") {
|
||||
if ($Optional) { return $true }
|
||||
return
|
||||
}
|
||||
|
||||
if (-not (Get-Command -Name "cl.exe" -ErrorAction SilentlyContinue)) {
|
||||
$msvcTargetArch = msvcArchName $TargetArch
|
||||
$cl = Get-Command -Name "cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
$needDevShell = -not $cl
|
||||
if ($cl -and $cl.Source -notmatch "[\\/]$msvcTargetArch[\\/]cl\.exe$") {
|
||||
$needDevShell = $true
|
||||
}
|
||||
|
||||
if ($needDevShell) {
|
||||
$vsInstall = findVisualStudioInstall
|
||||
if ($vsInstall) {
|
||||
$devShell = Join-Path $vsInstall "Common7\Tools\Microsoft.VisualStudio.DevShell.dll"
|
||||
if (Test-Path $devShell) {
|
||||
Import-Module $devShell
|
||||
Enter-VsDevShell -VsInstallPath $vsInstall -SkipAutomaticLocation -DevCmdArguments "-arch=x64 -no_logo"
|
||||
$hostArch = hostMsvcArchName
|
||||
Enter-VsDevShell -VsInstallPath $vsInstall -SkipAutomaticLocation -DevCmdArguments "-arch=$msvcTargetArch -host_arch=$hostArch -no_logo"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (-not (Get-Command -Name "cl.exe" -ErrorAction SilentlyContinue)) {
|
||||
Write-Error "Ninja builds require MSVC cl.exe. Install Visual Studio C++ tools or run from a VS Developer shell."
|
||||
$cl = Get-Command -Name "cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if (-not $cl) {
|
||||
$message = "Ninja builds require MSVC cl.exe. Install Visual Studio C++ tools or run from a VS Developer shell."
|
||||
if ($Optional) {
|
||||
Write-Warning $message
|
||||
return $false
|
||||
}
|
||||
Write-Error $message
|
||||
exit(1)
|
||||
}
|
||||
Write-Output "MSVC cl.exe available for Ninja builds"
|
||||
if ($cl.Source -notmatch "[\\/]$msvcTargetArch[\\/]cl\.exe$") {
|
||||
$message = "Ninja build for $TargetArch requires MSVC $msvcTargetArch cl.exe, but PATH has $($cl.Source)"
|
||||
if ($Optional) {
|
||||
Write-Warning $message
|
||||
return $false
|
||||
}
|
||||
Write-Error $message
|
||||
exit(1)
|
||||
}
|
||||
if ($Optional) {
|
||||
Write-Host "MSVC $msvcTargetArch cl.exe available for Ninja builds"
|
||||
return $true
|
||||
}
|
||||
Write-Output "MSVC $msvcTargetArch cl.exe available for Ninja builds"
|
||||
}
|
||||
|
||||
function saveEnvironment {
|
||||
$snapshot = @{}
|
||||
Get-ChildItem Env: | ForEach-Object {
|
||||
$snapshot[$_.Name] = $_.Value
|
||||
}
|
||||
return $snapshot
|
||||
}
|
||||
|
||||
function restoreEnvironment {
|
||||
param($Snapshot)
|
||||
|
||||
foreach ($item in Get-ChildItem Env:) {
|
||||
if (-not $Snapshot.ContainsKey($item.Name)) {
|
||||
Remove-Item "Env:$($item.Name)" -ErrorAction SilentlyContinue
|
||||
}
|
||||
}
|
||||
foreach ($name in $Snapshot.Keys) {
|
||||
Set-Item "Env:$name" $Snapshot[$name]
|
||||
}
|
||||
}
|
||||
|
||||
function checkEnv {
|
||||
if ($null -ne $env:ARCH ) {
|
||||
$script:ARCH = $env:ARCH
|
||||
} else {
|
||||
# RuntimeInformation.OSArchitecture can report X64 on ARM64 Windows
|
||||
# when PowerShell itself is running under x64 emulation.
|
||||
$procArch = (Get-CimInstance Win32_Processor).Architecture
|
||||
switch ($procArch) {
|
||||
12 { $script:ARCH = "arm64" }
|
||||
9 { $script:ARCH = "amd64" }
|
||||
default {
|
||||
$arch=([System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture)
|
||||
if ($null -ne $arch) {
|
||||
$script:ARCH = ($arch.ToString().ToLower()).Replace("x64", "amd64")
|
||||
@@ -134,6 +226,8 @@ function checkEnv {
|
||||
$script:ARCH="amd64"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
$script:TARGET_ARCH=$script:ARCH
|
||||
Write-host "Building for ${script:TARGET_ARCH}"
|
||||
Write-Output "Locating required tools and paths"
|
||||
@@ -352,7 +446,9 @@ function cpuArm64 {
|
||||
New-Item "${arm64DistDir}\lib\ollama\" -ItemType Directory -ea 0 | Out-Null
|
||||
|
||||
# Cross-compile the Windows ARM64 CPU llama-server payload from an x64 host
|
||||
# with llvm-mingw. GPU backends are not built for Windows ARM64.
|
||||
# with llvm-mingw. Upstream ggml only supports ARM CPU variant matrices on
|
||||
# Linux, Android, and Apple targets, so build one generic Windows ARM64 CPU
|
||||
# backend here instead of GGML_CPU_ALL_VARIANTS.
|
||||
$oldCC = $env:CC
|
||||
$oldCXX = $env:CXX
|
||||
$oldGenerator = $env:CMAKE_GENERATOR
|
||||
@@ -384,31 +480,136 @@ function cudaCMakeArgs {
|
||||
[string]$cuda
|
||||
)
|
||||
|
||||
$env:CUDACXX = "$cuda\bin\nvcc.exe"
|
||||
$cudaRoot = convertToCMakePath $cuda
|
||||
$nvcc = "$cudaRoot/bin/nvcc.exe"
|
||||
$env:CUDACXX = $nvcc
|
||||
if ($env:CMAKE_GENERATOR -like "Ninja*") {
|
||||
return @()
|
||||
return @("-DCUDAToolkit_ROOT:PATH=$cudaRoot", "-DCMAKE_CUDA_COMPILER:FILEPATH=$nvcc")
|
||||
}
|
||||
return @("-T", "cuda=$cuda", "-DCMAKE_CUDA_COMPILER=$cuda\bin\nvcc.exe")
|
||||
return @("-T", "cuda=$cuda", "-DCUDAToolkit_ROOT:PATH=$cudaRoot", "-DCMAKE_CUDA_COMPILER:FILEPATH=$nvcc")
|
||||
}
|
||||
|
||||
function findCudaRoot {
|
||||
param (
|
||||
[string]$MajorVer,
|
||||
[string]$ExactVer
|
||||
)
|
||||
|
||||
if ($ExactVer) {
|
||||
$envName = "CUDA_PATH_V$($ExactVer.Replace('.', '_'))"
|
||||
$candidates = @(
|
||||
[Environment]::GetEnvironmentVariable($envName),
|
||||
"C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v$ExactVer"
|
||||
)
|
||||
|
||||
foreach ($candidate in ($candidates | Where-Object { $_ } | Select-Object -Unique)) {
|
||||
if (Test-Path -LiteralPath (Join-Path $candidate "bin\nvcc.exe")) {
|
||||
return $candidate
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ("$script:CUDA_DIRS".Contains("v$MajorVer")) {
|
||||
foreach ($d in $Script:CUDA_DIRS){
|
||||
if ($d.FullName.Contains("v$MajorVer")) {
|
||||
if (test-path -literalpath (join-path -path $d -childpath "nvcc.exe" ) ) {
|
||||
return ($d.FullName|split-path -parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function cudaArm64CMakeArgs {
|
||||
param (
|
||||
[string]$cuda
|
||||
)
|
||||
|
||||
$cudaRoot = convertToCMakePath $cuda
|
||||
$cudaArm64LibDir = Join-Path $cuda "lib\arm64"
|
||||
if (-not (Test-Path -LiteralPath $cudaArm64LibDir)) {
|
||||
Write-Error "CUDA at $cuda is missing Windows ARM64 import libraries under lib\arm64"
|
||||
exit(1)
|
||||
}
|
||||
|
||||
$requiredLibs = @("cudart.lib", "cudart_static.lib", "cuda.lib", "cublas.lib", "cublasLt.lib")
|
||||
foreach ($lib in $requiredLibs) {
|
||||
$libPath = Join-Path $cudaArm64LibDir $lib
|
||||
if (-not (Test-Path -LiteralPath $libPath)) {
|
||||
Write-Error "CUDA at $cuda is missing Windows ARM64 import library $libPath"
|
||||
exit(1)
|
||||
}
|
||||
}
|
||||
|
||||
$cudaLib = convertToCMakePath $cudaArm64LibDir
|
||||
$nvcc = "$cudaRoot/bin/nvcc.exe"
|
||||
$cl = Get-Command -Name "cl.exe" -ErrorAction SilentlyContinue | Select-Object -First 1
|
||||
if (-not $cl -or $cl.Source -notmatch "[\\/]arm64[\\/]cl\.exe$") {
|
||||
Write-Error "CUDA Windows ARM64 builds require MSVC ARM64 cl.exe on PATH"
|
||||
exit(1)
|
||||
}
|
||||
$env:CUDACXX = $nvcc
|
||||
return @(
|
||||
"-DCUDAToolkit_ROOT:PATH=$cudaRoot",
|
||||
"-DCMAKE_CUDA_COMPILER:FILEPATH=$nvcc",
|
||||
"-DCUDAToolkit_LIBRARY_DIR:PATH=$cudaLib",
|
||||
"-DCUDA_CUDART:FILEPATH=$cudaLib/cudart.lib",
|
||||
"-DCUDA_cudart_LIBRARY:FILEPATH=$cudaLib/cudart.lib",
|
||||
"-DCUDA_cudart_static_LIBRARY:FILEPATH=$cudaLib/cudart_static.lib",
|
||||
"-DCUDA_cuda_driver_LIBRARY:FILEPATH=$cudaLib/cuda.lib",
|
||||
"-DCUDA_cublas_LIBRARY:FILEPATH=$cudaLib/cublas.lib",
|
||||
"-DCUDA_cublasLt_LIBRARY:FILEPATH=$cudaLib/cublasLt.lib"
|
||||
)
|
||||
}
|
||||
|
||||
function cudaArm64UnavailableReason {
|
||||
param (
|
||||
[string]$cuda
|
||||
)
|
||||
|
||||
$cudaArm64LibDir = Join-Path $cuda "lib\arm64"
|
||||
if (-not (Test-Path -LiteralPath $cudaArm64LibDir)) {
|
||||
return "missing Windows ARM64 import libraries under lib\arm64"
|
||||
}
|
||||
|
||||
$requiredLibs = @("cudart.lib", "cudart_static.lib", "cuda.lib", "cublas.lib", "cublasLt.lib")
|
||||
foreach ($lib in $requiredLibs) {
|
||||
$libPath = Join-Path $cudaArm64LibDir $lib
|
||||
if (-not (Test-Path -LiteralPath $libPath)) {
|
||||
return "missing Windows ARM64 import library $libPath"
|
||||
}
|
||||
}
|
||||
|
||||
return $null
|
||||
}
|
||||
|
||||
function cudaArm64ArchitectureArgs {
|
||||
if ($env:OLLAMA_WOA_CUDA_ARCHITECTURES) {
|
||||
Write-Output "Overriding Windows ARM64 CUDA architectures: $env:OLLAMA_WOA_CUDA_ARCHITECTURES"
|
||||
return @("-DCMAKE_CUDA_ARCHITECTURES=$env:OLLAMA_WOA_CUDA_ARCHITECTURES")
|
||||
}
|
||||
|
||||
return @()
|
||||
}
|
||||
|
||||
function cudaCommon {
|
||||
param (
|
||||
[string]$cudaMajorVer
|
||||
[string]$cudaMajorVer,
|
||||
[string]$cudaExactVer
|
||||
)
|
||||
|
||||
if ($script:ARCH -eq "arm64") {
|
||||
Write-Error "Use cudaArm64Common for Windows ARM64 CUDA builds"
|
||||
exit(1)
|
||||
}
|
||||
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
if ("$script:CUDA_DIRS".Contains("v$cudaMajorVer")) {
|
||||
foreach ($d in $Script:CUDA_DIRS){
|
||||
if ($d.FullName.Contains("v$cudaMajorVer")) {
|
||||
if (test-path -literalpath (join-path -path $d -childpath "nvcc.exe" ) ) {
|
||||
$cuda=($d.FullName|split-path -parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
$cuda = findCudaRoot $cudaMajorVer $cudaExactVer
|
||||
if ($cuda) {
|
||||
# Build llama-server CUDA backend from upstream source
|
||||
Write-Output "Building llama-server CUDA v$cudaMajorVer backend"
|
||||
$env:CUDAToolkit_ROOT=$cuda
|
||||
Write-Output "Building llama-server CUDA v$cudaMajorVer backend $cuda"
|
||||
$preset = "llama_cuda_v$($cudaMajorVer)_windows"
|
||||
$cudaToolsetArgs = cudaCMakeArgs $cuda
|
||||
$configureArgs = @("-S", "llama\server", "--preset", $preset) + $cudaToolsetArgs + @("--install-prefix", "$script:DIST_DIR")
|
||||
@@ -418,18 +619,98 @@ function cudaCommon {
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install "build\llama-server-cuda_v$cudaMajorVer" --component llama-server --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} else {
|
||||
if ($cudaExactVer) {
|
||||
Write-Output "CUDA v$cudaExactVer not detected, skipping"
|
||||
} else {
|
||||
Write-Output "CUDA v$cudaMajorVer not detected, skipping"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cudaArm64Common {
|
||||
param (
|
||||
[string]$cudaMajorVer,
|
||||
[string]$cudaExactVer,
|
||||
[switch]$Optional
|
||||
)
|
||||
|
||||
$cuda = findCudaRoot $cudaMajorVer $cudaExactVer
|
||||
if ($cuda) {
|
||||
$arm64DistDir = "${script:SRC_DIR}\dist\windows-arm64"
|
||||
mkdir -Force -path "${arm64DistDir}\lib\ollama\" | Out-Null
|
||||
|
||||
$unavailableReason = cudaArm64UnavailableReason $cuda
|
||||
if ($Optional -and $unavailableReason) {
|
||||
Write-Output "CUDA v$cudaMajorVer Windows ARM64 toolchain not detected ($unavailableReason), skipping"
|
||||
return
|
||||
}
|
||||
|
||||
Write-Output "Building llama-server CUDA v$cudaMajorVer backend for Windows ARM64 $cuda"
|
||||
$oldEnvironment = saveEnvironment
|
||||
$oldGenerator = $env:CMAKE_GENERATOR
|
||||
try {
|
||||
$env:CMAKE_GENERATOR = "Ninja"
|
||||
if ($Optional -and -not (ensureMsvcForNinja "arm64" -Optional)) {
|
||||
Write-Output "CUDA v$cudaMajorVer Windows ARM64 toolchain not detected, skipping"
|
||||
return
|
||||
}
|
||||
if (-not $Optional) {
|
||||
ensureMsvcForNinja "arm64"
|
||||
}
|
||||
$cudaArgs = cudaArm64CMakeArgs $cuda
|
||||
$architectureArgs = cudaArm64ArchitectureArgs
|
||||
$configureArgs = @(
|
||||
"-S", "llama\server",
|
||||
"--preset", "llama_cuda_v$($cudaMajorVer)_windows_arm64",
|
||||
"-G", "Ninja",
|
||||
"--install-prefix", "$arm64DistDir"
|
||||
) + $cudaArgs + $architectureArgs
|
||||
& cmake @configureArgs
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --build "build\llama-server-cuda_v$($cudaMajorVer)_arm64" --target ggml-cuda --config Release --parallel $script:JOBS
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
& cmake --install "build\llama-server-cuda_v$($cudaMajorVer)_arm64" --component llama-server --strip
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} finally {
|
||||
restoreEnvironment $oldEnvironment
|
||||
$env:CMAKE_GENERATOR = $oldGenerator
|
||||
}
|
||||
} else {
|
||||
if ($cudaExactVer) {
|
||||
Write-Output "CUDA v$cudaExactVer not detected, skipping Windows ARM64 build"
|
||||
} else {
|
||||
Write-Output "CUDA v$cudaMajorVer not detected, skipping Windows ARM64 build"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
function cuda12 {
|
||||
if ($script:ARCH -eq "arm64") {
|
||||
Write-Output "CUDA v12 is not supported on ARM64, skipping"
|
||||
return
|
||||
}
|
||||
cudaCommon("12")
|
||||
}
|
||||
|
||||
function cuda13 {
|
||||
cudaCommon("13")
|
||||
if ($script:ARCH -eq "arm64") {
|
||||
cudaArm64Common "13" "13.4"
|
||||
return
|
||||
}
|
||||
cudaCommon "13" "13.0"
|
||||
}
|
||||
|
||||
function cuda13Arm64 {
|
||||
cudaArm64Common "13" "13.4"
|
||||
}
|
||||
|
||||
function cuda13Arm64Cross {
|
||||
cuda13Arm64
|
||||
}
|
||||
|
||||
function cuda13Arm64IfAvailable {
|
||||
cudaArm64Common "13" "13.4" -Optional
|
||||
}
|
||||
|
||||
function rocm6 {
|
||||
@@ -513,15 +794,9 @@ function mlxCuda13 {
|
||||
mkdir -Force -path "${script:DIST_DIR}\" | Out-Null
|
||||
$cudaMajorVer="13"
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
if ("$script:CUDA_DIRS".Contains("v$cudaMajorVer")) {
|
||||
foreach ($d in $Script:CUDA_DIRS){
|
||||
if ($d.FullName.Contains("v$cudaMajorVer")) {
|
||||
if (test-path -literalpath (join-path -path $d -childpath "nvcc.exe" ) ) {
|
||||
$cuda=($d.FullName|split-path -parent)
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
$cudaExactVer = if ($env:OLLAMA_MLX_CUDA_VERSION) { $env:OLLAMA_MLX_CUDA_VERSION } else { "$cudaMajorVer.0" }
|
||||
$cuda = findCudaRoot $cudaMajorVer $cudaExactVer
|
||||
if ($cuda) {
|
||||
|
||||
# Check for cuDNN - required for MLX CUDA backend
|
||||
# Supports two layouts:
|
||||
@@ -554,7 +829,12 @@ function mlxCuda13 {
|
||||
}
|
||||
|
||||
Write-Output "Building MLX CUDA v$cudaMajorVer backend libraries $cuda"
|
||||
$oldCudaPath = $env:CUDA_PATH
|
||||
$oldCudaToolkitRoot = $env:CUDAToolkit_ROOT
|
||||
$oldCudaCxx = $env:CUDACXX
|
||||
$env:CUDA_PATH=$cuda
|
||||
$env:CUDAToolkit_ROOT=$cuda
|
||||
try {
|
||||
$cudaFlags = @()
|
||||
if ($env:OLLAMA_CMAKE_CUDA_FLAGS) {
|
||||
$cudaFlags += "-DCMAKE_CUDA_FLAGS=$env:OLLAMA_CMAKE_CUDA_FLAGS"
|
||||
@@ -569,8 +849,14 @@ function mlxCuda13 {
|
||||
}
|
||||
& cmake @buildArgs
|
||||
if ($LASTEXITCODE -ne 0) { exit($LASTEXITCODE)}
|
||||
} finally {
|
||||
$env:CUDA_PATH=$oldCudaPath
|
||||
$env:CUDAToolkit_ROOT=$oldCudaToolkitRoot
|
||||
$env:CUDACXX=$oldCudaCxx
|
||||
}
|
||||
} else {
|
||||
Write-Output "CUDA v$cudaMajorVer not detected, skipping MLX build"
|
||||
Write-Output "CUDA v$cudaExactVer not detected - set OLLAMA_MLX_CUDA_VERSION to use a different CUDA v$cudaMajorVer toolkit"
|
||||
Write-Output "Skipping MLX build"
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -867,6 +1153,57 @@ function newDependencyAuditJob($payloadDir, $label, $reportPath, $dependencyDirs
|
||||
} -ArgumentList $payloadDir, $label, $reportPath, $dumpbin, $dependencyDirText
|
||||
}
|
||||
|
||||
function verifyWindowsArm64Binaries {
|
||||
param (
|
||||
[string]$payloadDir = "${script:SRC_DIR}\dist\windows-arm64"
|
||||
)
|
||||
|
||||
$dumpbin = findDumpbin
|
||||
if (-not $dumpbin) {
|
||||
Write-Error "Unable to locate dumpbin.exe for Windows ARM64 binary verification"
|
||||
exit(1)
|
||||
}
|
||||
if (-not (Test-Path -Path $payloadDir)) {
|
||||
Write-Error "Windows ARM64 payload directory not found: $payloadDir"
|
||||
exit(1)
|
||||
}
|
||||
|
||||
$binaries = Get-ChildItem -Path $payloadDir -Recurse -File -Include *.dll,*.exe | Sort-Object FullName
|
||||
if (-not $binaries) {
|
||||
Write-Error "No Windows binaries found under $payloadDir"
|
||||
exit(1)
|
||||
}
|
||||
|
||||
$bad = [System.Collections.Generic.List[string]]::new()
|
||||
$arm64xCount = 0
|
||||
foreach ($binary in $binaries) {
|
||||
$output = & $dumpbin /nologo /headers $binary.FullName 2>&1
|
||||
if ($LASTEXITCODE -ne 0) {
|
||||
$bad.Add("$($binary.FullName): dumpbin failed with exit code $LASTEXITCODE")
|
||||
continue
|
||||
}
|
||||
|
||||
$machineLine = $output | Where-Object { $_ -match '^\s*[0-9A-Fa-f]+\s+machine\s+\(' } | Select-Object -First 1
|
||||
if (-not $machineLine) {
|
||||
$bad.Add("$($binary.FullName): unable to determine PE machine type")
|
||||
continue
|
||||
}
|
||||
if ($machineLine -match '\(ARM64X\)') {
|
||||
$arm64xCount++
|
||||
continue
|
||||
}
|
||||
if ($machineLine -notmatch '^\s*AA64\s+machine\s+\(ARM64\)') {
|
||||
$bad.Add("$($binary.FullName): $machineLine")
|
||||
}
|
||||
}
|
||||
|
||||
if ($bad.Count -gt 0) {
|
||||
Write-Error "Windows ARM64 binary verification failed:`n$([string]::Join([Environment]::NewLine, $bad))"
|
||||
exit(1)
|
||||
}
|
||||
Write-Output "Verified $($binaries.Count) Windows ARM64/ARM64X binaries under $payloadDir ($arm64xCount ARM64X)"
|
||||
}
|
||||
|
||||
function stageComponents($mainDir, $stagingDir, $pattern, $readmePrefix) {
|
||||
$components = Get-ChildItem -Path "${mainDir}\lib\ollama" -Directory -Filter $pattern -ErrorAction SilentlyContinue
|
||||
if ($components) {
|
||||
@@ -924,6 +1261,7 @@ function zip {
|
||||
$arm64Dir = "${distDir}\windows-arm64"
|
||||
if (Test-Path -Path $arm64Dir) {
|
||||
if ((Test-Path -Path "${arm64Dir}\ollama.exe") -and (Test-Path -Path "${arm64Dir}\lib\ollama\llama-server.exe")) {
|
||||
verifyWindowsArm64Binaries $arm64Dir
|
||||
Write-Output "Generating ${distDir}\ollama-windows-arm64.zip"
|
||||
$jobs += newZipJob $arm64Dir "${distDir}\ollama-windows-arm64.zip"
|
||||
$jobs += newDependencyAuditJob $arm64Dir "windows-arm64" "${distDir}\dependency-audit-windows-arm64.txt"
|
||||
@@ -962,15 +1300,18 @@ checkEnv
|
||||
try {
|
||||
if ($($args.count) -eq 0) {
|
||||
cpu
|
||||
cpuArm64
|
||||
cuda12
|
||||
cuda13
|
||||
if ($script:ARCH -ne "arm64") {
|
||||
cuda13Arm64IfAvailable
|
||||
}
|
||||
rocm7
|
||||
vulkan
|
||||
mlxCuda13
|
||||
ollama
|
||||
app
|
||||
cpuArm64
|
||||
ollamaArm64
|
||||
app
|
||||
appArm64
|
||||
deps
|
||||
sign
|
||||
|
||||
Reference in New Issue
Block a user