SerenityOS 贡献指南:从 Issue 规范、C++ 编码风格到 commit hook 的完整协作实践
【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity
SerenityOS 是一个从零自研的操作系统项目,其 CONTRIBUTING.md 定义了整个社区的协作契约:包括 Issue 提交流程、人类语言政策、C++26 编码风格、提交信息格式、Pull Request 评审预期,以及仓库内置的 pre-commit / commit-msg 钩子。本文以该文档为主线,结合仓库内的 .pre-commit-config.yaml、Meta/lint-commit.sh、Meta/lint-ci.sh、Meta/check-style.py 与 Documentation/CodingStyle.md 等真实实现,给出可直接落地执行的全流程贡献实操指南。
贡献前的方向确认
SerenityOS 对贡献者的第一要求是:确保你的改动符合项目发展方向。如果你不确定,应先在仓库中开启一个 Issue 讨论,而不是直接提交大段代码。
- 对于最初的一两个 Pull Request,文档明确建议从小改动开始,先熟悉项目与开发流程;
- 禁止以新增一个应用程序、库或其他大型组件作为首次 PR;
- 项目欢迎所有人参与,文档的原话是"我们玩得很开心,但这是认真的那种开心"——意味着协作氛围轻松、但对工程质量要求严肃。
从仓库结构可以看到项目的宏大版图:内核(Kernel/)、基础库(AK/)、浏览器(Ladybird/)以及数千个用户态程序(Userland/)。这也解释了为什么文档要求新贡献者从小处入手——改动必须能被维护者在合理时间内审阅清楚。
沟通渠道
项目的开发者沟通主阵地是 Discord 服务器(https://serenityos.org/discord)。文档后续多次强调 Discord 在代码评审中的实际作用:
- 未在社区"打广告"的 PR 可能被好奇的维护者随机合并,但主动在 Discord 上宣传会顺畅得多;
- 由于 GitHub 通知量过大,很多维护者关闭了 GitHub 通知、依赖 Discord 获知评审请求,因此在 Discord 上(例如
#code-review频道)询问评审远比在 GitHub 上等待有效; - 构建类问题(见下节)应前往 Discord 的
#build-problems频道求助。
Issue 政策:目标读者是开发者自己
文档开宗明义:与许多追求最大用户群的项目不同,SerenityOS 的目标受众是其自身的开发者。因此,项目对非贡献者的功能请求兴趣有限——请不要把这里当作普通软件的产品反馈渠道。
提交 Bug 时请遵守以下规则:
- 一个 Issue 只描述一个 Bug。把多个问题塞进同一 Issue 会使讨论和关闭都变得不必要的复杂;
- 不要提交构建问题或其他支持请求。如果 CI 构建成功而本地失败,问题大概率在你自己环境,应在本地解决,或去 Discord 的
#build-problems频道询问; - 不要在 Issue 里刷无意义评论(玩笑或无关吐槽)。成百上千人会被评论通知打扰,请保持相关性;
- 裸机(bare metal)问题必须附带完整调试日志:包括串口控制台的完整 debug log、你为解决该问题已尝试过的步骤、机器的硬件型号与相关细节,帮助维护者诊断。
人类语言政策:像对待编程语言一样对待自然语言
项目将人类语言与编程语言同等重视。以下规范适用于所有面向用户的字符串、代码、注释和提交信息:
- 官方语言为美式英语;
- 日期使用ISO 8601格式;
- 度量单位使用公制单位;
- 拼写、语法和标点必须正确;
- 语气要求权威且技术化(authoritative and technical)。
文档鼓励大家使用拼写检查器等工具来辅助。在仓库中,这一政策同样被机器强制执行——例如 Meta/lint-commit.sh 会检查提交信息中的大小写与标点,而 Meta/check-style.py 会强制 C++ 头文件的版权头格式。
测试政策:能测则测
修复 Bug 或添加新功能时,请尽可能附带测试。这是硬性要求而非建议。
仓库中测试的体量可以佐证这一政策的执行力度:Tests/AK/ 下有 100+ 个针对基础库的测试文件(如TestVector.cpp、TestString.cpp、TestHashMap.cpp),而 Tests/ 目录整体覆盖了从 LibGfx 图像解码到 LibJS、Kernel 等几乎所有子系统。CI 中的 Meta/check-ak-test-files.sh 还会专门检查 AK 的测试文件是否齐备。
代码提交规范:Do 与 Don't
应做事项(Do)
1. 编写地道的 SerenityOS C++26,并在所有代码中使用AK容器。
项目不使用 STL 作为主力容器库,而是使用自研的 AK(Auxiliary Kernel 工具库)——例如Vector、String、HashMap、OwnPtr、RefPtr等。提交代码前请确保对 AK/ 的常用容器有基本了解。
2. 遵循项目编码风格,并使用clang-format(20 或更新版本)。
完整的风格规范见 Documentation/CodingStyle.md,底层格式规则由仓库根目录的 .clang-format 定义。要点速览:
| 维度 | 规范 | 正例 / 反例 |
|---|---|---|
| 类/结构体/命名空间 | CamelCase(首字母大写) | class FileDescriptor/class filedescriptor |
| 变量/函数 | snake_case | size_t buffer_size/size_t bufferSize |
| 常量 | SCREAMING_CASE | MAX_ENTRIES |
| 成员前缀 | 非静态成员m_、静态成员s_、全局变量g_ | int m_length { 0 }; |
| getter/setter | setter 用set_前缀,getter 用裸词,out 参数 getter 用get_ | set_count(int)/int count() const |
| 头文件守卫 | 一律#pragma once | — |
| const 位置 | "east const"(const 写在类型右侧) | Salt const& m_salt; |
| 虚函数 | 声明必须带virtual,重写必须带override或final | virtual String description() override |
| 强制转换 | 禁止 C 风格 cast,用static_cast等对应 C++ cast | — |
| 花括号 | 单行体可省略花括号,否则整套 if/else 都要加 | — |
若你的发行版没有 clang-format 20,Documentation/AdvancedBuildInstructions.md 给出了三个方案:基于 apt 的发行版使用 LLVM 官方 apt 仓库安装最新 clang-format;或通过 Toolchain/BuildClang.sh 编译 SerenityOS 定制的 LLVM,使用编译产物Toolchain/Local/clang/bin/clang-format(pre-commit 钩子会自动识别该二进制)。
3. 命名要富有表现力:变量、函数和类名要尽可能直观地表达其用途。
4. 将改动拆分为独立的原子提交:每个提交对应一个功能或修复,且提交后构建、测试和系统都能正常运行。
5. 确保提交基于 master 分支 rebase 过。
6. 提交信息每行不超过 72 个字符,并按指定格式书写:
- 第一行为主题行,格式为
Category: Brief description of what's being changed; - Category 应为库、应用、服务或工具的名称,例如
LibAudio、HackStudio、Base、Kernel、ConfigServer、cat; - 除非改动横跨目录内大量代码,否则不要使用
Userland或Utilities这类宽泛类别; - 不要用具体组件名(如 C++ 类名)作类别,应写进摘要里,例如用
LibGUI: Brief description of what's being changed in FooWidget而非FooWidget: ...; - 多个类别可用
+组合,如LibJS+LibWeb+Browser: ...; - 主题行使用祈使语气(
Foo: Change the way dates work,而非Foo: Changed the way dates work); - 提交信息要用规范英语书写,注意措辞与标点;
- 评审后的修改请用 amend 合并进原提交(而非新提交),并在推送修复后把每条评审意见标记为 resolved。
仓库最近的提交历史就是活教材,例如Ports/ncurses: Remove the --enable-term-driver build option——类别 + 祈使语气 + 无句号结尾,完全符合上述格式。
7. 对文件做实质性修改时,可以(鼓励但非必须)添加个人版权行。
8. 检查代码、注释与提交信息的拼写。
9. 附带的图片资源先用optipng -strip all优化:去掉无用元数据,文件体积可能从数 KB 降到几百字节。
禁止事项(Don't)
- 提交与项目许可证(2-clause BSD)不兼容的代码;
- 触碰 PR 声明范围之外的任何东西;
- 在多个提交中反复迭代设计;
- 用 "refactor"、"fix" 之类模糊词汇回避解释改动内容;
- 提交信息主题行以句号结尾;
- 包含注释掉的代码;
- 用 C 编写代码——应充分利用 C++ 的能力,不要把自己限制在标准 C 库内;
- 在尚未熟悉系统前尝试大规模架构改动;
- 无量化收益地搬动代码(文档称之为 "feng shui programming");
- 在系统面向用户的部分加入玩笑或"有趣"内容。
提交钩子:让规范自动化
仓库根目录的 .pre-commit-config.yaml 定义了三个基于 pre-commit 框架的钩子:
| 钩子 | 入口 | 触发阶段 | 作用 |
|---|---|---|---|
| meta-lint-ci | bash Meta/lint-ci.sh --no-ports | pre-commit | 运行全部 lint 脚本,确保改动能通过 CI 检查 |
| meta-lint-ports | Meta/lint-ports.py | pre-commit | 仅在^Ports/文件变更时运行,扫描 Ports 目录 |
| meta-lint-commit | Meta/lint-commit.sh | commit-msg | 校验提交信息格式 |
启用方式:先按 pre-commit 官方文档安装框架,然后执行:
# 安装 pre-commit 钩子:提交前运行 Meta/lint-ci.sh 与 Meta/lint-ports.py,确保代码能通过 lint pre-commit install # 安装 commit-msg 钩子:提交时校验提交信息能否通过 commit lint pre-commit install --hook-type commit-msg注意钩子配置中的一个工程细节:meta-lint-ci通过args: [ --no-ports ]跳过了 Ports 检查,而meta-lint-ports只对Ports/目录的文件触发(files: ^Ports/且pass_filenames: false)。正如 Meta/lint-ci.sh 注释所解释的:lint-ports.py会全量扫描所有 Ports,若在 pre-commit 阶段每次都跑会非常耗时,因此拆成了按需触发的独立钩子。
lint-ci.sh 实际执行哪些检查
从 Meta/lint-ci.sh 源码看,pre-commit 的meta-lint-ci钩子会串行运行 16 个检查脚本,任何一个失败都会计入FAILURES并最终以非零退出码结束:
- Meta/check-ak-test-files.sh:AK 测试文件完整性
- Meta/check-debug-flags.sh:debug 标志检查
- Meta/check-emoji.py、Meta/check-idl-files.py、Meta/check-jbig2-json.sh、Meta/check-markdown.sh、Meta/check-newlines-at-eof.py、Meta/check-png-sizes.sh
- Meta/check-style.py:版权头、
#pragma once、include 合法性(详见下文) - Meta/lint-executable-resources.sh、Meta/lint-gml-format.sh、Meta/lint-gn.sh、Meta/lint-keymaps.py、Meta/lint-prettier.sh、Meta/lint-python.sh、Meta/lint-shell-scripts.sh
此外还会尝试用构建产物./Build/lagom/bin/IPCMagicLinter校验*.ipc文件(未构建时跳过),最后通过 Meta/lint-clang-format.sh 对全部.cpp/.h/.mm文件就地运行 clang-format 并比对 git diff。lint-clang-format.sh会按优先级查找clang-format-20、brew --prefix llvm@20下的二进制、Toolchain/Local/clang/bin/clang-format,并要求显式传入--overwrite-inplace参数——这是为了让开发者清楚意识到该脚本会直接改写本地文件。
check-style.py 的机器化风格检查
Meta/check-style.py 是风格政策的直接执行者,它用正则强制以下规则:
- BSD-2-Clause 版权头:每个
.cpp/.h文件顶部必须是/* ... SPDX-License-Identifier: BSD-2-Clause */格式(有少量排除名单,如 AK/Checked.h); #pragma once:所有头文件必须包含且格式正确的#pragma once(前后有空白行);- 禁止
#include <LibC/...>:LibC 是系统库,不应以目录形式被包含; - 禁止
#include <complex>/#include <ccomplex>:Serenity C++ 代码必须使用 AK 的复数实现; - 本地 include 必须可解析:
#include "..."指向的文件必须真实存在。
这些检查与 Documentation/CodingStyle.md 中的命名、前缀、const 位置、虚函数声明等规范一起,构成了"编码风格可被 CI 强制"的完整闭环。
lint-commit.sh 如何校验提交信息
Meta/lint-commit.sh 是 commit-msg 钩子的实现,它对提交信息做了非常具体的机器校验,逐条对应文档中的要求:
- 拒绝 Windows 风格 CRLF 换行;
- 拒绝 merge commit(提示改用 rebase);
- 主题行必须匹配
Category:格式(正则^(\S+: )),否则报"缺少类别";若怀疑是前一个提交的 fixup,应直接 squash 掉; - 主题行超过 72 字符即报错(
Revert "开头的提交豁免); - 主题行中类别后的首词必须以大写字母或数字开头;
- 主题行以句号结尾即报错;
- 第二行必须为空行(标题与正文之间的空行不可省略);
- 正文每行不得超过 72 字符(URL 行豁免);
- 正文中不允许出现
Signed-off-by:标记。
Pull Request 评审 FAQ
文档以 FAQ 形式回答了新贡献者最关心的评审问题:
Q:PR 通过了 CI,多久能收到评审反馈?未宣传的 PR 可能被好奇的维护者随机合并,但更稳妥的方式是在 Discord 上积极互动、主动宣传。
Q:PR 一直没人理,该等多久再联系维护者?如果是紧急内容可以立即 ping;非紧急则在 Discord 的#code-review频道宣传你的 PR 并请求评审。
Q:项目维护者是谁?当前维护者名单(GitHub 用户名):@ADKaster、@alimpfard、@AtkinsSJ、@BertalanD、@GMTA、@Lubrsi、@LucasChollet、@nico、@spholz、@timschumi、@trflynn89。维护权是仅限邀请制,且与任何特定指标无关。
Q:对长期无人维护的分支/PR 有策略吗?有。仓库运行一个 "stalebot":PR 连续 21 天无人触碰会被标记为 "stale",再经过 7 天仍无动静则自动关闭。
Q:不同子系统(Kernel、Browser、GUI 等)有专门对接人吗?理论上最合适的人选是"写过与你改动相邻代码最多的人";实践中在 Discord 的开发频道提问通常更简单有效,因为能让更多人参与讨论。
Q:请求评审该用 Discord 还是 GitHub?明确建议用 Discord。由于 GitHub 通知量太大,很多维护者关闭了通知、依赖 Discord 获知评审请求。
被遗弃的 Pull Request 如何处理
偶尔有质量不错但作者失联的 PR。若 PR 本身没有问题、只是作者不回应对接,项目可能会以小幅修改代码与提交信息的方式手动合入。因此文档特别鼓励贡献者开启 PR 上的"Allow edits from maintainers"选项,方便维护者直接修正。
关于意识形态类改动
Serenity 的愿景是在合理范围内让尽可能多的群体协作,欢迎使项目对更多人可及的贡献。但项目定位为纯粹的技术实践,不寻求引发任何社会政治层面的改变:项目明确避免卷入"外部"文化战争,并可能拒绝它认为敏感(如狗哨式隐语、宗教信仰——这显然离题——或现实政治人物)的改动。
文档也承认项目有时会判断失误,但鼓励以善意的对话而非愤怒来处理分歧。
小结:一次合规贡献的完整动线
把以上所有规范串联起来,一次符合 SerenityOS 流程的贡献大致是:
- 开 Issue 确认方向(或直接修一个明确的小 Bug);
- 用 SerenityOS 风格(C++26 + AK 容器)编写代码,
clang-format20 自动格式化; - 尽可能为改动补充测试(参考 Tests/AK/ 的模式);
- 按
Category: Imperative summary格式书写提交信息(72 字符、祈使语气、无句号),通过 .pre-commit-config.yaml 配置的 pre-commit 与 commit-msg 钩子自检; - 推送基于 master rebase 的原子提交,在 Discord 的
#code-review频道宣传 PR; - 根据评审意见 amend 提交、标记评论为 resolved,保持沟通畅通。
这套由文档 + 钩子脚本 + CI 共同构成的流程,让"编码风格"与"提交规范"从纸面约定变成了可机器校验的硬约束——这正是 SerenityOS 能在庞大的代码库规模下维持高度一致性的关键工程实践。
【免费下载链接】serenityThe Serenity Operating System 🐞项目地址: https://gitcode.com/GitHub_Trending/se/serenity
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考