Ollama 开发指南:从零构建 Ollama 二进制与原生推理后端的完整流程
本文基于 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默认强制为Release(CMakeLists.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 做了三件事:
- 拉取/复用第三方源码:llama.cpp 的固定版本记录在 LLAMA_CPP_VERSION 文件中,默认通过
ExternalProject_Add浅克隆(GIT_SHALLOW TRUE),并应用llama/compat下的兼容性补丁(见 cmake/apply-git-patches.cmake 与 llama/compat)。MLX / MLX-C 的版本分别记录在 MLX_VERSION 与 MLX_C_VERSION。 - 通过 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的定义)。 - 构建 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_v12、cuda_v13、rocm_v7_1、rocm_v7_2、vulkan、cuda_jetpack5、cuda_jetpack6。未知取值会直接触发 FATAL_ERROR。
每个后端在 llama/server/CMakePresets.json 中都有对应的 preset,可以从中读出各后端真正的构建配置:
| 后端 | 关键缓存变量 | 预置架构 |
|---|---|---|
cuda_v12 |
GGML_CUDA=ON,OLLAMA_RUNNER_DIR=cuda_v12 |
Linux:50-virtual;...;90a;100;120 |
cuda_v13 |
GGML_CUDA=ON,OLLAMA_RUNNER_DIR=cuda_v13 |
Linux:75-virtual;...;121-virtual(含 Blackwell) |
rocm_v7_1 |
GGML_HIP=ON,AMDGPU_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=ON、CMAKE_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=ON、GGML_METAL_EMBED_LIBRARY=ON(见 cmake/local.cmake 与 llama/server/CMakePresets.json 的 darwin 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_DIRS、CUDAToolkit_ROOT、CUDNN_ROOT_DIR、CMAKE_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_v3(cmake/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.cmake、cmake/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_v13、metal_v3、metal_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_ARCHITECTURES 或 CMAKE_CUDA_ARCHITECTURES 时使用 mlx_cuda_v13_user_arch,否则按 Windows/Linux 选择平台 preset(cmake/local.cmake)。产物安装到 build/lib/ollama/mlx_cuda_v13(RUNNER_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.cmake、cmake/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/ollama:ollama位于bin/下的标准安装布局./lib/ollama:Windows 发布风格负载与本地 dist 输出.:macOS 发布产物中与ollama同目录放置辅助程序build/lib/ollama与dist/<platform>/lib/ollama:本地开发构建
如果找不到这些库,Ollama 将不带任何加速库运行(即纯 CPU 模式)。
源码印证:
- ml/path.go 中的
LibOllamaPath包级变量在进程启动时按平台组装候选列表(macOS 额外包含“与 ollama 同目录”一项),并注释说明“GPU 专用库位于cuda_v12、rocm_v7_2、vulkan、mlx_cuda_v13等后端子目录中”; - llm/llama_binary.go 中的
FindLlamaCppBinary按“可执行文件所在目录 → 工作目录 →build/llama-server-*/bin构建输出”的顺序生成候选路径并逐个os.Stat,找不到时返回完整检查列表便于排错。
这也解释了为什么本地 cmake 构建后直接 ./ollama serve 就能工作:CMake 把原生负载输出到 build/lib/ollama(相对工作目录),恰好命中候选列表中的开发布局条目。
总结
Ollama 的开发构建体系可以概括为“一个编排入口、两类原生引擎、一套统一负载目录”:
- 编排入口:根 CMakeLists.txt + cmake/local.cmake,通过 ExternalProject 把 llama.cpp(llama/server 子工程 + CMakePresets)与 MLX(cmake/mlx 子工程)的每次变体构建编排为独立外部项目,并自动构建 Go 主二进制、收集 Go 依赖许可证(
GO_LICENSE); - 两类原生引擎:llama.cpp(ggml 后端:CPU/CUDA/ROCm/HIP/Vulkan/Metal)与 MLX(safetensor 模型),由
OLLAMA_LLAMA_BACKENDS与OLLAMA_MLX_BACKENDS两个分号分隔变量分别控制; - 统一负载目录:一切产物收敛到
build/lib/ollama/<runner_dir>/,运行时由 ml/path.go 与 llm/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 |
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0624
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00