首页
/ Ollama 开发指南:从零构建 Ollama 二进制与原生推理后端的完整流程

Ollama 开发指南:从零构建 Ollama 二进制与原生推理后端的完整流程

2026-09-04 14:31:26作者:彭桢灵Jeremy

本文基于 Ollama 仓库的 开发文档,系统讲解如何为 Ollama 搭建开发环境:从纯 Go 代码的快速迭代(go run . serve),到使用 CMake 超级构建(superbuild)编译 llama.cpp 与 MLX 原生推理负载,再到 CUDA/ROCm/Vulkan/Metal 各 GPU 后端的选择、架构裁剪、Docker 镜像构建、测试运行与运行时库检测机制的源码级解析。读完后你可以独立完成 Ollama 本地构建,理解每个 CMake 缓存变量如何落到 build/lib/ollama 目录下的原生运行时,以及 Go 主程序是如何找到这些库的。

一、开发环境前置条件

按照官方文档,构建 Ollama 需要以下工具链:

  • Go(用于构建 ollama 主程序)
  • CMake 3.24 或更高版本(根 CMakeLists.txt 第一行即声明 cmake_minimum_required(VERSION 3.24)
  • C/C++ 编译器:macOS 使用 Clang,Windows 使用 Visual Studio 2022 C++ 工具集,Linux 使用 GCC/Clang
  • 推荐将 Ninja 加入 PATH,在 Windows 上尤其重要

根 CMake 工程还约定了几个关键默认值,这些都可以被 CMakePresets 覆盖:

  • 未显式指定时,CMAKE_BUILD_TYPE 默认强制为 ReleaseCMakeLists.txt
  • C++ 标准为 C++17 且开启 GNU 扩展,注释明确说明“较新版本的 MLX 需要 gnu++17 扩展才能正确编译”(CMakeLists.txt
  • 除 macOS 外默认 BUILD_SHARED_LIBS=ON;RPATH 分别设置为 @loader_path(macOS)或 $ORIGIN(其他 UNIX),确保运行时从二进制自身位置加载本地库(CMakeLists.txt

二、纯 Go 迭代:go run . serve

如果你只修改 Go 代码、并且仓库中已经存在可用的原生负载(native payload),最轻量的方式是直接在仓库根目录运行:

go run . serve

注意(原文档 NOTE):Ollama 包含通过 CGO 编译的原生代码。这些数据结构的定义偶尔会发生变化,导致 CGO 生成的绑定与 C 侧不同步,出现意料之外的崩溃。此时可以先执行 go clean -cache 强制原生代码完整重新构建。

三、原生构建模型:CMake 超级构建

对于全新 checkout,或修改过原生代码之后,需要从仓库根目录执行完整构建。默认行为是:

  • macOS arm64:构建 Metal 推理(静态链接、嵌入 Metal 库)
  • 其他平台:构建纯 CPU 推理

构建产物为仓库根目录下的 Go 二进制,原生运行时负载安装到 build/lib/ollama

cmake -B build .
cmake --build build --parallel 8
./ollama serve

安装到标准前缀布局:

cmake --install build --prefix /path/to/install

3.1 超级构建的内部编排

从源码结构看,根 CMakeLists.txt 只是“编排入口”,真正的构建逻辑全部委托给 cmake/local.cmake,其文件头注释写得很直白:

This file keeps the repository-root CMake project focused on orchestration: it builds a runnable local Ollama payload by delegating llama.cpp work to the llama/server CMake project and building the Go binary into a matching layout.

具体地,local.cmake 做了三件事:

  1. 拉取/复用第三方源码:llama.cpp 的固定版本记录在 LLAMA_CPP_VERSION 文件中,默认通过 ExternalProject_Add 浅克隆(GIT_SHALLOW TRUE),并应用 llama/compat 下的兼容性补丁(见 cmake/apply-git-patches.cmakellama/compat)。MLX / MLX-C 的版本分别记录在 MLX_VERSIONMLX_C_VERSION
  2. 通过 ExternalProject 构建各变体:每个后端(local CPU、cuda_v12、vulkan 等)都是一个独立的 ollama-llama-server-<backend> 外部项目,配置命令指向 llama/server 子工程并使用对应的 CMake preset;MLX 后端则配置 cmake/mlx 子工程。所有产物最终统一安装到 ${CMAKE_BINARY_DIR}/lib/ollama(根 CMakeLists.txt 中 OLLAMA_BUILD_DIR 的定义)。
  3. 构建 Go 主二进制ollama-go 目标以 CGO_ENABLED=1 执行 go build -trimpath,并通过 -ldflags 注入版本号:
-X=github.com/ollama/ollama/version.Version=${OLLAMA_VERSION}
-X=github.com/ollama/ollama/server.mode=release

版本号来自 OLLAMA_VERSION 缓存变量(默认 0.0.0),输出路径可用 OLLAMA_GO_OUTPUT 覆盖,默认为仓库根目录的 ollama(Windows 为 ollama.exe)。

3.2 选择 GPU 后端:OLLAMA_LLAMA_BACKENDS

除 macOS arm64 外的平台,需要显式选择 GPU 后端:

cmake -B build . -DOLLAMA_LLAMA_BACKENDS="cuda_v13;vulkan"
cmake --build build --parallel 8

OLLAMA_LLAMA_BACKENDS 是一个以分号分隔的缓存字符串变量,定义于 cmake/local.cmake。文档列出的合法取值为:cuda_v12cuda_v13rocm_v7_1rocm_v7_2vulkancuda_jetpack5cuda_jetpack6。未知取值会直接触发 FATAL_ERROR

每个后端在 llama/server/CMakePresets.json 中都有对应的 preset,可以从中读出各后端真正的构建配置:

后端 关键缓存变量 预置架构
cuda_v12 GGML_CUDA=ONOLLAMA_RUNNER_DIR=cuda_v12 Linux:50-virtual;...;90a;100;120
cuda_v13 GGML_CUDA=ONOLLAMA_RUNNER_DIR=cuda_v13 Linux:75-virtual;...;121-virtual(含 Blackwell)
rocm_v7_1 GGML_HIP=ONAMDGPU_TARGETS=gfx1030;...;gfx1201 仅 Windows(代码中显式校验,非 Windows 报 FATAL_ERROR)
rocm_v7_2 GGML_HIP=ON 仅 Linux,覆盖 gfx908:xnack-gfx1201
vulkan GGML_VULKAN=ON 默认(可自定义 VULKAN_SDK
cuda_jetpack5/6 GGML_CUDA=ON Jetson 架构 72;87 / 87

从源码结构看,ROCm 7.1 与 7.2 目前共享同一套构建参数(GGML_HIP=ONCMAKE_HIP_PLATFORM=amd),后端名带版本号只是为了将来可以并列安装不同 ROCm 负载而不动超级构建接口(见 cmake/local.cmake 的注释)。

CPU 默认构建的参数也值得注意:非 macOS arm64 平台使用 GGML_BACKEND_DL=ON(后端以动态库形式加载)加 GGML_CPU_ALL_VARIANTS=ON(编译多种 CPU 指令集变体),Windows 额外开启 GGML_OPENMP;而 macOS arm64 是静态链接且 GGML_METAL=ONGGML_METAL_EMBED_LIBRARY=ON(见 cmake/local.cmakellama/server/CMakePresets.jsondarwin preset)。

3.3 用标准 CMake 变量裁剪 GPU 架构

为本地硬件缩小编译范围,直接使用标准 CMake 架构变量即可:

# CUDA
cmake -B build . -DOLLAMA_LLAMA_BACKENDS=cuda_v13 -DCMAKE_CUDA_ARCHITECTURES=native

# ROCm / HIP
cmake -B build . -DOLLAMA_LLAMA_BACKENDS=rocm_v7_2 -DCMAKE_HIP_ARCHITECTURES=gfx1100

local.cmake 中的 preset 选择逻辑印证了这一机制:一旦检测到 CMAKE_CUDA_ARCHITECTURES(或 ROCm 的 AMDGPU_TARGETS/CMAKE_HIP_ARCHITECTURES)被设置,就会自动从平台默认 preset 切换到对应的 *_user_arch preset(cmake/local.cmake),把架构列表完全交给用户。

3.4 透传 GGML_* 构建选项

配置阶段设置的任何 GGML_* 值都会透传给 llama-server 子构建——local.cmake 通过 ollama_collect_cache_args_with_prefix("GGML_") 收集所有以 GGML_(以及 LLAMA_)开头的缓存变量并逐一转发为 -D 参数(cmake/local.cmake)。例如本地调试时关闭 CUDA flash attention 内核:

cmake -B build . -DOLLAMA_LLAMA_BACKENDS=cuda_v12 -DGGML_CUDA_FA=OFF

MLX 子构建同理会透传所有 MLX_* 前缀的缓存变量,并额外转发 BLAS_INCLUDE_DIRSCUDAToolkit_ROOTCUDNN_ROOT_DIRCMAKE_PREFIX_PATH 等一组与 CUDA/cuDNN/OpenBLAS 定位相关的变量(cmake/local.cmake)。

另外,OLLAMA_BUILD_PARALLEL 缓存变量可固定嵌套原生构建的并行度(空则使用生成器默认值),适合调试时限制并发。

四、平台特定说明

4.1 macOS(Apple Silicon)

MLX Metal 后端需要 Metal 工具链:先安装 Xcode,然后执行:

xcodebuild -downloadComponent MetalToolchain

这一步并非只是文档建议:local.cmake 中的 ollama_check_metal_toolchain 函数会用 xcrun 预编译一段 Metal 源码来实测工具链可用性,失败即 FATAL_ERROR 并给出同样的安装指引(cmake/local.cmake)。

此外,macOS arm64 上 OLLAMA_MLX_BACKENDS 有自动默认值:系统主版本与 SDK 主版本均 ≥ 26.2 时默认 metal_v4,否则回退 metal_v3cmake/local.cmake)。

4.2 Windows

额外前置条件:

  • Visual Studio 2022(含 Native Desktop 工作负载)
  • (可选)AMD GPU:ROCm
  • (可选)NVIDIA GPU:CUDA SDK
  • (可选)Vulkan GPU:Vulkan SDK,对 AMD/Intel GPU 有用
  • (可选)MLX 引擎:CUDA 13+ SDK 与 cuDNN 9+

使用 Ninja 时,需要从 Developer PowerShell/Command Prompt 或其他可访问 Visual Studio 编译器的 shell 中运行 CMake。构建 Vulkan 时还需设置 VULKAN_SDK 环境变量:

# PowerShell
$env:VULKAN_SDK="C:\VulkanSDK\<version>"
:: CMD
set VULKAN_SDK=C:\VulkanSDK\<version>

一个 Windows 特有的实现细节:Vulkan 构建目录被特意缩短为 build/ls-vk,注释说明“Vulkan shader 生成器的目录嵌套深度足以触及 Windows MAX_PATH”限制(cmake/local.cmake)。另外在 Visual Studio 生成器下,MSBuild 的 CUDA 集成会忽略 -DCUDAToolkit_ROOT 来选择 nvcc,因此代码会自动改用 -T cuda=<toolkit_root> 生成器参数来指定 CUDA 工具链,并优先使用用户显式设置的 CUDAToolkit_ROOT,否则通过 CUDA_PATH_V<major>_<minor> 环境变量自动发现(cmake/local.cmakecmake/local.cmake)。

4.3 Windows (ARM)

当前 Windows ARM 不支持任何附加加速库(仅 CPU)。

4.4 Linux

额外前置条件(均可选):

  • AMD GPU:ROCm
  • NVIDIA GPU:CUDA SDK
  • Vulkan GPU:Vulkan SDK,或经包管理器安装:sudo apt install vulkan-sdk(Ubuntu/Debian)或 sudo dnf install vulkan-sdk(Fedora/CentOS)
  • MLX 引擎:CUDA 13+ SDK、cuDNN 9+,以及 OpenBLAS/LAPACK:sudo apt install libopenblas-dev liblapack-dev liblapacke-dev(Ubuntu/Debian)

重要(原文档 IMPORTANT):运行 CMake 之前,务必确保所有前置工具链已加入 PATH

五、MLX 引擎(可选)

MLX 引擎用于运行基于 safetensor 的模型。macOS arm64 上 MLX 默认启用;其他平台通过 OLLAMA_MLX_BACKENDS 选择后端,合法值为 cuda_v13metal_v3metal_v4(缓存变量文档字符串,见 cmake/local.cmake)。

5.1 CUDA 后端

需要 CUDA 13+ 与 cuDNN 9+:

cmake -B build . -DOLLAMA_MLX_BACKENDS=cuda_v13
cmake --build build --parallel 8

MLX CUDA 构建会走 cmake/mlx 子工程,preset 选择逻辑与 llama 侧一致:设置了 MLX_CUDA_ARCHITECTURESCMAKE_CUDA_ARCHITECTURES 时使用 mlx_cuda_v13_user_arch,否则按 Windows/Linux 选择平台 preset(cmake/local.cmake)。产物安装到 build/lib/ollama/mlx_cuda_v13RUNNER_DIR 参数)。

5.2 使用本地 MLX 源码覆盖

要针对本地 checkout 的 MLX / MLX-C 构建(开发场景常用),在运行 CMake 前设置环境变量:

export OLLAMA_MLX_SOURCE=/path/to/mlx
export OLLAMA_MLX_C_SOURCE=/path/to/mlx-c

macOS arm64 示例:

OLLAMA_MLX_SOURCE=../mlx OLLAMA_MLX_C_SOURCE=../mlx-c cmake -B build .
cmake --build build --parallel 8

CUDA 示例(PowerShell):

$env:OLLAMA_MLX_SOURCE="../mlx"
$env:OLLAMA_MLX_C_SOURCE="../mlx-c"
cmake -B build . -DOLLAMA_MLX_BACKENDS=cuda_v13
cmake --build build --parallel 8

从源码结构看,OLLAMA_MLX_SOURCE/OLLAMA_MLX_C_SOURCE 环境变量(以及 FETCHCONTENT_SOURCE_DIR_MLX/FETCHCONTENT_SOURCE_DIR_MLX-C)会被 local.cmake 读取,替代默认的 git 克隆;MLX-C 头文件还会通过 cmake/vendor-mlx-c-headers.cmake 同步到 x/mlxrunner/mlx/include/mlx/c,因为所有 MLX 后端变体共享源树中的这份 vendored 头文件。若本地存在 Go 工具链且非交叉编译,ollama-mlx-generate-wrappers 目标还会执行 go generate ./x/... 重新生成 CGO 包装代码(cmake/local.cmakecmake/local.cmake)。

六、Docker 构建

默认构建:

docker build .

ROCm 变体:

docker build --build-arg FLAVOR=rocm .

Dockerfile 开头即以 ARG FLAVOR=${TARGETARCH} 作为构建入口,并按架构提供 ROCm 基础镜像(rocm/dev-almalinux-8:7.2.1-complete)等;文件顶部还预留了 local-mlx / local-mlx-c 两个默认空的 build stage,注释说明可通过 --build-context 传入本地 MLX 源码覆盖,与本地构建的 OLLAMA_MLX_SOURCE 机制呼应。

七、运行测试

go test ./...

仓库中各包均有配套 _test.go 文件;涉及 GPU 库路径解析的逻辑可在 discover/llama_server_test.go 等测试中看到,例如断言 load_backend: loaded CUDA backend from /lib/ollama/cuda_v12/libggml-cuda.so 这类日志能被正确解析为对应的 lib/ollama/cuda_v12 目录。

八、库检测机制:Ollama 从哪里找原生负载

文档最后一节说明了 Ollama 查找原生辅助二进制与加速库的目录优先级,这部分在源码中有完整对应实现:

  • ../lib/ollamaollama 位于 bin/ 下的标准安装布局
  • ./lib/ollama:Windows 发布风格负载与本地 dist 输出
  • .:macOS 发布产物中与 ollama 同目录放置辅助程序
  • build/lib/ollamadist/<platform>/lib/ollama:本地开发构建

如果找不到这些库,Ollama 将不带任何加速库运行(即纯 CPU 模式)。

源码印证:

  • ml/path.go 中的 LibOllamaPath 包级变量在进程启动时按平台组装候选列表(macOS 额外包含“与 ollama 同目录”一项),并注释说明“GPU 专用库位于 cuda_v12rocm_v7_2vulkanmlx_cuda_v13 等后端子目录中”;
  • llm/llama_binary.go 中的 FindLlamaCppBinary 按“可执行文件所在目录 → 工作目录 → build/llama-server-*/bin 构建输出”的顺序生成候选路径并逐个 os.Stat,找不到时返回完整检查列表便于排错。

这也解释了为什么本地 cmake 构建后直接 ./ollama serve 就能工作:CMake 把原生负载输出到 build/lib/ollama(相对工作目录),恰好命中候选列表中的开发布局条目。

总结

Ollama 的开发构建体系可以概括为“一个编排入口、两类原生引擎、一套统一负载目录”:

  1. 编排入口:根 CMakeLists.txt + cmake/local.cmake,通过 ExternalProject 把 llama.cpp(llama/server 子工程 + CMakePresets)与 MLX(cmake/mlx 子工程)的每次变体构建编排为独立外部项目,并自动构建 Go 主二进制、收集 Go 依赖许可证(GO_LICENSE);
  2. 两类原生引擎:llama.cpp(ggml 后端:CPU/CUDA/ROCm/HIP/Vulkan/Metal)与 MLX(safetensor 模型),由 OLLAMA_LLAMA_BACKENDSOLLAMA_MLX_BACKENDS 两个分号分隔变量分别控制;
  3. 统一负载目录:一切产物收敛到 build/lib/ollama/<runner_dir>/,运行时由 ml/path.gollm/llama_binary.go 的候选路径搜索机制按平台布局解析。

常用命令速查:

目的 命令
纯 Go 迭代 go run . serve
默认本地构建 cmake -B build . && cmake --build build --parallel 8
指定 GPU 后端 cmake -B build . -DOLLAMA_LLAMA_BACKENDS="cuda_v13;vulkan"
本地架构裁剪 追加 -DCMAKE_CUDA_ARCHITECTURES=native-DCMAKE_HIP_ARCHITECTURES=gfx1100
MLX CUDA 引擎 cmake -B build . -DOLLAMA_MLX_BACKENDS=cuda_v13
标准前缀安装 cmake --install build --prefix /path/to/install
运行测试 go test ./...
排障:清理 CGO 缓存 go clean -cache
登录后查看全文
热门项目推荐
相关项目推荐