llama.cpp 发布工程实践:语义化版本、release 工作流与分发渠道全解析
llama.cpp 的版本管理遵循语义化版本(Semantic Versioning, MAJOR.MINOR.PATCH),发布流程由根 CMakeLists.txt 中的版本变量、.github/workflows/make-release.yml 手动工作流以及一套预检脚本共同构成。读完本篇,你能掌握 llama.cpp 完整的版本升级规则、发布前置校验逻辑(分支归属、3 天时效、上游 ggml 一致性比对)、nightly 构建机制,以及预编译二进制、包管理器、源码编译三类分发渠道的工作原理。
语义化版本规则与版本号的唯一事实来源
根据 docs/release.md,llama.cpp 的版本变更遵循如下映射规则:
| 变更类型 | 版本组件 |
|---|---|
公共 C API(include/llama.h)的破坏性变更 |
MAJOR |
| 向后兼容的功能、新模型支持或 API 新增 | MINOR |
| 不涉及 API 变更的缺陷修复 | PATCH |
版本号集中定义在根 CMakeLists.txt 顶部的三个变量中(当前仓库快照为 0.3.0):
# CMakeLists.txt(第 5-21 行)
### llama.cpp version
set(LLAMA_VERSION_MAJOR 0)
set(LLAMA_VERSION_MINOR 3)
set(LLAMA_VERSION_PATCH 0)
set(LLAMA_VERSION_BASE "${LLAMA_VERSION_MAJOR}.${LLAMA_VERSION_MINOR}.${LLAMA_VERSION_PATCH}")
# whether this is a development/nightly build
# set this to OFF when making a release from a release tag (vX.Y.Z)
option(LLAMA_BUILD_IS_DEV "llama: dev build" ON)
if (LLAMA_BUILD_IS_DEV)
set(LLAMA_VERSION "${LLAMA_VERSION_BASE}-dev")
else()
set(LLAMA_VERSION "${LLAMA_VERSION_BASE}")
endif()
文档同时强调了一条流程约定:版本号的 bump 应当包含在引入变更的 PR 中,或作为独立 bump 提交在切出 release 之前合入。文档中还留有一个待办事项——为 PR 增加 semver: patch / semver: minor / semver: major 标签,以便在切 release 前识别哪些 PR 需要版本号变更。
-dev 后缀的机制:区分 nightly 与正式构建
LLAMA_BUILD_IS_DEV 默认值为 ON,会给最终版本字符串追加 -dev 后缀,用于标记 nightly/开发构建;从 release tag 构建正式分发包时必须显式传入 -DLLAMA_BUILD_IS_DEV=OFF,才能得到干净的版本字符串(例如 0.3.0 而非 0.3.0-dev)。
这个版本字符串并非只用于打印,它沿着清晰的传播链路进入构建产物与公共 API:
- 库产物版本:src/CMakeLists.txt 中
llama库以VERSION ${LLAMA_VERSION_BASE}、SOVERSION ${LLAMA_VERSION_MAJOR}声明共享库版本号,common与mtmd库(common/CMakeLists.txt、tools/mtmd/CMakeLists.txt)采用同样策略,SOVERSION与MAJOR绑定意味着只有MAJOR变更才会改变主库的 ABI 符号链接版本; - CMake 包与 pkg-config:cmake/llama-config.cmake.in 将
@LLAMA_VERSION@写入下游 CMake 包配置,cmake/llama.pc.in 将其写入 pkg-config 文件的Version:字段,包管理器据此感知版本; - 公共 C API:include/llama.h 声明了
LLAMA_API const char * llama_version(void);,其实现位于 src/llama.cpp:
const char * llama_version(void) {
return LLAMA_VERSION;
}
即运行时打印的版本号与构建时注入的 LLAMA_VERSION 宏完全一致。这也解释了为什么 LLAMA_BUILD_IS_DEV 必须参与正式构建的开关控制:它是唯一区分 x.y.z 与 x.y.z-dev 的闸门。
版本升级:release.sh 的准备流程
仓库提供 scripts/release.sh 作为版本准备的半自动化工具,其用法为:
./scripts/release.sh [major|minor|patch] [--dry-run]
# 示例:升级次版本号
$ ./scripts/release.sh minor
脚本执行前会做三项硬性校验(见脚本内 check_git_status、check_master_branch、check_master_up_to_date 函数):工作区无未提交变更、当前分支必须是 master、本地 master 必须与 origin/master 一致(会执行 git fetch origin master 比对 SHA)。--dry-run 模式则跳过这些校验,只打印将要执行的操作。
校验通过后,脚本依次完成:
- 读取当前版本:从根
CMakeLists.txt中grep出LLAMA_VERSION_MAJOR/MINOR/PATCH三个值; - 计算新版本号:按 semver 规则进位——
major升级时MINOR、PATCH归零,minor升级时PATCH归零,缺省参数按patch处理; - 创建 release candidate 分支:命名为
llama-rc-v<新版本号>(如llama-rc-v0.4.0)并切换过去; - 修改 CMakeLists.txt 并提交:通过兼容 GNU 与 BSD sed 的
sed_inplace原地替换三个set(LLAMA_VERSION_*)语句,提交信息固定为llama.cpp : bump version to <新版本号>。
脚本结束后打印的 Next steps 明确了后续分工:推送 RC 分支、向 master 发起 PR、等待合并且 build-cpu 工作流通过后,再由 make-release 工作流创建 release tag。也就是说,版本号变更走常规 PR 评审流程,tag 创建才由工作流完成——这与文档中"bump 应包含在引入变更的 PR 中"的约定形成互补。
make-release 工作流:tag 即发布
正式发布通过 .github/workflows/make-release.yml 触发,这是一个 workflow_dispatch 手动工作流,暴露两个输入:
| 输入 | 说明 | 默认值 |
|---|---|---|
commit |
要发布的 commit SHA,留空则使用所选分支的 HEAD | 空 |
dry_run |
仅执行校验、不创建 tag | true |
工作流运行在"Run workflow"对话框所选的分支上(默认 master)。当指定了 commit 时,scripts/make-release-checks.sh 会验证该 commit 属于目标分支且不晚于分支 HEAD 的 3 天前,满足条件时发布该 commit 而非分支 HEAD。
发布前的四道校验
make-release-checks.sh 是发布门禁的核心,按顺序执行:
- 推导版本号:同样从根
CMakeLists.txt解析出v<MAJOR>.<MINOR>.<PATCH>(注意此处带v前缀,即 tag 形如v0.3.0); - commit 归属与时效检查:用
git merge-base --is-ancestor确认 commit 在origin/<RELEASE_BRANCH>上,并用提交时间戳差值确认其落后分支 HEAD 不超过3 * 86400秒; - tag 冲突检查:
git ls-remote --tags origin <版本>确认远端不存在同名 tag; - CI 与上游一致性检查:通过 GitHub API 确认该 commit 存在一次
conclusion == success的 release.yml(nightly)运行——"nightly 构建必须先成功才能发布";随后读取 ggml/CMakeLists.txt 中的GGML_VERSION_*(当前为0.22.0),git clone --depth 1 --branch v<GGML_VERSION>拉取上游 ggml 对应 tag,对本地 vendored 的ggml/src、ggml/include与ggml/CMakeLists.txt做diff -rq全量比对,本地 vendored 副本与上游 tag 不一致时中止发布(--dry-run模式下仅记录告警并置checks_passed=false)。
校验通过后,工作流执行(dry_run=false 时):
- 以
github-actions[bot]身份创建附注 tag(git tag -a)并推送远端,例如v0.3.0; - 调用 scripts/make-release-desc.sh 生成发布描述:自动寻找低于当前版本号的最近一个纯 semver tag 作为基准,用
git log --oneline <PREV>..<RELEASE_COMMIT>产出逐 commit 的 changelog,并定位指向同一 commit 的b*系列 nightly tag 以生成对应的 nightly 构建链接; - 创建 GitHub Release 对象(
prerelease: false),并将nightly-tag.txt(内容为对应 nightly tag 名)作为 Release asset 上传,供下游工具链追踪该版本对应的 nightly 构建。
发布描述的写作规范
scripts/make-release-summary.txt 定义了人工撰写 Release 概述的模板,要求基于 make-release-desc.sh 输出的 changelog,按以下章节组织:Overview(1-3 句)、API changes(/include/*、/tools/mtmd/mtmd.h、/tools/server 的变更)、New models(src/models/ 新增模型)、Core changes(/src/*)、Multi-modality changes(/tools/mtmd/)、Server changes(/tools/server/)、UI changes(/tools/ui/)、ggml changes(ggml 版本变更时链接对应上游 release 并摘录其描述)。规范还要求每条 bullet 尽量单行不超过 120 字符、尽量附 PR 链接,且不要重复 ggml 侧已由链接覆盖的内容。
nightly 构建:发布流水线的上游
文档提到"目前只有 nightly/开发构建发布在 GitHub Releases 上",其来源是 .github/workflows/release.yml。该工作流有两条触发路径:master 分支 push(按源码文件类型过滤,且 commit message 含 [no release] 时跳过)以及手动 workflow_dispatch(create_release 输入强制为 true)。构建统一使用:
-DLLAMA_BUILD_EXAMPLES=OFF -DLLAMA_BUILD_TESTS=OFF -DLLAMA_BUILD_TOOLS=ON -DLLAMA_BUILD_SERVER=ON -DGGML_RPC=ON
以 macOS 为例,矩阵包含 arm64(-DGGML_METAL_EMBED_LIBRARY=ON,部署目标 13.3)与 x64(Metal 关闭以规避 runner 无 GPU 导致的间歇性失败)两个构建,均集成 ccache、构建后将 LICENSE 一并打入 build/bin/ 打包产物,并按 get-tag-name action 确定的 b* tag 命名发布。nightly tag 与正式 tag 指向同一 commit 的机制,正是 make-release-desc.sh 能在正式 Release 中链接对应 nightly 构建的基础,也是 make-release-checks.sh 要求"该 commit 必须有成功 nightly 运行"才能放行正式发布的原因——正式发布实质上是"把某个已验证的 nightly commit 固化成 semver tag"。
发布物如何触达用户
文档明确当前分发渠道共三种:
- 预编译二进制:下载基于 release tag 构建的预编译产物(nightly/开发构建直接可用,正式构建从 tag 产出),对应上述 release.yml 矩阵产物;
- 包管理器:直接消费 git tag。tag 是唯一的发布工件——
v<MAJOR>.<MINOR>.<PATCH>形态的附注 tag 推送远端后,下游即可基于该 tag 出包;仓库中还存在如.github/workflows/winget.yml这类面向具体包生态的自动化工作流,以及 docs/docker.md 等面向容器用户的文档; - 源码构建:用户克隆仓库并 checkout 指定 tag 自行编译,此时应确保构建参数携带
-DLLAMA_BUILD_IS_DEV=OFF以获得无-dev后缀的版本字符串,同时可用llama_version()运行时验证。
小结:一条完整的发布链路
把各组件串起来,llama.cpp 的发布链路是:
- 功能/修复 PR 合入时同步 bump
CMakeLists.txt三个版本变量(可借助scripts/release.sh生成 RC 分支与 bump 提交); master每次符合条件的 push 触发 release.yml,产出b*tag 的 nightly 构建并上传 GitHub Releases;- 手动触发 make-release 工作流:
make-release-checks.sh依次验证版本推导、commit 分支归属与 3 天时效、tag 唯一性、nightly CI 成功、vendored ggml 与上游 tag 逐文件一致; - 创建并推送附注 tag(如
v0.3.0),生成 changelog 与 nightly 关联链接,产出 GitHub Release 及nightly-tag.txtasset; - 用户经由预编译二进制、包管理器(直接消费 tag)或源码 checkout 三条渠道获取该版本,
llama_version()返回的最终字符串由LLAMA_BUILD_IS_DEV决定带不带-dev。
整套机制的关键设计在于:版本号单一事实来源(CMake)、tag 即发布、nightly 先行验证、vendored 依赖一致性强制比对,四个环节互为约束,使得任何一个环节的漂移(错误的 bump、未过 CI 的 commit、本地 ggml 魔改)都会在发布前被拦截。
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 StartedRust0623
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