首页
/ Ladybird 代码策略:测试、语言、代码规范与自动化 Lint 钩子的完整实践

Ladybird 代码策略:测试、语言、代码规范与自动化 Lint 钩子的完整实践

2026-09-04 17:41:36作者:蔡丛锟

本文基于 Ladybird 浏览器仓库的 Documentation/CodePolicy.md 展开,系统梳理该独立浏览器项目对上游代码的准入要求:从测试策略、人类语言规范,到 C++23 代码风格、提交信息格式、AI 辅助使用边界,以及 pre-commit 钩子和 git notes 的实际工作方式。读完后,你将了解 Ladybird 贡献代码时必须满足哪些硬性规则,这些规则是如何被 Meta/lint-ci.shMeta/lint-commit.sh 等脚本自动强制执行的。

测试策略:修 Bug 加功能必须附带测试

CodePolicy 的第一条原则是:在可能的情况下,代码变更在修复缺陷或新增功能时应附带测试。对于与 Web 平台相关的改动,策略特别强调 Web Platform Tests(WPT):如果某个改动使 Ladybird 通过了之前尚未通过的 WPT 测试,应考虑把对应测试导入 Ladybird 代码树,并随代码改动一并提交。

导入 WPT 的操作方式在 Documentation/Testing.md 中有完整说明,核心命令是:

./Meta/WPT.sh import html/dom/aria-attribute-reflection.html

即把目标 WPT 测试在 http://wpt.live/ 上的路径部分传给 ./Meta/WPT.sh import。脚本会下载该测试及其 JavaScript 依赖,复制到 Tests/LibWeb/<test-type>/input/wpt-import 目录,运行测试后在 Tests/LibWeb/<test-type>/expected/wpt-import 下生成期望结果文件。WPT 的日常运行也统一通过仓库根目录的 Meta/WPT.sh 完成(如 runcompareupdate 子命令)。

人类语言策略:把英文当作编程语言一样对待

Ladybird 明确要求“对人类语言的态度要和对编程语言一样严肃”。该政策适用于所有用户可见字符串、代码、注释和提交信息:

  • 项目官方语言为美式英语,日期使用 ISO 8601 格式,单位使用公制;
  • 使用正确的拼写、语法和标点;
  • 采用权威、技术性的语气;
  • 避免缩写(contractions)、俚语和习语;
  • 避免幽默、讽刺及其他非字面含义的表达;
  • 使用性别中立的代词(指代特定个人时除外)。

文档特别指出:这条规则同样适用于调试日志等内部字符串,因为它们未来可能被暴露给用户。

代码策略(Do):C++23、AK 容器与原子提交

CodePolicy 给出了明确的“应该做”清单,核心要点包括:

  1. 写符合项目风格的惯用 C++23,在所有代码中使用 AK 容器。AK 是仓库根目录 AK/ 下的基础库,提供了 VectorHashMapString 等现代容器与智能指针(如 OwnPtrRefPtr),是 Ladybird 代码的基础设施。
  2. 遵循 Documentation/CodingStyle.md 的编码风格,并用 clang-format 自动格式化 C++ 文件。该文档强调必须使用正确版本的 clang-format,CI 强制的版本由 Meta/Linters/lint_clang_format.py 指定。命名规范上:类/结构体/命名空间用 CamelCase,变量和函数用 snake_case,常量用 SCREAMING_CASE;实现规范算法时尽量与规范原文命名保持一致。
  3. 选择有表达力的变量、函数与类名,让代码意图尽可能明显。
  4. 将改动拆分为独立的原子提交(一个提交对应一个功能或修复,且构建、测试、系统整体可用)。
  5. 确保提交已经 rebase 到 master 分支
  6. 提交信息按 72 字符换行
  7. 提交信息第一行是主题行,格式必须为 Category: Brief description of what's being changed,其中 Category 是库、应用、服务或工具的名字。文档给出的规则细节包括:
    • 示例类别:LibMediaWebContentCIAKRequestServerjs
    • 不要使用 LibrariesUtilities 这类过大的目录名作为类别(除非是确实影响大片代码的通用改动);
    • 也不要用具体组件名(如 C++ 类名)做类别——应写 LibGUI: Brief description of what's being changed in FooWidget,而不是 FooWidget: ...
    • 多个类别可用 + 组合,如 LibJS+LibWeb+Browser: ...
  8. 主题行使用祈使句("Foo: Change the way dates work" 而不是 "Foo: Changed ...")。
  9. 提交信息用规范的英文、仔细的措辞和标点撰写。
  10. 评审后追加改动时,在合适的情况下 amend 已有提交
  11. 推送修复后,把相应的评审评论标记为 “resolved”。
  12. 对文件做实质性修改时,添加个人版权行(可选但鼓励)。
  13. 检查代码、注释和提交信息的拼写。
  14. 随代码提交的图片要运行 optipng -strip all 优化并剥离无用元数据——文档称这能把文件大小从几 KB 压到几百字节。

这条 optipng 要求在 CI 侧有对应的强制检查:Meta/Linters/check_png_sizes.sh 会对 git 跟踪的每个 PNG(wpt-import 目录除外)运行 optipng -strip all,如果剥离出的字节数达到阈值(环境变量 MINIMUM_OPTIMIZATION_BYTES,默认 1024 字节)就判定未优化并失败,提示开发者“请对修改过的 PNG 运行 optipng -strip all”。本地若未安装 optipng 该检查会跳过,但在 CI(GITHUB_ACTIONS 环境)中缺失 optipng 会直接失败。

代码策略(Don't):明确禁止的反模式

文档同样列出了禁止事项,每一条都有明确的工程动机:

  • 不要引入与项目许可证(2-clause BSD)不兼容的改动。仓库根目录的 LICENSE 即为 BSD 2-Clause,且 Meta/Linters/check_style.py 会校验源文件头部的版权注释必须符合 Copyright (c) YYYY(-YYYY), ...SPDX-License-Identifier: BSD-2-Clause 的固定格式,否则 lint 失败。
  • 不要触碰改动范围之外的任何内容(保持原子性)。
  • 不要跨多个提交反复迭代设计(设计应在提交前成熟)。
  • 不要用 "refactor"、"fix" 这类含糊词逃避解释具体改了什么
  • 主题行结尾不要加句号
  • 不要包含被注释掉的代码
  • 不要用 C 的方式写代码——应充分利用 C++ 的特性,不要自我限制在标准 C 库内。
  • 不要在熟悉系统之前就尝试大型架构改动
  • 不要做过度的“风水编程”——没有可量化收益地移动代码。
  • 不要在用户可见部分加入玩笑或“有趣”的东西

关于 AI 与 LLM 的使用边界

文档对 AI 辅助的立场务实而明确:使用 AI 辅助通常没问题,但使用者有责任确保输出达到项目标准。文档指出现有 AI 生成内容往往过于冗长,质量不如精心撰写的人工代码。两条红线是:

  • 不得用 AI 或 LLM 直接生成改动、回复 issue 或参与项目讨论,而不同时以人工内容相同的标准审视其输出;
  • 不得用 AI 生成的描述或摘要来替代对相关代码、issue 或讨论的实际理解。

Commit 钩子:用 pre-commit 在本地提前拦截 CI 失败

仓库包含 .pre-commit-config.yaml,定义了可在创建提交前后自动运行的钩子,用于在本地提前保证改动和提交信息能通过自动化 CI 检查。该文件要求 minimum_pre_commit_version: 3.2.0,并注册了两个 local 类型的钩子:

  • meta-lint-ci(stages: pre-commit):入口命令为 bash Meta/lint-ci.sh,确保代码改动通过 lint;
  • meta-lint-commit(stages: commit-msg):入口命令为 Meta/lint-commit.sh,对提交信息做 lint。

启用方式(先按 pre-commit 官方文档完成安装,然后二选一或同时执行):

# 安装 pre-commit 钩子:提交前运行 Meta/lint-ci.sh 等 lint 检查
pre-commit install
# 安装 commit-msg 钩子:校验提交信息格式
pre-commit install --hook-type commit-msg

lint-ci.sh 实际检查什么

Meta/lint-ci.sh 的源码可以看到,它是一组 lint 的聚合执行器,依次运行(任一失败则整体非零退出):

值得一提的是 check_style.py 的具体规则,它把 CodePolicy 的诸多“Do”落实为机器可校验的检查:校验 #pragma once 必须存在且前后各有一个空行;校验 #include 只能是系统包含或可从当前文件直接解析的本地包含;禁止注释中出现 whatwg 单页 HTML 规范链接(加载过慢);要求 FIXMEAD-HOCNBNOTE 后必须紧跟冒号。这些细节解释了为什么代码风格在 Ladybird 中不是“建议”而是“门禁”。

另外从当前仓库结构看,.pre-commit-config.yaml 的钩子实际只调用了 Meta/lint-ci.sh,而 CodePolicy 文档中提到的 Meta/lint-ports.py 在当前树中已不存在,vcpkg 端口检查由 lint-ci.sh 内调用的 check_vcpkg.py 承担;以当前仓库的实际文件为准即可。

lint-commit.sh 逐条规则

Meta/lint-commit.sh 把提交信息格式规则变成了可执行的断言,遇到违规会打印完整提交信息并以非零退出。具体校验逻辑(源码逐行可对照):

规则 对应 lint 断言
只允许 Unix 风格 LF 换行 检测到 \x0D(CRLF)即失败
标题与正文之间必须有一个空行 第 2 行非空时报错
禁止 merge 提交(应使用 rebase) 首行匹配 ^Merge branch 即失败
首行必须带类别前缀 首行须匹配 `^(Revert "
类别后的第一个单词必须大写 首行须匹配 ^\S.*?: [A-Z0-9]
主题行不得以句号结尾 首行以 . 结尾即失败
每行最长 72 字符 超长行失败,除非该行是独占一行的 URL(scheme://host/path 形式)
禁止 Signed-off-by: 标签 正文含该行即失败
兼容 git commit --verbose>8 截断线和 # 注释行,以及 fixup! 开头的超长前缀 这些行被跳过

对照 CodePolicy 的 Do 清单可以看出:72 字符换行、Category: 祈使句描述 格式、不以句号结尾,这三条“人读”的规则与钩子“机读”的断言是一一对应的——这就是“先本地钩子、再 CI”的双层门禁设计。

Git Notes:在 git log 中看到 PR 与评审信息

GitHub 上的 Ladybird 项目为每个提交维护了 git notes,内容例如该提交来自哪个 Pull Request、评审人信息等,且会自动更新。要在本地 git log 中看到 notes,需要一次性配置 fetch refspec(upstream 应替换为你本地克隆中对上游仓库的 remote 名,可用 git remote -v 查询):

git config --add remote.upstream.fetch '+refs/notes/*:refs/notes/*'

配置后,每次 git fetch 都会同步最新 notes。此后 git log 会在提交信息下方额外显示 Notes 段。以文档中给出的真实示例(提交 c1b0e180ba64d2ea7e815e2c2e93087ae9a26500)为例:

commit c1b0e180ba64d2ea7e815e2c2e93087ae9a26500
Author: Timothy Flynn <trflynn89@pm.me>
Date:   Mon Jul 29 10:18:25 2024 -0400

    LibWebView: Insert line numbers before each line in about:srcdoc

    The behavior chosen here (fixed-width counters, alignment, etc.) matches
    Firefox.

Notes:
    Author:        <提交作者的 GitHub 主页链接>
    Commit:        <该提交在上游 GitHub 仓库的链接>
    Pull-request: <来源 Pull Request 的链接>
    Reviewed-by:  <评审人的 GitHub 主页链接> ✅

其中 Reviewed-by 行末尾的 ✅ 表示评审已完成。这一机制配合前文的提交信息类别规范(LibWebView: ...),使得提交历史在本地即可查看完整的溯源链:哪个库、哪个 PR、谁评审通过。

小结:策略文档与自动化门禁的闭环

Ladybird 的 CodePolicy.md 的价值在于它不只是一份“风格倡导”:文档中几乎每条硬性规则都能在当前仓库找到对应的自动化实现——72 字符与类别前缀由 Meta/lint-commit.sh 断言,clang-format 版本、#pragma once、SPDX 头、PNG 压缩由 Meta/lint-ci.sh 聚合的各 Meta/Linters/ 脚本校验,WPT 导入由 Meta/WPT.sh 承载。对研究该项目代码质量的读者而言,直接阅读这些脚本与本文对照,是理解其工程纪律最快、最可靠的路径。

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

项目优选

收起
kernelkernel
deepin linux kernel
C
33
18
ops-transformerops-transformer
本项目是CANN提供的transformer类大模型算子库,实现网络在NPU上加速计算。
C++
1.12 K
2.72 K
ops-nnops-nn
本项目是CANN提供的神经网络类计算算子库,实现网络在NPU上加速计算。
C++
903
1.82 K
docsdocs
暂无描述
Markdown
888
5.78 K
pytorchpytorch
作为 Ascend for PyTorch 社区的核心组件,TorchNPU 是昇腾专为 PyTorch 打造的深度学习适配插件,使 PyTorch 框架能够直接调用昇腾 NPU,为开发者提供昇腾 AI 处理器的超强算力。
Python
854
1.34 K
kernelkernel
openEuler内核是openEuler操作系统的核心,既是系统性能与稳定性的基石,也是连接处理器、设备与服务的桥梁。
C
527
590
jiuwenswarmjiuwenswarm
JiuwenSwarm 是一款基于openJiuwen开发的智能AI Agent,它能够将大语言模型的强大能力,通过你日常使用的各类通讯应用,直接延伸至你的指尖。
Python
3.51 K
1.01 K
ops-mathops-math
本项目是CANN提供的数学类基础计算算子库,实现网络在NPU上加速计算。
C++
1.33 K
1.45 K
AscendNPU-IRAscendNPU-IR
AscendNPU-IR是基于MLIR(Multi-Level Intermediate Representation)构建的,面向昇腾亲和算子编译时使用的中间表示,提供昇腾完备表达能力,通过编译优化提升昇腾AI处理器计算效率,支持通过生态框架使能昇腾AI处理器与深度调优
C++
540
384
flutter_flutterflutter_flutter
本仓库是 Flutter SDK 与 Flutter Engine 的 OpenHarmony 适配版本,由 CPF-Flutter 团队维护。开发者可使用熟悉的 Flutter 技术栈开发 OpenHarmony 应用,3.35.7 及以后的适配版本可基于本仓库源码构建支持 OpenHarmony 的 Flutter Engine。
Dart
1.17 K
341