构建系统、测试基础设施与贡献者工作流
前置知识
- ›第 1 篇:架构总览(了解各组件的构成)
- ›CMake 基础知识(构建目标、依赖关系、变量)
- ›熟悉命令行构建工具和测试运行器
构建系统、测试基础设施与贡献者工作流
对架构的理解,只有在你能够构建项目、运行测试并提交变更时,才能真正发挥价值。WebKit 的构建系统虽然面对的是一个体量庞大的项目,但上手体验出乎意料地友好——不过它也有一些容易让新人踩坑的特殊之处。双构建系统、统一源文件优化,以及覆盖广泛的测试套件,都需要你真正理解之后才能高效使用。
本篇是第 1 至第 5 篇架构深度解析的实践配套指南。读完之后,你将掌握如何在自己的平台上构建 WebKit、针对具体改动运行合适的测试,以及使用 git-webkit 工作流提交 Pull Request。
双构建系统:Xcode 与 CMake
WebKit 并行维护两套构建系统,各自面向不同平台:
| 构建系统 | 平台 | 入口文件 |
|---|---|---|
| Xcode | macOS、iOS、tvOS、watchOS、visionOS | WebKit.xcworkspace |
| CMake | GTK、WPE、PlayStation、Windows | CMakeLists.txt |
在 Apple 平台上,Xcode workspace(WebKit.xcworkspace)是主要的构建入口。它包含了所有组件的构建目标,并负责处理 framework 的生成、代码签名以及平台相关的编译配置。Apple 工程师和大多数 macOS 贡献者都走这条路径。
对于所有非 Apple 平台,CMake 是构建系统。CMakePresets.json 文件定义了常用的构建配置:
flowchart TD
subgraph APPLE["Apple Platforms"]
XC["WebKit.xcworkspace"] --> XB["xcodebuild"]
XB --> FW["Frameworks<br/>(WebKit.framework, etc.)"]
end
subgraph OTHER["Non-Apple Platforms"]
CMAKE["CMakeLists.txt"] --> PRESET["CMakePresets.json"]
PRESET --> GTK_P["GTK preset"]
PRESET --> WPE_P["WPE preset"]
PRESET --> PS_P["PlayStation preset"]
GTK_P --> LIBS["Shared Libraries<br/>(libwebkit2gtk.so, etc.)"]
end
BW["build-webkit script"] --> XC
BW --> CMAKE
预设配置包含 release、debug 和 dev 三种基础构建类型,以及 gtk-release、wpe-debug 等平台专属预设。dev 预设会启用 CMAKE_EXPORT_COMPILE_COMMANDS(用于 IDE 集成)和 DEVELOPER_MODE(构建测试运行器和性能工具)。
平台专属的构建配置通过各组件内的 PlatformX.cmake 文件来完成。正如我们在第 1 篇中所见,PlatformMac.cmake 负责添加 macOS 专属源文件和 framework 依赖,而 PlatformGTK.cmake 则添加 GTK 专属源文件和 pkg-config 依赖。
统一源文件:编译时间优化
仅 WebCore 就拥有超过 5,270 个源文件,如果逐一编译,整个过程将耗费数小时。WebKit 采用**统一源文件(unified sources)**机制,将多个 .cpp 文件打包成单个编译单元,从而大幅缩短编译时间。
flowchart TD
SOURCES["Sources.txt<br/>5,270 .cpp file paths"] --> GEN["Build system<br/>(CMake or Xcode)"]
GEN --> U1["UnifiedSource1.cpp<br/>#include 'File1.cpp'<br/>#include 'File2.cpp'<br/>...<br/>#include 'File8.cpp'"]
GEN --> U2["UnifiedSource2.cpp<br/>#include 'File9.cpp'<br/>...<br/>#include 'File16.cpp'"]
GEN --> UN["UnifiedSourceN.cpp<br/>..."]
U1 --> COMP["Compiler"]
U2 --> COMP
UN --> COMP
Sources.txt 是一个简单的相对路径列表,每行一个 .cpp 文件。构建系统读取这份列表,将文件按约 8 个一组进行打包,生成以 #include 原始源文件为内容的 UnifiedSourceN.cpp 文件。
这种方式能将编译时间缩短一个数量级,原因如下:
- 头文件在每个打包单元中只解析一次,而非每个源文件各解析一次。
- 模板实例化可在同一打包单元内的文件之间共享。
- 编译器的整体遍历次数大幅减少。
这种优化也带来了一定的代价——同一打包单元内的文件共享同一个编译单元,这意味着:
- 某个文件中的静态符号,对同一打包单元内的其他文件是可见的。
- 头文件的引入顺序至关重要——在第 3 个文件中引入的头文件,在同一打包单元的第 4 至第 8 个文件中同样可用。
- 同一打包单元内的文件之间可能发生符号冲突。
平台专属文件放在独立的列表中:Apple 平台对应 SourcesCocoa.txt,GTK 对应 SourcesGTK.txt,依此类推。这些文件会被单独打包,且只在对应平台上参与编译。
提示: 如果你的改动导致出现莫名其妙的构建错误,比如某个符号"已被定义"或某个头文件"找不到",很可能是遇到了统一源文件的排序问题。检查一下你的文件落在哪个打包单元中,并确保它不会与
Sources.txt中相邻的文件产生冲突。
条件编译:PLATFORM、ENABLE、USE
正如第 1 篇所讨论的,三组宏家族控制着编译内容的取舍。下面来更深入地了解它们之间的协作方式:
flowchart TD
subgraph MACROS["Conditional Compilation Macros"]
PLAT["PLATFORM(X)<br/>Target OS<br/>COCOA, GTK, WPE, WIN"]
EN["ENABLE(X)<br/>Feature Flags<br/>WEBGL, CSS_SELECTOR_JIT, FTL_JIT"]
USE_M["USE(X)<br/>Implementation Choice<br/>CG, CAIRO, SKIA, CF, GLIB"]
end
PLAT --> CONFIG_H["config.h<br/>(auto-generated)"]
EN --> CONFIG_H
USE_M --> CONFIG_H
CONFIG_H --> EVERY_CPP["Every .cpp file<br/>#include 'config.h'"]
PLATFORM(COCOA) 在所有 Apple 平台(macOS、iOS 等)上为真;PLATFORM(GTK) 在 GTK 移植版上为真。两者互斥。
ENABLE(X) 系列的开关可以独立切换。ENABLE(WEBGL) 可以不受平台限制地开启或关闭;ENABLE(CSS_SELECTOR_JIT) 启用第 3 篇介绍的 CSS JIT 编译器;ENABLE(FTL_JIT) 启用第 5 篇介绍的 FTL 编译层级。
USE(X) 用于选择具体的实现方案。USE(CG) 表示使用 CoreGraphics 进行 2D 渲染;在非 Apple 平台上,USE(CAIRO) 或 USE(SKIA) 是可选的替代方案;USE(CF) 表示使用 CoreFoundation;USE(GLIB) 表示使用 GLib。
构建 WebKit:build-webkit 及相关工具
构建 WebKit 最简便的方式是使用 Tools/Scripts/ 目录下的 build-webkit 脚本:
# Build for macOS (Debug)
Tools/Scripts/build-webkit --debug
# Build for macOS (Release)
Tools/Scripts/build-webkit --release
# Build for GTK
Tools/Scripts/build-webkit --gtk --release
# Build for WPE
Tools/Scripts/build-webkit --wpe --debug
构建完成后,可以用本地构建版本启动 Safari:
Tools/Scripts/run-safari --debug
这个脚本会将 DYLD_FRAMEWORK_PATH 指向你的构建输出目录,使 Safari 加载本地构建的 WebKit framework,而非系统自带的版本。
flowchart LR
DEV["Developer"] --> BW["build-webkit<br/>--debug or --release"]
BW -->|macOS| XCODE["xcodebuild<br/>WebKit.xcworkspace"]
BW -->|GTK/WPE| CMAKE_B["cmake --build"]
XCODE --> BUILD_DIR["WebKitBuild/Debug<br/>or Release"]
CMAKE_B --> BUILD_DIR
BUILD_DIR --> RS["run-safari<br/>DYLD_FRAMEWORK_PATH"]
RS --> SAFARI["Safari with local WebKit"]
根目录下的 Makefile 提供了一些便捷目标,将常用配置的 build-webkit 调用封装好,开箱即用。
提示: 想要加快迭代速度,可以只构建你正在修改的组件。如果你改动的是 WebCore,每次都从头重建 JSC 是没有必要的。构建系统对增量构建的支持已经相当完善,此外你也可以用
build-webkit --no-experimental-features跳过不需要的功能,进一步节省时间。
测试基础设施:Layout Tests、JSTests 与 API Tests
WebKit 拥有四套相互独立的测试套件,分别覆盖不同的层次:
| 套件 | 位置 | 运行器 | 测试内容 |
|---|---|---|---|
| Layout Tests | LayoutTests/ |
run-webkit-tests |
Web 平台合规性(HTML、CSS、DOM 渲染) |
| JSTests | JSTests/ |
run-javascriptcore-tests |
JavaScript 引擎正确性 |
| API Tests | Tools/TestWebKitAPI/ |
GTest | C++ API 正确性 |
| WebDriver Tests | WebDriverTests/ |
基于 Selenium | 浏览器自动化 |
Layout Tests 是最具特色的一套。每个测试都是一个 HTML 文件,会产生文本转储或像素渲染结果。测试运行器将实际输出与预期结果(存储为 -expected.txt 或 -expected.png 文件)进行比对。这种方式能够测试从解析到渲染的完整流程。运行方式如下:
Tools/Scripts/run-webkit-tests
JSTests 通过数千个 JavaScript 程序、压力测试和微基准测试来验证 JavaScriptCore 的正确性。测试运行器会覆盖所有编译层级:
Tools/Scripts/run-javascriptcore-tests
flowchart TD
subgraph LAYOUT["Layout Tests"]
HTML["test.html"] --> RUNNER["run-webkit-tests<br/>(DumpRenderTree / WebKitTestRunner)"]
RUNNER --> OUTPUT["Actual output"]
EXPECTED["test-expected.txt"] --> DIFF["Compare"]
OUTPUT --> DIFF
DIFF --> RESULT["PASS / FAIL"]
end
subgraph JSC_TESTS["JSTests"]
JS["test.js"] --> JSC_RUN["run-javascriptcore-tests"]
JSC_RUN --> |"All tiers"| JSC_OUT["Test results"]
end
subgraph API["API Tests"]
GTEST["TestWebKitAPI/*.cpp"] --> GTEST_RUN["GTest runner"]
GTEST_RUN --> API_OUT["Test results"]
end
API Tests 是基于 GTest 的 C++ 测试,直接对 WebKit 的公共 API 和内部 API 进行验证。相比 Layout Tests,它们运行速度更快,非常适合对特定 C++ 类进行隔离测试。
性能基准测试
WebKit 维护了三大主要基准测试,用于检测性能回退:
-
JetStream — 通过哈希表、加密、物理模拟、解析器等多种负载,测试 JavaScript 和 WebAssembly 的性能。位于
PerformanceTests/JetStream3/。 -
MotionMark — 通过动态 2D 动画场景对绘制和合成流程施压,测试图形和渲染性能。
-
Speedometer — 通过模拟用户与基于 React、Angular、Vue 等主流框架构建的 TodoMVC 风格应用进行交互,测试 Web 应用的响应速度。
这些基准测试位于 PerformanceTests/ 目录,并在 WebKit 的 CI 基础设施上持续运行。一旦检测到性能回退,会被当作需要修复的 bug 对待。
贡献者工作流:git-webkit 与代码风格
WebKit 使用 GitHub Pull Request 进行代码审查。git-webkit 工具(通过 Tools/Scripts/ 安装)可以简化整个工作流:
# Install git-webkit
git webkit setup
# Create a branch and make changes
git checkout -b my-fix
# ... edit files ...
git commit -m "[Component] Fix the thing"
# Submit a pull request
git webkit pr
flowchart LR
BRANCH["Create branch"] --> EDIT["Make changes"]
EDIT --> COMMIT["git commit"]
COMMIT --> PR["git webkit pr"]
PR --> REVIEW["Code review on GitHub"]
REVIEW --> |"approved"| LAND["git webkit land"]
REVIEW --> |"changes requested"| EDIT
代码格式由 .clang-format 统一约束,其中定义了 WebKit 的编码风格。主要规则包括:
- 大括号风格:
BreakBeforeBraces: WebKit— 控制结构的左括号与语句同行,函数则另起一行。 - 缩进:4 个空格,禁止使用制表符。
- 列宽限制:clang-format 不强制限制(WebKit 采用手动换行)。
- 命名规范:类名使用
PascalCase,方法名使用camelCase,成员变量使用m_camelCase。
提交前,请运行风格检查工具:
Tools/Scripts/check-webkit-style
提示:
Introduction.md包含面向新贡献者的详细说明,涵盖开发环境搭建、如何找到适合入手的 bug,以及如何完成代码审查流程。这是官方的新人入门文档,会持续保持更新。
系列总结
这六篇文章带领我们从架构基础出发,一路走到了实际的贡献工作流,完整地穿越了 WebKit 代码库:
- 架构总览 — 分层依赖链、多进程模型与仓库结构。
- WTF 与内存管理 — 智能指针体系、
protectedThis、IsoHeap 安全加固。 - WebCore — DOM、渲染流水线、CSS JIT 与 Web IDL 绑定。
- 多进程 IPC —
.messages.in代码生成系统与代理模式。 - JavaScriptCore — 四层编译流水线与 B3 后端。
- 构建与测试 — 双构建系统、统一源文件、测试套件与贡献者工作流。
WebKit 是一个活跃演进的项目,每年有数千次提交。我们深入探讨的这些架构模式——分层依赖、进程隔离、分层编译、侵入式引用计数——都是经受了十余年考验的稳定设计决策。真正理解它们,你就能在这个庞大的代码库中游刃有余,无论走到哪个角落都不会迷失方向。
加深理解最好的方式,就是找一个你感兴趣的具体领域,读代码,并参与贡献。WebKit 社区对新贡献者非常友好,完善的测试基础设施也让你能够放心地大胆尝试。祝你好运,编码愉快。