libghostty 与 C API:把终端核心变成库
libghostty、libghostty-vt、C ABI、WASM 和嵌入约束
libghostty 与 C API:把终端核心变成库
Ghostty 的库化不是把 GUI 可执行文件改成 shared library。项目在构建图上区分完整 libghostty、更窄的 libghostty-vt、benchmark API、config API 和 WASM 入口,使不同宿主只链接自己需要的部分。
两种库
libghostty-vt
src/lib_vt.zig 导出 Page、PageList、Screen、ScreenSet、Terminal、TerminalStream 等 VT 核心类型。它不要求完整窗口系统,目标可以是 macOS、Linux、Windows 甚至 wasm32-freestanding。适合做终端解析、协议测试、Web 终端和其他 emulator 的底层。
libghostty
更完整的库还包括 Surface、renderer、font、runtime callbacks 和 app/surface C API。源码注释也很诚实:当前 C API 主要服务 macOS 嵌入,未来才可能成为通用 embedding API。阅读 API 时要区分“当前被 GhosttyKit 使用”和“设计上理论可被任何宿主使用”。
C ABI 的装配方式
src/main_c.zig 在 comptime 阶段强制引用 config C API、embedded runtime C API、benchmark API 和平台需要的导出,确保链接器不会把只通过反射/类型引用的函数裁掉。顶层导出包括:
ghostty_init:初始化全局状态;ghostty_cli_try_action:运行 CLI action;ghostty_info:版本与 build mode;ghostty_translate:语言翻译;ghostty_string_free:释放 core 分配的字符串;- config/app/surface 的生命周期、事件和查询函数。
这是一条重要的 ABI 纪律:C 侧只能看到稳定布局的 extern struct、明确 ownership 的字符串和函数;Zig 内部的 allocator、union 细节不能直接泄露。
字符串 ownership
ghostty_string_s 同时记录 pointer、length、是否有 sentinel。ghostty_string_free 根据 sentinel 选择正确的 slice,再用 Ghostty global allocator 释放。Swift wrapper 不能随便 free(),而要调用对应的 API;否则分配器或零结尾约束可能不匹配。
生命周期与线程
embedded 宿主需要遵循类似的顺序:
ghostty_init
→ config_new/load/finalize
→ app_new(runtime_config, config)
→ surface_new(...)
→ app_tick / surface events / redraw callbacks
→ surface_free
→ app_freemacOS Swift 的 Surface.deinit 特别说明:若不在主线程,要把 ghostty_surface_free 重新投递到 MainActor。这个细节体现了 API 并不是“任意线程可调用”;宿主必须把 core 的生命周期和平台 UI 线程规则一起实现。
WASM 入口
src/config/Wasm.zig、src/os/wasm 和 WebGL/font web canvas 相关模块说明项目把“可移植终端语义”和“桌面 GUI”分开了。WASM 目标通常只需要配置、VT parser、字体/渲染的 web backend,不应假设 POSIX PTY 存在。
适合嵌入的边界
如果要在另一个应用里嵌入 Ghostty,优先选择:
- 只要 parser/state:使用
libghostty-vt; - 要完整 terminal surface:使用
libghostty的 embedded runtime contract; - 自己掌控窗口和事件:实现 userdata + callback + tick + redraw;
- 不要直接依赖
src/的内部 Zig 类型作为 ABI。
现实的限制
C API 的存在不等于 API 已经稳定。README 明确指出 libghostty 仍在演进,API signatures 可能变化;构建脚本也把库、XCFramework、WASM 和完整 app 分成不同 step。二次开发应把版本锁定、C header 生成和回调契约测试纳入自己的构建。