Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -73,6 +73,12 @@ jobs:
conan install . --build=missing -cc core.version_ranges:resolve_prereleases=True
conan build . -cc core.version_ranges:resolve_prereleases=True

# Build llama-cpp for Windows arm64, both natively and crossbuilt from x86_64
- name: conan create llama-cpp
if: matrix.cuda-version == '13.4' && startsWith(matrix.os, 'windows')
working-directory: samples/llama-cpp
run: conan create all --version=b6565 -cc core.version_ranges:resolve_prereleases=True --build=missing -pr clang-cl-arm64

# Skip the following for 13.4-preview
- name: conan create cudnn
if: matrix.cuda-version != '13.4' && !contains(matrix.os, '-arm')
Expand Down
23 changes: 22 additions & 1 deletion docs/building-for-windows-on-arm.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ conan create . -s arch=armv8

When cross-building, Conan ensures that `nvcc` runs on your x86_64 workstation, while the CUDA libraries linked into your application are ARM64.

## Example: building and running `cuda-samples`
## Example 1: building and running `cuda-samples`

[`cuda-samples`](https://github.com/NVIDIA/cuda-samples) is NVIDIA's official collection of example CUDA
applications. It ranges from minimal examples like
Expand Down Expand Up @@ -103,6 +103,27 @@ build\Release\cpp\1_Utilities\deviceQuery\deviceQuery.exe
The application should launch successfuly. If there is no GPU with an NVIDIA driver installed, it should simply report that cudaGetDeviceCount returned an error querying the devices.


## Example 2: building `llama-cpp` for Windows ARM64 with CUDA support for RTX Spark

[`llama.cpp`](https://github.com/ggml-org/llama.cpp) is a widely used, dependency-light C/C++ inference engine
for LLaMA and other GGUF-format language models. It's one of the most popular ways to run LLMs locally, with
over 80k stars on GitHub, and is the engine behind many downstream projects (Ollama, LM Studio, and others).

This repository contains a recipe to build `llama.cpp` from source using CUDA from Conan, including support
for Windows ARM64:

```
cd samples/llama-cpp
conan create all --version=b6565 -pr clang-cl-arm64 -cc core.version_ranges:resolve_prereleases=True
```

This command can be run on x86_64 Windows and ARM64 Windows. You can customize the CUDA GPU architecture by editing the profile at `samples/llama-cpp/clang-cl-common`.

> [!IMPORTANT]
> Windows ARM64 builds of `llama.cpp` currently currently require building with **Clang** (`clang-cl`), rather than MSVC's
> `cl.exe`. Clang can be installed via the **Visual Studio Installer**: under **Individual components**, search
> for **"Clang"** and select the **C++ Clang Compiler for Windows** component, then apply.

## Current limitations

- While the ARM64 binaries will run on any Windows on ARM, CUDA support at runtime can only be tested on NVIDIA-powered devices.
Expand Down
1 change: 1 addition & 0 deletions samples/llama-cpp/all/conanfile.py
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,7 @@ def generate(self):
# Follow with_examples when newer versions can compile examples,
# right now it tries to add_subdirectory to a non-existent folder
tc.variables["GGML_BUILD_EXAMPLES"] = False
tc.cache_variables["GGML_OPENMP"] = "OFF"
tc.variables["GGML_CUDA"] = self.options.get_safe("with_cuda")
if self.settings.compiler in ("msvc", "clang") and self.options.get_safe("with_cuda"):
tc.cache_variables['CMAKE_CUDA_FLAGS'] = '-Xcompiler /Zc:preprocessor '
Expand Down
8 changes: 8 additions & 0 deletions samples/llama-cpp/clang-cl-arm64
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
include(clang-cl-common)

[settings]
arch=armv8

[conf]
tools.build:cflags=['--target=aarch64-pc-windows-msvc']
tools.build:cxxflags=['--target=aarch64-pc-windows-msvc']
33 changes: 33 additions & 0 deletions samples/llama-cpp/clang-cl-common
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
{% set msvc, msvc_version, _ = detect_api.detect_msvc_compiler() %}
{# msvc_version is e.g. "193", "194", "195" — first two digits = toolset generation #}
{% set toolset_map = {"190": "v140", "191": "v141", "192": "v142", "193": "v143", "194": "v144", "195": "v145"} %}
{% set runtime_version = toolset_map.get(msvc_version|string|truncate(3, end=''), "v143") %}

{# Derive the VS install path from the registry via vswhere #}
{% set vswhere = subprocess.check_output(
['C:\\Program Files (x86)\\Microsoft Visual Studio\\Installer\\vswhere.exe',
'-latest', '-property', 'installationPath'],
stderr=subprocess.DEVNULL
).decode().strip() %}

{# Read the clang-cl version from its manifest file inside the VS install — no dev prompt needed #}
{% set clang_exe = vswhere + '\\VC\\Tools\\Llvm\\x64\\bin\\clang-cl.exe' %}
{% set clang_version = subprocess.check_output(
[clang_exe, '--version'],
stderr=subprocess.STDOUT
).decode().split('version ')[1].split('.')[0].strip() %}

[settings]
build_type=Release
compiler=clang
compiler.cppstd=17
compiler.runtime=dynamic
compiler.version={{ clang_version }}
compiler.runtime_version={{ runtime_version }}
os=Windows


[conf]
tools.cmake.cmaketoolchain:generator=Ninja
tools.build:compiler_executables={"c": "clang-cl", "cpp": "clang-cl"}
tools.cmake.cmaketoolchain:extra_variables*={'CMAKE_CUDA_ARCHITECTURES':'87-real'}
4 changes: 4 additions & 0 deletions samples/llama-cpp/clang-cl-x64
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
include(clang-cl-common)

[settings]
arch=x86_64