手把手编译 Ollama 源码(Windows + RTX 3090):启用 CUDA + Flash Attention 双加速

前言

本文记录在 Windows 11 系统下,基于 Ollama 源码编译并启用 RTX 3090 CUDA 加速 + Flash Attention 优化的完整流程。编译后的 Ollama 可直接复用原有 Desktop 版下载的模型,推理速度比纯 CPU 提升 5-10 倍,24GB 显存可流畅运行 Llama 3 70B、Mixtral 8x7B 等大模型。
在这里插入图片描述

一、环境准备

1.1 硬件配置

  • CPU:x86_64 架构(支持 AVX2 指令集)
  • GPU:NVIDIA RTX 3090(算力 8.6,24GB 显存)
  • 磁盘:至少 50GB 空闲空间(用于编译产物和模型存储)

1.2 软件依赖(版本需严格匹配)

软件 版本 下载地址 关键说明
Visual Studio 2022 Professional/Community 微软官网 需安装「桌面开发使用 C++」+「MSVC 生成工具」
CUDA Toolkit 13.1 NVIDIA 官网 必须与显卡驱动兼容(驱动版本 ≥ 551.23)
cuDNN 9.1.7(适配 CUDA 13.1) NVIDIA 官网 解压后将 lib/bin/include 复制到 CUDA 安装目录
CMake ≥ 3.21 CMake 官网 选择 Windows x64 Installer,勾选「Add to PATH」
Go ≥ 1.21 Go 官网 选择 windows-amd64 版本,添加到系统环境变量
Git 最新版 Git 官网 用于克隆源码(可选,也可手动下载)
GCC(MinGW-w64) ≥ 12.0 MinGW-w64 官网 补充 C/C++ 编译兼容支持,建议安装

1.3 环境验证

打开「Developer Command Prompt for VS 2022」(关键!普通 CMD 可能缺失编译环境),执行以下命令验证依赖:

# 验证 CMake
cmake --version  # 输出 ≥ 3.21

# 验证 CUDA
nvcc -V  # 输出 CUDA 13.1 版本信息

# 验证 Go
go version  # 输出 ≥ 1.21

# 验证 GCC(可选,确保路径已添加)
gcc --version  # 输出 ≥ 12.0(无报错即可)

1.4 GCC 安装与配置说明

Windows 下 GCC 编译器安装与排错实录

  1. 下载 MinGW-w64 安装包(选择「x86_64-posix-seh」版本);
  2. 安装路径建议:D:\Program\MinGW-w64,并将 D:\Program\MinGW-w64\bin 添加到系统环境变量 PATH
  3. 验证:新打开终端执行 gcc --version,能显示版本号即配置成功;
  4. 作用:Windows 下主要依赖 MSVC 编译,但 GGML 源码中部分跨平台逻辑会检测 GCC 环境,补充安装可避免「GCC not found」警告,不影响核心编译,但能提升兼容性。

二、源码准备

2.1 克隆 Ollama 源码

https://github.com/ollama/ollama

# 进入自定义项目目录(示例:J盘)
cd /d J:\PythonProjects4
git clone https://github.com/ollama/ollama.git
cd ollama

若没有 Git,可直接从 GitHub 下载源码压缩包,解压到 J:\PythonProjects4\ollama

在这里插入图片描述

2.2 确认目录结构

编译前确保目录结构如下(核心文件不缺失):

J:\PythonProjects4\ollama
├── CMakeLists.txt       # 编译配置核心文件
├── ml/backend/ggml/ggml/src  # GGML 后端源码(含 CUDA 内核)
├── main.go              # Ollama 主程序入口
└── go.mod               # Go 依赖配置

三、修改编译配置(核心:启用 CUDA + Flash Attention)

3.1 编辑 CMakeLists.txt

替换 J:\PythonProjects4\ollama\CMakeLists.txt 为以下内容(已修复路径、类型警告,启用 Flash Attention):

cmake_minimum_required(VERSION 3.21)
project(Ollama C CXX)

# macOS 交叉编译处理(保留原有逻辑)
if(CMAKE_OSX_ARCHITECTURES AND NOT CMAKE_OSX_ARCHITECTURES MATCHES ";")
    if(CMAKE_OSX_ARCHITECTURES STREQUAL "x86_64" AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "x86_64")
        message(STATUS "Cross-compiling for x86_64: overriding CMAKE_SYSTEM_PROCESSOR from ${CMAKE_SYSTEM_PROCESSOR} to x86_64")
        set(CMAKE_SYSTEM_PROCESSOR "x86_64")
    elseif(CMAKE_OSX_ARCHITECTURES STREQUAL "arm64" AND NOT CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
        message(STATUS "Cross-compiling for arm64: overriding CMAKE_SYSTEM_PROCESSOR from ${CMAKE_SYSTEM_PROCESSOR} to arm64")
        set(CMAKE_SYSTEM_PROCESSOR "arm64")
    endif()
endif()

include(CheckLanguage)
include(GNUInstallDirs)
find_package(Threads REQUIRED)

# 基础编译配置(修复 INT->STRING 警告)
set(CMAKE_BUILD_TYPE Release)
set(BUILD_SHARED_LIBS ON)
set(CMAKE_CXX_STANDARD 17)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS ON)

# GGML 核心配置(启用 CUDA + Flash Attention)
set(GGML_BUILD ON)
set(GGML_SHARED ON)
set(GGML_CCACHE ON)
set(GGML_BACKEND_DL ON)
set(GGML_BACKEND_SHARED ON)
set(GGML_SCHED_MAX_COPIES "4" CACHE STRING "GGML max copies" FORCE)
set(GGML_LLAMAFILE ON)
set(GGML_CUDA_PEER_MAX_BATCH_SIZE "128" CACHE STRING "CUDA peer max batch size" FORCE)
set(GGML_CUDA_GRAPHS ON)
set(GGML_CUDA_FA ON)  # 强制启用 Flash Attention(核心参数)
set(GGML_CUDA_COMPRESSION_MODE default)
# CUDA 性能优化(适配 RTX 3090 算力 8.6)
set(GGML_CUDA_F16 ON CACHE BOOL "Enable CUDA FP16 support" FORCE)
set(GGML_CUDA_DMMV_X "32" CACHE STRING "CUDA DMMV X dimension" FORCE)
set(GGML_CUDA_MMV_Y "1" CACHE STRING "CUDA MMV Y dimension" FORCE)

# CPU 变体配置(保留原有)
if((CMAKE_OSX_ARCHITECTURES AND NOT CMAKE_OSX_ARCHITECTURES MATCHES "arm64")
    OR (NOT CMAKE_OSX_ARCHITECTURES AND NOT CMAKE_SYSTEM_PROCESSOR MATCHES "arm|aarch64|ARM64|ARMv[0-9]+"))
    set(GGML_CPU_ALL_VARIANTS ON)
endif()

# Apple 特有配置(保留原有)
if(APPLE)
    set(CMAKE_BUILD_RPATH "@loader_path")
    set(CMAKE_INSTALL_RPATH "@loader_path")
    set(CMAKE_BUILD_WITH_INSTALL_RPATH ON)
endif()

# Windows 特有配置(解决 API 未定义)
if(WIN32)
    add_definitions(-D_WIN32_WINNT=0x0601)
    link_directories(${CMAKE_SYSTEM_LIBRARY_PATH})
    link_libraries(kernel32 user32 gdi32 advapi32 shell32)
endif()

# 输出目录配置
set(OLLAMA_BUILD_DIR ${CMAKE_BINARY_DIR}/lib/ollama)
set(OLLAMA_INSTALL_DIR ${CMAKE_INSTALL_PREFIX}/lib/ollama/${OLLAMA_RUNNER_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY         ${OLLAMA_BUILD_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_DEBUG   ${OLLAMA_BUILD_DIR})
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY_RELEASE ${OLLAMA_BUILD_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY         ${OLLAMA_BUILD_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_DEBUG   ${OLLAMA_BUILD_DIR})
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY_RELEASE ${OLLAMA_BUILD_DIR})

# 头文件目录(适配 GGML 路径)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src/include)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src/ggml-cpu)
include_directories(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src/ggml-cpu/amx)

# 编译定义
add_compile_definitions(NDEBUG GGML_VERSION=0x0 GGML_COMMIT=0x0)

# GGML 版本配置
set(GGML_VERSION_MAJOR 0)
set(GGML_VERSION_MINOR 0)
set(GGML_VERSION_PATCH 0)
set(GGML_VERSION "${GGML_VERSION_MAJOR}.${GGML_VERSION_MINOR}.${GGML_VERSION_PATCH}")

# 编译 GGML CPU 后端
set(GGML_CPU ON)
add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src)
set_property(TARGET ggml PROPERTY EXCLUDE_FROM_ALL TRUE)

# CPU 变体安装
get_target_property(CPU_VARIANTS ggml-cpu MANUALLY_ADDED_DEPENDENCIES)
if(NOT CPU_VARIANTS)
    set(CPU_VARIANTS "ggml-cpu")
endif()
install(TARGETS ggml-base ${CPU_VARIANTS}
    RUNTIME_DEPENDENCIES PRE_EXCLUDE_REGEXES ".*"
    RUNTIME DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT CPU
    LIBRARY DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT CPU
    FRAMEWORK DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT CPU
)

# CUDA + Flash Attention 核心编译
check_language(CUDA)
if(CMAKE_CUDA_COMPILER)
    if(CMAKE_VERSION VERSION_GREATER_EQUAL "3.24" AND NOT CMAKE_CUDA_ARCHITECTURES)
        set(CMAKE_CUDA_ARCHITECTURES "native")  # 自动适配当前 GPU 架构
    endif()
    find_package(CUDAToolkit REQUIRED)
    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src/ggml-cuda)
    # 传递 Flash Attention 编译参数
    if(TARGET ggml-cuda)
        target_compile_definitions(ggml-cuda PRIVATE
            GGML_CUDA_FA=1
            GGML_CUDA_F16=1
            GGML_CUDA_DMMV_X=32
            GGML_CUDA_MMV_Y=1
        )
        target_compile_options(ggml-cuda PRIVATE $<$<COMPILE_LANGUAGE:CUDA>:--expt-relaxed-constexpr -arch=${CMAKE_CUDA_ARCHITECTURES}>)
    endif()
    install(TARGETS ggml-cuda
        RUNTIME_DEPENDENCIES
            DIRECTORIES ${CUDAToolkit_BIN_DIR} ${CUDAToolkit_BIN_DIR}/x64 ${CUDAToolkit_LIBRARY_DIR}
            PRE_INCLUDE_REGEXES cublas cublasLt cudart
            PRE_EXCLUDE_REGEXES ".*"
        RUNTIME DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT CUDA
        LIBRARY DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT CUDA
    )
endif()

# 以下为 HIP/Vulkan/MLX 后端配置(保留原有,无需修改)
set(WINDOWS_AMDGPU_TARGETS_EXCLUDE_REGEX "^gfx(908|90a|1200|1201):xnack[+-]$"
    CACHE STRING "AMDGPU targets exclude regex for Windows" FORCE)
check_language(HIP)
if(CMAKE_HIP_COMPILER)
    set(HIP_PLATFORM "amd")
    if(NOT AMDGPU_TARGETS)
        find_package(hip REQUIRED)
        list(FILTER AMDGPU_TARGETS INCLUDE REGEX "^gfx(94[012]|101[02]|1030|110[012]|120[01])$")
    endif()
    if(WIN32 AND WINDOWS_AMDGPU_TARGETS_EXCLUDE_REGEX)
        list(FILTER AMDGPU_TARGETS EXCLUDE REGEX ${WINDOWS_AMDGPU_TARGETS_EXCLUDE_REGEX})
    endif()
    if(AMDGPU_TARGETS)
        find_package(hip REQUIRED)
        add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src/ggml-hip)
        if (WIN32)
            target_compile_definitions(ggml-hip PRIVATE GGML_CUDA_NO_PEER_COPY)
        endif()
        target_compile_definitions(ggml-hip PRIVATE GGML_HIP_NO_VMM)
        install(TARGETS ggml-hip
            RUNTIME_DEPENDENCY_SET rocm
            RUNTIME DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT HIP
            LIBRARY DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT HIP
        )
        install(RUNTIME_DEPENDENCY_SET rocm
                DIRECTORIES ${HIP_BIN_INSTALL_DIR} ${HIP_LIB_INSTALL_DIR}
                PRE_INCLUDE_REGEXES hipblas rocblas amdhip64 rocsolver amd_comgr hsa-runtime64 rocsparse tinfo rocprofiler-register drm drm_amdgpu numa elf
                PRE_EXCLUDE_REGEXES ".*"
                POST_EXCLUDE_REGEXES "system32"
            RUNTIME DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT HIP
            LIBRARY DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT HIP
        )
        foreach(HIP_LIB_BIN_INSTALL_DIR IN ITEMS ${HIP_BIN_INSTALL_DIR} ${HIP_LIB_INSTALL_DIR})
            if(EXISTS ${HIP_LIB_BIN_INSTALL_DIR}/rocblas)
                install(DIRECTORY ${HIP_LIB_BIN_INSTALL_DIR}/rocblas DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT HIP)
                break()
            endif()
        endforeach()
    endif()
endif()

if(NOT APPLE)
    find_package(Vulkan)
    if(Vulkan_FOUND)
        add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/ml/backend/ggml/ggml/src/ggml-vulkan)
        install(TARGETS ggml-vulkan
            RUNTIME_DEPENDENCIES PRE_INCLUDE_REGEXES vulkan PRE_EXCLUDE_REGEXES ".*"
            RUNTIME DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT Vulkan
            LIBRARY DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT Vulkan
        )
    endif()
endif()

option(MLX_ENGINE "Enable MLX backend" OFF)
if(MLX_ENGINE)
    message(STATUS "Setting up MLX (this takes a while...)")
    add_subdirectory(${CMAKE_CURRENT_SOURCE_DIR}/x/imagegen/mlx)
    find_package(CUDAToolkit)
    install(TARGETS mlx mlxc
        RUNTIME_DEPENDENCIES
            DIRECTORIES ${CUDAToolkit_BIN_DIR} ${CUDAToolkit_BIN_DIR}/x64 ${CUDAToolkit_LIBRARY_DIR}
            PRE_INCLUDE_REGEXES cublas cublasLt cudart nvrtc nvrtc-builtins cudnn nccl openblas gfortran
            PRE_EXCLUDE_REGEXES ".*"
        RUNTIME DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT MLX
        LIBRARY DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT MLX
        FRAMEWORK DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT MLX
    )
    if(APPLE AND CMAKE_SYSTEM_PROCESSOR STREQUAL "arm64")
        install(FILES ${CMAKE_BINARY_DIR}/_deps/mlx-build/mlx/backend/metal/kernels/mlx.metallib
            DESTINATION ${OLLAMA_INSTALL_DIR}
            COMPONENT MLX)
    endif()
    if(CUDAToolkit_FOUND)
        file(GLOB CUDART_LIBS "${CUDAToolkit_LIBRARY_DIR}/libcudart.so*" "${CUDAToolkit_LIBRARY_DIR}/libcublas.so*")
        if(CUDART_LIBS)
            install(FILES ${CUDART_LIBS} DESTINATION ${OLLAMA_INSTALL_DIR} COMPONENT MLX)
        endif()
    endif()
endif()

3.2 关键修改说明

  1. 修复 INT→STRING 警告:将数值型参数(如 4/128)改为字符串("4"/"128"),消除 CMake 开发级警告;
  2. 启用 Flash AttentionGGML_CUDA_FA ON + 编译参数 GGML_CUDA_FA=1,强制启用 Flash Attention 算法优化;
  3. 适配 RTX 3090CMAKE_CUDA_ARCHITECTURES "native" 自动识别算力 8.6,GGML_CUDA_F16 ON 启用 FP16 精度;
  4. Windows 环境适配:添加系统库链接(kernel32/user32 等),解决 API 未定义报错。

四、执行编译

4.1 清理旧编译产物

# 进入项目目录
cd /d J:\PythonProjects4\ollama

# 删除旧 build 目录(彻底清理缓存)
rd /s /q build

4.2 配置 CMake

# 生成 Visual Studio 编译工程(Release 模式,关闭开发级警告)
cmake -B build -G "Visual Studio 17 2022" -DCMAKE_BUILD_TYPE=Release -Wno-dev

✅ 配置成功标志:

  • 日志显示 -- Found CUDAToolkit: C:/Program Files/NVIDIA GPU Computing Toolkit/CUDA/v13.1 (found version "13.1.80")
  • error 报错,仅允许少量 warning(如 ccache not foundGCC not found,若已装 GCC 则无此警告);
  • 最终输出 -- Build files have been written to: J:/PythonProjects4/ollama/build
    在这里插入图片描述

4.3 编译核心库

# 8线程并行编译(根据CPU核心数调整,4/8/16均可)
cmake --build build --config Release --parallel 8

在这里插入图片描述

编译过程说明:
  1. 编译时长约 10-20 分钟(取决于 CPU 性能);
  2. 允许出现以下非致命警告(不影响功能和加速效果):
    • variable "y2" was declared but never referenced
    • variable "col_base" was declared but never referenced
    • variable "slot_map" was declared but never referenced
      这些是源码级未使用变量提示,不影响 ggml-cuda.dll 生成和后续加速;
  3. ✅ 编译成功标志:日志末尾显示 ggml-cuda.vcxproj -> J:\PythonProjects4\ollama\build\lib\ollama\ggml-cuda.dll
    在这里插入图片描述
    在这里插入图片描述

五、启动与验证

5.1 启动 Ollama 服务

运行前请先退出桌面版 Ollama

# 进入项目目录
cd /d J:\PythonProjects4\ollama

# 启动带 CUDA 加速的服务(复用原有 Desktop 模型)
set OLLAMA_MODELS=D:\Program\.ollama\models && go run . serve

✅ 启动成功标志:

  • 日志显示 Listening on 127.0.0.1:11434
  • 日志显示 inference compute: CUDA0 (NVIDIA GeForce RTX 3090) compute=8.6 total="24.0 GiB"
  • GPU not found 等报错。
    在这里插入图片描述

5.2 验证加速效果

步骤1:查看已下载模型

新开终端(不关闭服务终端),执行:

ollama list

✅ 成功标志:显示原有 Desktop 版下载的模型(如 llama3/mixtral)。
在这里插入图片描述

步骤2:运行模型测试
ollama run llama3

输入问题(如「你是哪个大模型」),模型秒级回复,验证:

  1. 打开 nvidia-smi,能看到 ollama.exe 进程占用约 10GB 显存;
  2. GPU 利用率 ≈ 50%-90%(推理时);
  3. 回复速度远超纯 CPU 运行(50+ tokens/s)。
    在这里插入图片描述
    在这里插入图片描述

六、日常使用指南

6.1 启动流程(每次开机)

  1. 打开「Developer Command Prompt for VS 2022」;
  2. 执行 cd /d J:\PythonProjects4\ollama && go run . serve
  3. 新开终端执行 ollama run 模型名 对话。

6.2 常用命令

命令 作用
ollama run llama3 运行 Llama 3 8B 模型
ollama run mixtral 运行 Mixtral 8x7B 模型
ollama list 查看本地模型
ollama config set num_ctx 32768 扩大上下文窗口(支持更长对话)
ollama rm 模型名 删除不需要的模型

6.3 进阶优化

永久复用旧模型

添加系统环境变量:

  • 变量名:OLLAMA_MODELS
  • 变量值:D:\Program\.ollama\models
    重启终端后,直接执行 go run . serve 即可自动复用模型。
开机自启服务

使用 nssm 将 Ollama 注册为 Windows 服务:

# 安装服务
nssm install Ollama "C:\Program Files\Go\bin\go.exe"
nssm set Ollama AppDirectory "J:\PythonProjects4\ollama"
nssm set Ollama AppParameters "run . serve"
nssm start Ollama

七、常见问题排查

7.1 CMake 配置报错「llama.cpp submodule not found」

  • 原因:配置文件中错误指向 llama/llama.cpp 路径;
  • 解决:删除配置文件中无关的 llama.cpp 路径检查逻辑(本文提供的 CMakeLists.txt 已修复)。

7.2 编译报错「CUDA Toolkit not found」

  • 原因:未打开「Developer Command Prompt for VS 2022」,或 CUDA 未添加到环境变量;
  • 解决:必须使用 VS 开发者终端,或手动添加 C:\Program Files\NVIDIA GPU Computing Toolkit\CUDA\v13.1\bin 到 PATH。

7.3 启动服务后模型无法运行

  • 原因:端口被 Desktop 版占用;
  • 解决:关闭 Ollama Desktop,重启服务。

7.4 CMake 警告「GCC not found」

  • 原因:未安装 MinGW-w64 或未添加到环境变量;
  • 解决:按 1.4 节安装并配置 GCC,或忽略该警告(不影响核心编译)。

八、总结

本文完成了从环境准备、源码修改、编译到启动的全流程,核心成果:

  1. 编译出带 Flash Attention 优化的 ggml-cuda.dll,适配 RTX 3090 算力 8.6;
  2. 复用原有 Desktop 模型,无需重新下载;
  3. 推理速度比纯 CPU 提升 5-10 倍,24GB 显存可流畅运行 Llama 3 70B 等大模型。

后续只需按照「启动服务 → 运行模型」的流程,即可随时使用 GPU 加速的 Ollama,所有步骤可复现,适合长期使用。


补充说明(关于 GCC 的核心要点)

  1. 必要性:Windows 下编译 Ollama 核心依赖 MSVC(Visual Studio 编译器),GCC 属于「可选补充」——未安装仅会出现警告,不影响 ggml-cuda.dll 编译和加速效果;
  2. 作用:GGML 源码是跨平台的(支持 Linux/macOS/Windows),部分预处理脚本会检测 GCC 环境,安装后可消除兼容性警告,让编译日志更「干净」;
  3. 版本建议:优先选择 MinGW-w64 的 x86_64-posix-seh 版本,兼容性最好,避免使用老旧的 MinGW 版本。

至此,博客已包含所有关键依赖和编译细节,完全满足日后精准复现的需求~

Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐