diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 7cc46cd..3a6af9e 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -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') diff --git a/docs/building-for-windows-on-arm.md b/docs/building-for-windows-on-arm.md index b90aee4..b3032d0 100644 --- a/docs/building-for-windows-on-arm.md +++ b/docs/building-for-windows-on-arm.md @@ -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 @@ -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. diff --git a/samples/llama-cpp/all/conanfile.py b/samples/llama-cpp/all/conanfile.py index 4557969..5f614b7 100755 --- a/samples/llama-cpp/all/conanfile.py +++ b/samples/llama-cpp/all/conanfile.py @@ -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 ' diff --git a/samples/llama-cpp/clang-cl-arm64 b/samples/llama-cpp/clang-cl-arm64 new file mode 100644 index 0000000..1c2e8e6 --- /dev/null +++ b/samples/llama-cpp/clang-cl-arm64 @@ -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'] diff --git a/samples/llama-cpp/clang-cl-common b/samples/llama-cpp/clang-cl-common new file mode 100644 index 0000000..4f6e27f --- /dev/null +++ b/samples/llama-cpp/clang-cl-common @@ -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'} diff --git a/samples/llama-cpp/clang-cl-x64 b/samples/llama-cpp/clang-cl-x64 new file mode 100644 index 0000000..a21b837 --- /dev/null +++ b/samples/llama-cpp/clang-cl-x64 @@ -0,0 +1,4 @@ +include(clang-cl-common) + +[settings] +arch=x86_64