kitty 源码构建完全指南:dev.sh 构建系统、依赖管理、调试构建与打包实践
本文基于 kitty 官方文档 docs/build.rst 编写,系统讲解从源码构建 kitty 终端模拟器的完整流程:通过 ./dev.sh build 一键完成依赖下载与编译、理解构建系统背后的工作原理、掌握 debug/sanitize 构建参数的用法、了解 Linux/macOS 系统级依赖清单,以及面向发行版打包者的 linux-package 打包方案与交叉编译流程。读完本文,你将能够独立完成 kitty 的源码构建、长期维护构建环境,并为其制作 Linux/macOS 软件包。
从源码运行:一条命令完成构建
kitty 被设计为可以直接从源码目录运行(designed to run from source),目的是方便二次开发与修改。在准备一个 C 编译器和 Go 编译器(Linux 上还需要 X11 开发库)之后,官方构建流程只有两条命令:
git clone https://github.com/kovidgoyal/kovidgoyal/kitty.git && cd kitty
./dev.sh build
构建完成后,直接运行 kitty/launcher/kitty 即可启动 kitty。后续如果修改了 kitty 的代码,只需重新执行 ./dev.sh build 即可带上你的改动重新构建。
提示:如果你只是想体验 kitty 的最新改动而非参与开发,无需从源码构建,安装官方 nightly 构建版即可。
构建系统剖析:dev.sh 背后的自动化
"一条命令魔法般地构建完成"并非黑盒,仓库中的构建脚本链条清晰可查:
-
dev.sh 只有一行实质代码:
exec go run bypy/devenv.go "$@"。即./dev.sh的所有子命令都交给 Go 编写的 bypy/devenv.go 处理。 -
bypy/devenv.go 的
build子命令(见build()函数,L389-L410)做了四件事:- 如果
dependencies目录不存在,先自动调用dependencies()下载依赖——这就是"魔法"的来源:./dev.sh build会自动补齐依赖,无需单独执行./dev.sh deps; - 设置
DEVELOP_ROOT环境变量,并把预编译依赖自带的slangc(shader 编译器)路径写入SLANGC; - 把
PKG_CONFIG_PATH指向前者,使 pkg-config 优先找到预编译的依赖包; - 最后用预编译的 Python 执行
python setup.py develop <你的参数>,即真正进入 setup.py 的编译流程,成功后打印Build successful. Run kitty as: kitty/launcher/kitty。
- 如果
-
依赖下载机制:
dependencies()函数(L251-L356)从 CI 工作流脚本 .github/workflows/ci.py 中正则提取BUNDLE_URL(当前为https://download.calibre-ebook.com/ci/kitty/{platform}-64.tar.xz),按平台(linux/macos)与架构(amd64/arm64)下载预编译依赖包,解压到dependencies/<os>-<arch>/目录;下载采用 ETag 缓存(cached_download(),L160-L200),未变更时直接复用本地文件。此外还会下载 Nerd Font 的SymbolsNerdFontMono-Regular.ttf放入fonts/目录,这正是文档"构建时依赖"一节中提到的字体文件。 -
为什么能"从源码运行":kitty 的 C 扩展
kitty/data-types.c(L1007-L1010)在编译期通过-DDEVELOP_ROOT="..."宏把源码目录绝对路径嵌入二进制(该值由bypy/devenv.go在 L395 注入)。这解释了官方文档中的一个重要注意事项:构建产物默认假设源码目录不变——如果你移动或重命名了构建目录,需要执行make clean && ./dev.sh build重新构建。 -
运行时加载源码:kitty/constants.py L44-L47 会读取
fast_data_types.DEVELOP_ROOT,非空时优先使用该路径下的slangc与源码资源——这是"从源码运行"的另一环。
长期从源码运行的注意事项
官方文档特别列出了长期以源码方式运行 kitty 时需要留意的三点,均可在源码中得到印证:
- 定期刷新依赖:执行
./dev.sh deps重新下载依赖。从 bypy/devenv.go 的dependencies()实现看,该命令每次会os.RemoveAll清空dependencies/<os>-<arch>/目录再重新解压,并删除包内自带的libfontconfig.so以便使用发行版自己的 fontconfig 配置目录(L329-L331); - 目录不可移动:如上所述,构建产物内嵌了首次执行
./dev.sh build时的目录路径,移动/重命名目录后需make clean && ./dev.sh build; - 加入 PATH:建议在 PATH 中的某个目录为
kitty与kitten二进制创建符号链接,方便日常启动。
macOS 专属:kitty.app
在 macOS 上还可以用 kitty/launcher/kitty.app 以应用形式运行 kitty。但要注意这是未经签名的 kitty.app,部分功能(如系统通知)会被 Apple 的签名策略阻止。若确需这些功能,可用自签名证书对构建出的 kitty.app 进行 codesign 签名后使用。
调试构建:debug 与 sanitizer
文档提供的三种构建变体如下:
# 带调试符号构建
./dev.sh build --debug
# 带 ASan/UBSan sanitizer 与调试符号构建
./dev.sh build --debug --sanitize
# 查看构建脚本支持的全部选项
./dev.sh build -h
这些参数最终透传给 setup.py develop。查看 setup.py 的 option_parser()(L2244-L2381),与日常构建最相关的选项包括:
| 选项 | 默认值 | 作用 |
|---|---|---|
--debug |
关 | 以调试符号构建扩展模块 |
--sanitize |
关 | 开启 AddressSanitizer + UndefinedBehaviorSanitizer 以检测内存访问错误与未定义行为(性能开销大) |
-v/--verbose |
0 | 输出更详细构建日志 |
--full |
关 | 全量重建,忽略增量编译缓存 |
--profile |
关 | 添加性能剖析所需的编译选项 |
--prefix |
./linux-package |
打包时安装的暂存目录(staging area) |
--skip-code-generation |
关 | 跳过生成 *_generated.* 文件,用于两阶段交叉编译 |
--clean-for-cross-compile |
关 | 交叉编译场景下保留生成的 Go 源码不删除 |
--extra-include-dirs/-I、--extra-library-dirs/-L |
空 | 追加头文件/库搜索路径 |
--ignore-compiler-warnings |
关 | 忽略编译器警告(默认 -Werror,警告即报错) |
--disable-link-time-optimization |
LTO 开 | 关闭链接时优化(也可用环境变量 KITTY_NO_LTO 控制) |
--vcs-rev |
自动读取 .git | 指定嵌入二进制的版本修订号 |
从 init_env()(L595-L749)可以看到参数如何真正影响编译:
- debug 构建:优化级别从
-O3切换为-g3 -Og(编译器 ≥ 5.0 时),并额外追加-DKITTY_DEBUG_BUILD与-fno-omit-frame-pointer,保证调试器能拿到完整符号与栈帧; - sanitize 构建:追加
-fsanitize=address,undefined -fno-omit-frame-pointer,同时关闭 native 优化与 LTO(两者与 sanitizer 不兼容); - 发布构建:默认开启
-O3、-flto(链接时优化)、-fstack-protector-strong、-D_FORTIFY_SOURCE=2,x86 平台还会加-march=native -mtune=native及-fcf-protection=full控制流保护。
--extra-logging=event-loop(对应 Makefile 的 debug-event-loop 目标)可用于在构建中开启事件循环的额外日志,便于排查渲染/事件问题。
系统级依赖:何时需要手动安装
需要强调的适用前提:上述依赖清单只在你选择链接系统库(即不通过 dev.sh 的预编译依赖、而直接用 make/setup.py 构建)时才需要手动安装。使用 ./dev.sh build 时,主要依赖均已随预编译包自动就位,Linux 上真正必需的系统库只剩 X11 与 DBUS。
运行期依赖
| 依赖 | 版本要求/说明 |
|---|---|
| python | 版本下限由 pyproject.toml 的 requires-python 约束,setup.py 启动时会校验(L31-L45) |
| harfbuzz | >= 2.2.0(setup.py 实际用 pkg-config 检查,见 at_least_version 调用) |
| zlib | — |
| libpng | — |
| liblcms2 | — |
| libxxhash | — |
| openssl | — |
| shader-slang | 仅使用自定义 shader 时需要 |
| pixman / cairo / freetype / fontconfig / libcanberra | macOS 上不需要 |
| libsystemd | 可选,非 systemd 系统不需要 |
| ImageMagick | 可选,终端内显示不常见图片格式时需要 |
构建期依赖
gcc或clang;simde(SIMD 移植层);shader-slang;go(>=_build_go_version,当前 go.mod 声明go 1.26.0/toolchain go1.26.6,该文件同时列出了构建期使用的 Go 包);pkg-config;- Nerd Font Mono 字体:系统已安装,或放置在
fonts/SymbolsNerdFontMono-Regular.ttf(使用dev.sh时会自动下载到此路径); - Linux 上可能还需:
liblcms2-dev、libfontconfig-dev、libssl-dev、libpython3-dev、libxxhash-dev、libsimde-dev、libcairo2-dev; - X11 开发库:
libdbus-1-dev、libxcursor-dev、libxrandr-dev、libxi-dev、libxinerama-dev、libgl1-mesa-dev、libxkbcommon-x11-dev、libfontconfig-dev、libx11-xcb-dev。
kitty 仓库自带的 Nix 环境 shell.nix 恰好是上述清单的可执行版本:mkShell 的 buildInputs 包含 harfbuzz、lcms2、xxHash、simde、go、shader-slang,Linux 分支另含 fontconfig、libcanberra、X11 系列、wayland、openssl、dbus、cairo 等,并在 shellHook 中为 Linux 设置 KITTY_EGL_LIBRARY、KITTY_CANBERRA_LIBRARY 等库路径、为 macOS 设置 KITTY_NO_LTO 并手动复制 Nerd 字体到 fonts/。
用 Nix 构建并运行
在 NixOS 或任何安装了 Nix 包管理器的 Linux/macOS 系统上:
nix-shell # 自动拉取全部构建依赖并注入 shell
nix-shell --pure # 排除全局安装包等外部环境影响
进入 Nix shell 后,按前文对应平台的说明执行 make 或 make app 即可。
本地构建文档
# 生成可本地浏览的文档
./dev.sh deps -for-docs && ./dev.sh docs
# 开发文档:本地服务器 + 实时热重载
./dev.sh deps -for-docs && ./dev.sh docs -live-reload
从源码看其实现:bypy/devenv.go 的 dependencies_for_docs()(L219-L249)先下载 get-pip.py,再用预编译 Python 执行 pip install -r docs/requirements.txt;docs/requirements.txt 包含 sphinx、furo、sphinx-copybutton、sphinxext-opengraph、sphinx-design、sphinx-autobuild、matplotlib。docs 子命令(L412-L439)则调用 make docs SPHINXBUILD=... SPHINXAUTOBUILD=...;-live-reload 切换为 docs/Makefile 中的 develop-docs 目标,使用 sphinx-autobuild 监视 kitty/ 与 kittens/ 源码目录变更并热重载。根 Makefile 还保留了传统入口:make man、make html、make dirhtml 等直接代理到 docs 目录的 Sphinx 构建。
面向 Linux/macOS 打包者的说明
kitty 的发布源码以 tarball 形式提供于 GitHub Releases 页面。由于 kitty 虽使用 Python 但不是传统 Python 包,不应安装进 site-packages,正确的打包方式是:
make linux-package
该目标(Makefile L38-L40)会先 rm -rf linux-package 再运行 python3 setup.py linux-package,把所有文件安装到 linux-package 暂存目录:
- 可执行文件:
linux-package/bin/kitty; - 运行所需文件:
linux-package/lib/kitty; - terminfo:
linux-package/share/terminfo。
把这三个目录内容拷入 /usr 即完成安装;可用 --prefix 参数指定其他暂存目录。
官方建议将 kitty 拆分为三个软件包,以便用户可以在只 ssh 登录的服务器上仅安装 terminfo 与 shell 集成脚本:
kitty-terminfo:仅安装 terminfo 文件;kitty-shell-integration:安装 shell 集成脚本(即源码中 shell-integration/ 目录内容),通常放到/usr/share/kitty/shell-integration;kitty:安装主程序。
硬性约束:安装 kitty 主包时,shell 集成脚本必须同时存在于 lib/kitty/shell-integration,因为 kitty 程序在运行时预期从该位置读取它们。
额外构建依赖:编译 terminfo 需要 tic(通常随 ncurses 开发包提供);若从 git 检出(而非发布 tarball)构建 linux-package,还需按 docs/requirements.txt 安装文档依赖(最简方式:python -m pip install -r docs/requirements.txt)。以上规则同样适用于 Homebrew、MacPorts 等 macOS 打包场景。
交叉编译
官方立场:交叉编译既不受官方支持也不推荐——因为交叉编译出的构建无法运行测试套件。但仓库提供了一定程度的支持,流程为两步:
# 第一阶段:构建出已生成代码(生成的 Go/C 源文件保留)
make prepare-for-cross-compile
对应 Makefile L66-L67:先 clean all,再执行 python3 setup.py clean --clean-for-cross-compile(该选项的作用正是保留生成的 Go 源文件,见 setup.py 参数说明)。
# 配置好交叉编译环境(CC、CFLAGS、PATH 等)后:
make cross-compile
对应 L69-L70:python3 setup.py linux-package --skip-code-generation,即跳过代码生成阶段、直接链接交叉目标,产物同样落在 linux-package 目录。
小结:构建流程速查
| 场景 | 命令 |
|---|---|
| 首次/日常源码构建 | ./dev.sh build |
| 刷新预编译依赖 | ./dev.sh deps |
| 调试构建 | ./dev.sh build --debug |
| sanitizer 构建 | ./dev.sh build --debug --sanitize |
| 本地文档(热重载) | ./dev.sh deps -for-docs && ./dev.sh docs -live-reload |
| Nix 环境构建 | nix-shell && make |
| 制作软件包 | make linux-package |
| 交叉编译 | make prepare-for-cross-compile → 配置环境 → make cross-compile |
核心结论:kitty 的构建体系围绕"预编译依赖 + 源码直跑"设计,./dev.sh build 之下的 bypy/devenv.go 负责依赖自动化,setup.py 负责编译细节(严格告警、LTO、SIMD 优化、架构探测);理解 DEVELOP_ROOT 这一内嵌路径宏,是理解其"从源码运行"特性与目录不可移动约束的关键。
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