首页
/ Godot Engine 的 thirdparty 目录:第三方库 Vendor 化、补丁管理与更新流程全解析

Godot Engine 的 thirdparty 目录:第三方库 Vendor 化、补丁管理与更新流程全解析

2026-09-06 00:00:03作者:尤峻淳Whitney

本文以 Godot 仓库中的 thirdparty/README.md 为主体,系统讲解 Godot Engine 如何将近 70 个第三方 C/C++ 库以“源文件级 vendor(vendoring)”方式纳入引擎源码树:每类库的上游版本与许可证登记格式、文件裁剪清单、patches 补丁体系、Godot 私有扩展文件,以及基于 update-sdl.shupdate-metal-cpp.sh 等脚本的半自动升级流程。读完后,你将能够准确读懂任意一个 vendored 库的出处与裁剪依据,并掌握对其中某个库执行版本升级时的标准操作路径。

一、文档定位与格式约定

thirdparty/README.md 是 Godot 仓库内所有 vendored 第三方代码的唯一登记表。文件开头即给出了两条硬性维护约定:

Please keep categories (## level) listed alphabetically and matching their respective folder names. Use two empty lines to separate categories for readability.

即:

  • 每个二级标题(##)必须与 thirdparty/ 下的目录名逐字一致,且按字母序排列;
  • 分类之间用两个空行分隔,保证可读性。

当前仓库中 thirdparty/ 下共有 67 个库目录(加上 README 本身),涵盖渲染(Vulkan、SDL、metal-cpp)、物理(Jolt、VHACD)、图像与压缩(libpng、libwebp、zlib、zstd)、文本(Freetype、HarfBuzz、ICU4C、Graphite)、网络(ENet、wslay、miniupnpc)、字体资源(fonts)等领域,与目录实际内容一一对应。

二、每个库条目的标准结构

除少数聚合类条目外,README 中每个库条目都由四个部分组成。以 thirdparty/sdl/ 为例:

## sdl

- Upstream: https://github.com/libsdl-org/SDL
- Version: 3.2.28 (7f3ae3d57459e59943a4ecfefc8f6277ec6bf540, 2025)
- License: Zlib
- Vendored: hidapi 0.14.0, license BSD-3-Clause

Files extracted from upstream source:
- See `thirdparty/sdl/update-sdl.sh`
  1. Upstream(上游地址):代码的真实来源仓库;
  2. Version(版本 + 完整 commit hash + 年份):注意即使写的是 git,也带精确 commit 与年份,例如 1.2.0 (8e4808736e9c181b971306cc3f05df9e61354004, 2025)(libtheora);
  3. License(许可证):个别库还额外登记了内部再打包的依赖,如 SDL 条目中的 Vendored: hidapi 0.14.0
  4. Files extracted from upstream source(裁剪清单):精确列出从上游拷贝了哪些文件/目录、删掉了什么,这是 vendoring 的“可复现收据”;
  5. Patches(可选):每个补丁文件都附带对应的 Pull Request 编号,说明补丁的来由。

这种登记方式使得任何一位维护者在升级库时都能回答三个问题:这个文件是不是该在的?它来自哪个 commit?本地改动过哪些地方?

三、文件级裁剪:vendor 不是“整库照搬”

Godot 的 vendoring 原则是只拷贝构建所需的最小文件集。README 的裁剪清单体现了这一点,仓库文件也与之严格一致:

  • zlibthirdparty/zlib/):- All .c and .h files, except gz*.c and infback.c。实际目录中确无 gzlib.c/gzclose.c 等 gzip 流接口,也不含 infback.c,仅保留 deflate.cinflate.ccrc32.c 等核心模块;
  • libjpeg-turbothirdparty/libjpeg-turbo/):README 列出一长串被排除的文件(cjpeg.c djpeg.c jpegtran.c tjbench.c ...),即所有命令行工具与基准测试代码,只留解码/编码库本体;
  • embreethirdparty/embree/):README 明确指出被提取的文件列表由 modules/raycast/godot_update_embree.py 脚本声明——“All .cpp files listed in ... 所有该脚本列出的 .cpp、头文件与配置文件”。这说明对于超大库,裁剪规则本身也代码化了,脚本同时负责“从最新 Embree release 拉取相关文件并自动打补丁”;
  • libwebpthirdparty/libwebp/):只取 src/sharpyuv/,并排除 .am.rc.in 等自动化工具文件;
  • harfbuzzthirdparty/harfbuzz/):递归取 src 下所有 .cc/.h/.hh,但显式排除 main.ccharfbuzz*.cc(命令行工具)、hb-gpu*hb-wasm*rust/ 等与 Godot 无关的目标。

与之配合的还有“反向声明”:少数文件是 Godot 自有的,升级时必须保留。README 中此类声明包括:

  • thirdparty/dr_libs/dr_bridge.hdr_bridge.h is a Godot file and should be preserved on updates.
  • thirdparty/vulkan/vk_mem_alloc.cppvk_mem_alloc.cpp is a Godot file and should be preserved on updates.vk_mem_alloc.h 则来自 GPUOpen 的 VulkanMemoryAllocator 3.3.0)
  • thirdparty/mbedtls/godot/:新增的 godot_mbedtls_config.hgodot_psa_config.hgodot_mbedtls_platform.cpp,用于用 Godot 原生 API 实现 mbedTLS 的平台层函数。

四、补丁体系:patches 目录与可追溯的修改

当上游代码不能原样编译、或需要为 Godot 做小改造时,README 要求同时提交一个补丁文件并登记。补丁以 NNNN-描述.patch 命名存放在各库目录的 patches/ 子目录(如 thirdparty/sdl/patches/thirdparty/mbedtls/ 下的 extract_mbedtls_sources.py 流程),且每个条目都注明引入它的 Pull Request。典型例子:

  • sdl:共 9 个补丁,包括 0001-remove-unnecessary-subsystems.patch(裁剪无用子系统)、0005-fix-libudev-dbus.patch0008-fix-linux-joycon-serial-num.patch0009-update-device-blocklist.patch(手柄设备黑名单更新)等;
  • basis_universal:6 个补丁,其中 0001-external-zstd 将 zstd 依赖外置、0002-external-tinyexr0003-remove-tinydds-qoi 去重(改为复用 thirdparty/tinyexr/thirdparty/zstd/ 的 vendored 版本),0006-explicit-includes.patch 统一补全显式头文件包含;
  • clipper2embree0001-disable-exceptions.patch,即全局禁用 C++ 异常以匹配 Godot 的构建约定;
  • libjpeg-turbo0002-disable-16bitlossless.patch0003-remove-bmp-ppm-support.patch 进一步缩小编译面;
  • glslang0002-apple-m1-msaa-fix.patch 针对 Apple M 系列 GPU 的 MSAA 问题修复。

这个体系的价值在于:vendored 代码与上游的差异是可审计、可重放的——git apply patches/xxx.patch 即可重建改动,升级新版本时只需重新验证或重打补丁,而不是面对一堆无法追溯的手工修改。

五、Godot 扩展文件:在上游 API 之上做适配

README 还记录了一类“上游没有、Godot 新增”的文件,它们把通用库接入了引擎自己的对象模型:

  • enetthirdparty/enet/,上游 1.3.18):Added 3 files enet_godot.cpp, enet/enet_godot.h, and enet/enet_godot_ext.h, providing ENet socket implementation using Godot classes, allowing IPv6 and DTLS.。仓库中三个文件确实存在。README 同时给出重要提示:使用系统级 ENet 虽然可行,但功能会被限制为仅 IPv4 且无 DTLS,官方不推荐。从源码结构看,modules/enet/SCsubthirdparty_sources 列表正是编译这些 vendored 源文件(含 Godot 扩展)的构建入口;
  • mbedtlsthirdparty/mbedtls/,4.1.1):除用 thirdparty/mbedtls/extract_mbedtls_sources.py 从 release tarball 提取相关文件外,还从 git 源码更新时需先运行上游的 scripts/make_generated_files.py 等生成脚本——因为 mbedtls 的 git 仓库本身不含全部生成文件;
  • rvo2thirdparty/rvo2/,2D 版在 rvo2_2d/、3D 版在 rvo2_3d/):README 特别声明“几乎每个文件都有 Godot 的改动与重命名”,目的是让 2D/3D 两套 RVO 库 API 兼容并解决冲突,属于“深度二次开发”型 vendor,升级时必须谨慎;
  • grisu2:由 simdjson 的 to_chars.cpp 重命名并略作修改而来(经 0001-godot-changes.patch 固定),用于快速浮点转字符串;
  • misc:单文件库的集合目录(见 thirdparty/misc/),README 为每个文件单独登记上游与许可证,包括 fastlz.{c,h}smaz.{c,h}polypartition.{cpp,h}qoa.{c,h}r128.{c,h}ok_color.hpcg.{cpp,h} 等十余个,个别文件(如 nvapi_minimal.h)注明了“由上游 nvapi.h 删减生成”的修改方式。

六、更新脚本:把升级流程脚本化

对较复杂的库,Godot 提供了可重复执行的升级脚本,README 只登记“脚本 + 版本号”:

SDLthirdparty/sdl/update-sdl.sh)脚本头部即声明 VERSION=3.2.28,与 README 登记版本一致。脚本流程为:

  1. 清空目标目录中的 vendored 源码(rm -rf atomic core events haptic hidapi include io joystick libm loadso sensor stdlib thread timer *.c *.h ...);
  2. curl 下载上游 release-$VERSION.tar.gz 并解压到临时目录;
  3. 只拷贝构建所需的最小文件集——脚本内注释写明 “We aim to copy only the minimum amount of files needed, so we don't need to vendor and compile more source code than necessary.”,例如头文件拷贝时会删除 SDL_{egl,gpu,oldnames,opengl*,test*,vulkan}.h 等 Godot 不用的接口头;
  4. 应用 patches/ 下的补丁序列。

metal-cppthirdparty/metal-cpp/,Apple 官方 26.0):从 Apple 开发者站点下载 ZIP 后运行 update-metal-cpp.sh <zip 路径> 提取并打补丁。

thorvgthirdparty/thorvg/,1.0.3):README 指向 thorvg/update-thorvg.sh,设定版本号后执行。

embreethirdparty/embree/,4.4.0):modules/raycast/godot_update_embree.py 同时定义“取哪些文件”和“打哪些补丁”,是脚本化程度最高的案例。

glad 是另一类:文件不是直接拷贝,而是由上游 Web 生成器生成的(egl.c gl.c glx.cglad/*.h),README 提示通过 glad/egl.hglad/gl.hglad/glx.h 内的 permalinks 可以用新版本重新生成。

七、Vulkan 工具链的版本联动约束

README 的 vulkan 一节(thirdparty/vulkan/,Vulkan-Headers vulkan-sdk-1.4.335.0)给出了明确的同步规则,是全文档中最强的跨条目约束:

Unless there is a specific reason to package a more recent version, please stick to tagged SDK releases. All Vulkan libraries and headers should be kept in sync so: Update Vulkan SDK components / volk / glslang / spirv-headers / spirv-cross / spirv-reflect

即升级 thirdparty/vulkan/ 时必须同步更新六个组件:vulkan、volk、glslang、spirv-headers、spirv-cross、spirv-reflect。仓库当前状态与之吻合:thirdparty/volk/thirdparty/glslang/thirdparty/spirv-headers/thirdparty/spirv-reflect/ 的 README 登记版本均为 vulkan-sdk-1.4.335.0(2025)。其中 glslang 还要求构建后把 CMake 生成的 include/glslang/build_info.h 拷贝为 glslang/build_info.h,并删除 C 接口代码(CInterface/*_c[_\.]* 文件)与 glslang/stub.cppvk_enum_string_helper.h 则取自同版 Vulkan-Utility-Libraries。

八、fonts 与 ICU 数据:资源型 vendor

fontsthirdparty/fonts/)条目登记了 16 组字体资源的出处、精确 commit 与字体许可证(Apache 2.0 / OFL-1.1),并说明:

All fonts are converted from the unhinted .ttf sources using the woff2 tool. Use UI font variant if available, because it has tight vertical metrics and good for UI.

即统一使用 Google woff2 工具从 unhinted TTF 转码,UI 字体优先选 UI 变体以保证垂直度量紧凑。icu4cthirdparty/icu4c/,78.3)则给出了完整的 5 步数据文件重建流程:下载 icu4c-{version}-src.tgzicu4c-{version}-data.zip → 默认选项构建 → 用 ICU_DATA_FILTER_FILE={GODOT_SOURCE}/thirdparty/icu4c/godot_data.json 重新配置 → 清空 data/out 重编数据 → 将 icudt{ICU_VERSION}l.dat 拷贝为 thirdparty/icu4c/icudt_godot.dat。这是“源码 + 生成数据”双重 vendor 的典型。

九、构建系统集成

thirdparty/ 中的源码由各平台/模块构建脚本通过 SCons 引入。例如 platform/linuxbsd/detect.pyenv.Prepend(CPPPATH=["#thirdparty/linuxbsd_headers"])"#thirdparty/linuxbsd_headers/wayland/" 等,将 vendored 的 Linux/BSD 系统头文件(见 thirdparty/linuxbsd_headers/)加入编译搜索路径,使 Wayland 等依赖无需系统安装即可构建;core/io/compression.cpp 直接 #include <thirdparty/misc/fastlz.h>modules/enet/SCsub 则把 #thirdparty/enet/ 下的 C 源文件并入模块编译。从源码结构看,thirdparty 在 SCons 中以 # 前缀的源码根相对路径被统一引用,因此 README 中“目录名与标题一致”的约定也保障了构建脚本路径的可预期性。

十、完整登记表(当前仓库状态)

以下是 thirdparty/README.md 当前登记的全部库及其版本与许可证(按 README 字母序,对应 thirdparty/ 目录名)。这是查阅“某能力依赖哪个库”时的快速索引:

目录(对应 README 小节) 上游项目 版本(登记于当前仓库) 许可证 典型用途
accesskit/ accesskit-c 0.22.3 MIT 无障碍树导出
amd-fsr/ FidelityFX-FSR 1.0.2 MIT FSR 1.0 超分辨率头文件
amd-fsr2/ FidelityFX-FSR2 2.2.1 MIT FSR 2 实现与着色器
angle/ ANGLE (chromium) chromium/5907 BSD-3-Clause EGL/ANGLE 接口头
astcenc/ astc-encoder 5.3.0 Apache 2.0 ASTC 纹理压缩
basis_universal/ basis_universal git (2025) Apache 2.0 BasisU 纹理编码/转码
brotli/ brotli 1.2.0 MIT Brotli 压缩
certs/ ca-bundle (Mozilla) git (2025) MPL 2.0 ca-bundle.crt 系统证书
clipper2/ Clipper2 1.5.4 BSL 1.0 多边形布尔运算(导航网格等)
cvtt/ ConvectionKernels git (2022) MIT BC 压缩纹理转码内核
d3d12ma/ D3D12MemoryAllocator 3.1.0 MIT Windows D3D12 内存分配
directx_headers/ DirectX-Headers main (2025) MIT DXGI/D3D 等纯头文件
doctest/ doctest 2.4.12 MIT 单元测试框架(tests/ 使用)
dr_libs/ dr_libs mp3-0.7.3 PD/Unlicense/MIT-0 dr_mp3.h MP3 解码桥接
embree/ embree 4.4.0 Apache 2.0 光线求交加速结构(raycast 模块)
enet/ enet 1.3.18 MIT 可靠 UDP 网络(Multiplayer)
etcpak/ etcpak 2.0 BSD-3-Clause ETC2/DXT 压缩纹理
fonts/ 多上游(Droid/Inter/Noto/JetBrains…) 各组独立登记 Apache 2.0 / OFL-1.1 引擎内置 UI 字体 woff2
freetype/ freetype 2.14.3 FreeType License 位图字体渲染
gamepadmotionhelpers/ GamepadMotionHelpers git (2023) MIT 手柄陀螺仪死区计算
glad/ glad 2.0.8 CC0 1.0 + Apache 2.0 GL/EGL/GLX 加载器生成代码
glslang/ glslang vulkan-sdk-1.4.335.0 glslang GLSL→SPIR-V 编译
graphite/ graphite (SIL) 1.3.14 MIT HarfBuzz 的 AAT 回退
grisu2/ simdjson to_chars git (2025) Apache/MIT 浮点快速转字符串
harfbuzz/ harfbuzz 14.2.0 MIT 文字 shaping
icu4c/ icu 78.3 Unicode 国际化数据与 uspoof 语言检测
jolt_physics/ JoltPhysics 5.6.0 MIT Jolt 3D 物理
libbacktrace/ libbacktrace git (2022) BSD-3-Clause Windows 调用栈回溯
libjpeg-turbo/ libjpeg-turbo 3.1.3 BSD-3-Clause + IJG JPEG 编解码
libktx/ KTX-Software 4.4.2 Apache 2.0 KTX2 容器与 Basis 转码
libogg/ libogg 1.3.6 BSD-3-Clause Ogg 容器
libpng/ libpng 1.6.58 libpng/zlib PNG 编解码(含 NEON 汇编)
libtheora/ libtheora 1.2.0 BSD-3-Clause Theora 视频解码(MovieWriter)
libvorbis/ libvorbis 1.3.7 BSD-3-Clause Vorbis 音频解码
libwebp/ libwebp 1.6.0 BSD-3-Clause WebP 编解码
linuxbsd_headers/ 各 X11/Wayland/udev 上游 见其内部 README 各异 Linux/BSD 系统头文件
manifold/ manifold 3.3.2 Apache 2.0 CSG 布尔几何(csg 模块)
mbedtls/ mbedtls 4.1.1 Apache 2.0 TLS/DTLS、加密 API
meshoptimizer/ meshoptimizer 1.2 MIT 网格重排/索引优化
metal-cpp/ metal-cpp (Apple) 26.0 Apache 2.0 Metal C++ 绑定(macOS/visionOS)
mingw-std-threads/ mingw-std-threads git (2023) BSD-2-clause MinGW 下 C++11 线程
miniupnpc/ miniupnpc 2.3.3 BSD-3-Clause UPnP NAT 端口映射(upnp 模块)
minizip/ zlib contrib/minizip 1.3.2 zlib Zip 读写(.pck 打包基础)
misc/ 见 README 内逐文件登记 各异 MIT 等 十余个单文件算法库
msdfgen/ msdfgen 1.13 MIT 多尺度距离场字体(text_server_adv)
openxr/ OpenXR-SDK 1.1.60 Apache 2.0 OpenXR 运行时加载器
pcre2/ PCRE2 10.47 BSD-3-Clause 正则表达式(Regex 类)
re-spirv/ re-spirv git (2026) MIT SPIR-V 反汇编
recastnavigation/ recastnavigation 1.6.0 zlib 导航网格烘焙
rvo2/ RVO2 / RVO2-3D git (2021) Apache 2.0 2D/3D 避行(RVO)
smaa/ smaa git (2013) MIT SMAA 抗锯齿纹理
sdl/ SDL 3.2.28(内置 hidapi 0.14.0) Zlib 窗口/输入/音频/游戏手柄(各平台)
smay 见 misc/
spirv-cross/ SPIRV-Cross git (2025) Apache 2.0 SPIR-V → GLSL/Metal
spirv-headers/ SPIRV-Headers vulkan-sdk-1.4.335.0 MIT SPIR-V 头文件
spirv-reflect/ SPIRV-Reflect vulkan-sdk-1.4.335.0 Apache 2.0 SPIR-V 反射
swappy-frame-pacing/ swappy (AOSP 镜像) git (2025) Apache 2.0 Android Vulkan 帧节奏(VRR)
thorvg/ thorvg 1.0.3 MIT SVG 矢量渲染(svg 模块)
tinyexr/ tinyexr 1.0.13 BSD-3-Clause EXR 解码(high_dynamic_range 图像)
ufbx/ ufbx 0.21.3 MIT FBX 解析(fbx 模块)
vhacd/ v-hacd git (2020) BSD-3-Clause 凹体分解(vhacd 模块)
volk/ volk vulkan-sdk-1.4.335.0 MIT Vulkan 函数指针加载器
vulkan/ Vulkan-Headers vulkan-sdk-1.4.335.0 Apache 2.0 Vulkan 头文件 + VMA 3.3.0
wayland/ wayland 1.24.0 MIT wayland.xml 协议描述
wayland-protocols/ wayland-protocols 1.47 MIT xdg-shell/tablet/viewporter 等协议
wslay/ wslay 1.1.1+git MIT WebSocket 帧层(websocket 模块)
xatlas/ xatlas git (2022) MIT UV 展开(xatlas_unwrap 模块)
zlib/ zlib 1.3.2 zlib DEFLATE 压缩
zstd/ zstd 1.5.7 BSD-3-Clause zstd 压缩(与 minizip 1.3.2 同 commit)

注:表中“典型用途”一列为基于仓库中各模块/驱动对相应头文件的引用关系整理(如 modules/enet/SCsubcore/io/compression.cpp 等);版本与许可证均直接取自 thirdparty/README.md 登记。

总结:为什么 Godot 采用这种 vendoring 方式

综合 README 的登记规则与仓库实际结构,可以归纳出 Godot 第三方依赖管理的四条核心实践:

  1. 源码随仓库分发、最小文件集裁剪——保证 clone 即可离线构建,且只编译真正用到的代码(SDL、zlib、libjpeg-turbo 等条目均可验证);
  2. 登记即合同——上游 URL、commit hash、许可证、裁剪清单四要素缺一不可,目录名与 README 标题强绑定,便于交叉核对;
  3. 修改必须补丁化——patches/ 目录 + PR 编号让每个 diff 可追溯、可重放、可随上游版本重新验证;
  4. 升级流程脚本化——update-sdl.shupdate-metal-cpp.shupdate-thorvg.shextract_mbedtls_sources.pygodot_update_embree.py 等把“下载—裁剪—打补丁”固化为可重复步骤,Vulkan 系六个组件则通过版本联动规则保持一致性。

对于需要 fork Godot 引擎、替换或升级其中某个依赖的开发者而言,正确的工作路径是:先读 thirdparty/README.md 对应小节确认上游与裁剪清单,再检查该目录下的 patches/ 与 Godot 自有文件(README 中有明确标注),最后按登记的脚本或步骤执行升级——而不是直接覆盖整个目录。

登录后查看全文
热门项目推荐
相关项目推荐