curl 贡献实战指南:代码风格、测试用例、REUSE 合规与提交信息的完整规范
本文以 CONTRIBUTE.md 为骨架,系统梳理 curl 项目的贡献全流程:如何遵循被 make checksrc 强制约束的 C 代码风格、如何为每个新特性补齐测试用例、pull request 如何通过与 CI 验证及 feature window 机制最终被合并,以及 curl 特有的 commit message 格式、REUSE 许可证合规检查和对 AI 辅助贡献的明确要求。读完本文,你将掌握一份从第一次提交补丁到成为 push access 贡献者的可操作路线图,并能直接对照仓库中的脚本与测试体系落地执行。
1. 贡献前的准备:社区渠道、许可与必读材料
1.1 加入社区
curl 项目偏好问题与讨论在邮件列表上进行,而不是直接发给个人。在提问前应阅读邮件列表礼仪规范——仓库内即有 MAIL-ETIQUETTE.md 记录了完整的列表行为规范;在提交补丁之前,则应先通读本文档。如果对代码侧开发感兴趣,curl 在 IRC 频道 #curl(libera.chat)也有社区驻留。
1.2 许可与版权规则
以代码形式向 curl 贡献时,需遵守以下许可规则(源自 CONTRIBUTE.md “License and copyright”一节):
- 你的改动与新代码默认采用与 curl/libcurl 相同的许可证,除非另行说明并达成一致;
- 如果加入较大的一块代码,可以让该文件或文件组使用不同的许可证,前提是它不强制改动包的其他部分、且选择合理。这类“独立部分”不允许使用 GPL(项目不希望 copyleft 传导给 libcurl 用户),但必须使用“GPL 兼容”的许可证(保证 GPL 环境下的使用者能正常使用 libcurl);
- 修改已有源码不会改变原文件的版权归属,版权仍归原始作者或其受让人;
- 提交补丁即表示你拥有该代码的处置权,并获雇主等允许将其交给项目。项目会尽量署名贡献者,因此贡献时请始终提供真实全名。
仓库的许可证文本保存在 LICENSES/ 目录(含 curl 许可证 等),根级 REUSE.toml 则按 REUSE 规范描述无法直接加注释的文件的许可状态。
1.3 必读材料清单
原文档要求贡献者在动手前阅读:
- 源码与 man 页面——命令行选项的 man 页面源文件集中在 docs/cmdline-opts/,libcurl API 文档在 docs/libcurl/,均以 markdown 编写再渲染为 man 页与 HTML;
- 内部实现文档——docs/internals/ 目录包含 28 篇模块级文档(如 CODE_STYLE.md、CHECKSRC.md、NEW-PROTOCOL.md 等),入口是 docs/internals/README.md;
- docs/TODO.md 与 docs/KNOWN_BUGS.md,以及 git 中的最新提交记录;
- 关注 curl-library 邮件列表的近期讨论,了解正在进行的工作。
2. 写出一个好补丁(Write a good patch)
2.1 遵循既定代码风格,并跑通 make checksrc
C 代码必须遵循项目既定的 C 代码风格指南。风格统一比个人口味更重要,它让代码库像“一个人写的”,也便于评审与调试。风格指南的几条硬性规则包括:
- 缩进只用空格、每层两个空格,禁止 TAB;
- 只写 C89 代码,因此
//注释不被允许,一律使用/* */; - 源码行宽不得超过 79 列;
if/while/for的开括号与关键字同行,函数开括号单独成行;else换行书写。
在提交任何改动之前,文档明确要求运行 make checksrc。该目标定义在根 Makefile.am,会依次进入 lib、src、tests、include/curl、docs/examples、projects 各子目录执行检查,底层工具是 scripts/checksrc.pl。需要说明的是,checksrc 并不校验完整风格指南,它只捕获贡献者最常犯的典型错误——但“如果它抱怨了,你就还有功课要做”。
从 docs/internals/CHECKSRC.md 可以看到它覆盖的主要检查项,摘取其中对日常编码影响最大的几类:
| 警告名 | 检查内容 |
|---|---|
BANNEDFUNC |
使用了被禁函数:sprintf、vsprintf、strcat、strncat、gets 绝不允许出现在 curl 源码中 |
SNPRINTF |
检测到 snprintf();项目偏好内部替代实现 curl_msnprintf() |
LONGLINE |
行宽超过 79 列 |
TABS |
出现 TAB 字符 |
CPPCOMMENTS |
出现非 C89 的 // 注释 |
ASTERISKNOSPACE / ASTERISKSPACE |
指针声明应为 char *name 形式 |
EQUALSNULL |
在 if/while 中比较 == NULL,项目偏好 !var |
USESAFEFREE |
curlx_free(var) 后手动置 NULL,应改用 curlx_safefree() |
COPYRIGHT |
文件缺少版权声明 |
checksrc 还支持在源码内联控制豁免:
/* !checksrc! disable LONGLINE all */
/* ... 一段确实无法缩短的长行 ... */
/* !checksrc! enable LONGLINE */
也可以只豁免 N 次,例如 /* !checksrc! disable LONGLINE 1 */ 表示忽略一次长行警告后自动恢复。此外还有默认关闭的扩展警告(如 COPYRIGHTYEAR),可通过在目录中放置 .checksrc 文件按 enable <EXTENDEDWARNING> 逐行启用。
2.2 不做全局性翻修(Non-clobbering All Over)
开发新功能或修 bug 时,不要顺手“翻新”无关的源码和函数——其他开发者很可能正在改同一个文件甚至同一个函数,全局改动会制造大量冲突。文档给出的具体建议是:
- 引入全新功能时,尽量写进新的源文件;
- 修 bug 时,一次只修一个 bug,拆成独立补丁分别提交。
2.3 拆分变更(Write Separate Changes)
文档用一个很现实的反例说明拆分的重要性:一个号称修复 11 个问题的巨型补丁,若其中 10 个与讨论结论不符或已被别的方式修复,合并者就得从代码山里手工剥离那 1 个有效改动,工作量巨大。因此每个修复都应有自己的补丁/commit 和各自的描述,使维护者可以选择性地采纳。拆分变更还让日后的 git bisect 定位回归问题顺畅得多。
2.4 基于最新源码打补丁
请尽量用当前可获得的最新源码作为补丁基线:最优是从 git 仓库拿到最新代码,使用最新发布包也可以。基线越新,维护者合并时的工作量越小(“Making quality changes”一节再次强调:补丁要尽可能基于最新源码)。
2.5 附带文档
文档坦承“写文档是枯燥的,也是许多开源项目的大问题”,但要求每个贡献都附带一小段对修复内容或新特性的描述,便于快速并入包内文档。curl 的文档体系是:man 页面与站点 HTML 大多由 markdown / 纯 ASCII 源文件渲染生成,因此在 docs/cmdline-opts/(命令行选项)、docs/libcurl/(API)下维护 markdown 源文件即可。
2.6 每个新特性都要带测试用例
自测试套件建立以来,项目可以快速验证主要功能符合预期。为保持并改善这一状态,所有新增功能和函数都必须进入测试套件:每个新增特性至少要有一个能验证“它按文档工作”的有效测试用例。如果某处确实难以写测试,则必须在提交说明中准确解释你如何以其他方式测试与验证了改动。
仓库中的测试体系可以直接对应理解:
- tests/ 目录是套件主体,tests/runtests.pl 是测试运行器,
TFLAGS中的参数直接透传给它; - tests/libtest/ 下约 276 个
.c文件是基于 libcurl API 的测试程序,tests/unit/ 下约 79 个.c文件是针对内部组件的单元测试; - tests/data/ 下有 2000 余个测试数据文件(
test**编号文件即各测试用例的请求/期望定义); - 测试服务器脚本如 tests/http-server.pl、tests/ftpserver.pl、tests/rtspserver.pl 等支撑对应协议用例。
运行方式见 docs/tests/TEST-SUITE.md:在仓库根目录执行 ./configure && make && make test,指定用例可用 make test TFLAGS="303 410",加速可用 make test TFLAGS="-j10";失败后到 tests/log 目录查看 stdout/stderr 与测试服务器输出。
3. 提交变更:Pull Request 工作流
3.1 优先使用 Pull Request
向 curl 提交改动有两条路径:在 GitHub 发起 pull request,或把纯补丁发到 curl-library 邮件列表。如果走邮件列表,大概率会有人帮你把补丁转成 pull request,让 CI 先完整验证再合并——并且要预期后续评审反馈会转到 GitHub 上进行。
项目强烈偏好 pull request 而非邮件补丁,原因是 PR 天然是规整的 git commit,易于合并、易于跟踪,不会淹没在邮件洪流中。
3.2 CI 会自动验证每一个 PR
每个 pull request 都会被自动测试,验证内容(见 docs/tests/CI.md)包括:
- 在 Linux、macOS、Windows、BSD 上用 clang 与 gcc、autotools 与 CMake、树内与树外构建,且无警告;
- Windows 上各受支持 MSVC 版本可构建;
- 基础代码风格规则(即 checksrc);
- 测试套件 100% 通过;
- 发布包(dist tarball)可用;
- 不同 TLS 后端与编译选项可编译并过测试。
任何一项失败都会显示红叉,提交者有责任修复;若看不懂失败原因,应提问求助。若失败是依赖服务临时不可用(如包下载服务宕机)导致的偶发失败,可以通过 push 新 commit 或 force-push 重新触发测试。评审后调整 PR 时,建议把 commit squash 起来,方便维护者看完整的更新版本。
3.3 needs-votes 标签
一个 PR 可能被维护者打上 needs-votes 标签,含义是:除满足所有其他检查外,它还需要更多“用户支持票”——可以是留言表达支持,也可以是 GitHub 上的 thumbs-up 反应。
3.4 审批与 feature window
- 若你认为 PR 已就绪却迟迟未被批准,可以主动询问;
- PR 获批后由维护者合并;如果获批后长时间未被合并,也可以主动询问“还能做什么”;
- 对新特性类 PR,合并要求 feature window 处于打开状态。从 docs/CONTRIBUTE.md 看,这通常是上一次发布 10 天之后开始、持续约三周的窗口期;窗口期提交的新特性 PR 必须等窗口打开才能合并。docs/RELEASE-PROCEDURE.md 中对应的发布流程说明(发布后 3 周/21 天内为 feature window)与这一描述相互印证;
- 若补丁按本文所有建议操作数周后仍无回应,考虑重新提交到列表,或更好——改为 pull request。
3.5 Push Access
频繁贡献者可能被授予 git 仓库的 push 权限,从而直接推送而不是走 PR/邮件。前提是先提交过多份高质量补丁。文档明确表示:如果你想申请,可以直接问。
4. Commit Message 规范
curl 项目有明确的 commit message 格式:
---- start ----
[area]: [short line describing the main effect]
-- empty line --
[full description, no wider than 72 columns that describes as much as
possible as to why this change is made, and possibly what things
it fixes and everything else that is related,
-- end --
具体要求:
- 第一行是对改动的简洁描述,应当理想地可直接作为 RELEASE NOTES 中的一行(项目根目录即有 RELEASE-NOTES 文件承接这类内容);
- 使用祈使句、现在时:change 而不是 "changed" 或 "changes";
- 首字母不大写;
- 行尾不加句号。
[area] 可以是 http2、cookies、openssl 之类,没有固定列表,但建议与相关改动使用同一个 area 以保持一致。
4.1 关键词(Keywords)
文档列出了一组用于指向相关工作、改进信息密度的关键词:
Follow-up to {shorthash}—— 本提交修复或延续某个先前 commit 时使用;若不是小而明显的修复,再加一行Ref:指向那个 commit 的 PR 或 issue,然后空一行;Bug: URL—— 指向报告来源或更相关的讨论;对 GitHub issue 则改用Fixes;Fixes #1234—— 修复某个 GitHub issue,commit 合并后 GitHub 会自动关闭该 issue;Closes #1234—— 合并某个 GitHub PR,合并后自动关闭;Ref: #1234—— 关联某个(可能已关闭的)issue 或 PR;Ref: URL—— 指向该 commit 的更多信息;若引用的是其他 bug tracker 的 bug 则用Bug:;Approved-by: John Doe—— 署名批准该 PR 的人;Authored-by: John Doe—— 署名代码原作者,仅当你无法使用git commit --author=...时才用;Signed-off-by: John Doe—— 项目不用这个,但看到了也不用费心删除;whatever-else-by:—— 署名所有协助者,尽量从Acked-by:、Assisted-by:、Co-authored-by:、Found-by:、Reported-by:、Reviewed-by:、Suggested-by:、Tested-by:中选择,保持格式一致。
署名细节同样有讲究:提交他人作品时记得用 --author;提交前确认自己 git 的 user/email 配置正确;多人参与时每人一行;不需要给自己署名(除非用了 --author 隐藏了自己的身份);header 中不要包含他人邮箱地址以免被垃圾邮件利用——除非邮箱已在先前 commit 中公开;写 {userid} on github 是可以的。
5. 版权与许可证信息的维护(REUSE 合规)
每个 PR 和 commit 都会触发名为 REUSE compliance / check 的 CI 作业,验证所有文件的 REUSE 状态 依然合规。这意味着每个文件都必须清晰声明许可证与版权:
- 首选方式是在文件内使用标准 curl 源码头(含
SPDX-License-Identifier)。仓库中几乎每个 C 文件都长这样,例如 lib/llist.c 的文件头完整声明了版权声明、许可说明并以SPDX-License-Identifier: curl收尾; - 如果无法加注释(不可注释的文件等),可以用较小的头,或把该文件的许可信息写进根目录的 REUSE.toml。该文件按 REUSE 规范声明
SPDX-PackageName = "curl",并以[[annotations]]段落批量覆盖如 RELEASE-NOTES、tests/data/ 下的测试数据、projects/Windows/ 等无法直接注释的路径,统一标注SPDX-License-Identifier = "curl"与版权持有者; - 也可以手动运行 REUSE helper tool 的
reuse lint命令自检合规状态。
6. AI 辅助贡献的明确边界
CONTRIBUTE.md 专门设有一节 “On AI use in curl”,这是贡献者必须注意的合规要点:
6.1 安全报告与其他问题
- 如果用 AI 工具发现了 curl 中的问题,必须在报告里披露这一事实;
- 报告前必须仔细复核,确认问题真实存在且行为如 AI 所述——AI 工具频繁产出不准确或虚构的结果;
- 不建议把 AI 生成的报告直接粘贴给项目:这类报告通常冗长、不切题且常带虚构细节。正确做法是:自己验证属实后,用自己的话重写报告,解释你学到的问题所在,让 AI 生成的不准确之处尽早被过滤;
- 项目对每条安全报告都会优先调查,这消耗大量时间精力;虚构的安全报告会挤占真实工作。提交伪造报告的账号会被立即封禁。
6.2 Pull Request
- 提交内容即授予项目按原样使用、并按 curl 许可证再分发的权限;确保所提交内容允许这样分发(无未许可代码)的责任在作者,这一点与是否使用 AI 无关;
- 基本判断标准是:如果别人能一眼看出贡献是 AI 辅助完成的,你还需要再下功夫;
- 项目可以接受 AI 辅助写的代码,但它仍必须遵循编码标准、写清楚、有文档、带测试用例,满足一切常规要求。
6.3 翻译
项目鼓励并欢迎借助翻译工具用非母语提交报告、文本与文档;但 AI 翻译有时会让文字带“机器味”,可考虑主动说明使用了此类工具——否则维护者可能误把翻译文本当作“AI 垃圾”而错误拒掉。
7. 贡献流程速查
| 阶段 | 关键动作 | 仓库内依据 |
|---|---|---|
| 准备 | 读内部文档、TODO、KNOWN_BUGS;邮件列表提问先读礼仪 | docs/internals/README.md、docs/MAIL-ETIQUETTE.md |
| 编码 | 遵循代码风格;新特性写新文件;一 bug 一补丁 | docs/internals/CODE_STYLE.md |
| 自查 | make checksrc;为特性补测试用例并本地跑通 |
scripts/checksrc.pl、Makefile.am、docs/tests/TEST-SUITE.md |
| 提交 | 标准头 + SPDX;无法注释的文件更新 REUSE.toml | REUSE.toml、lib/llist.c |
| PR | 按 CI 反馈修复;评审后 squash;注意 needs-votes 与 feature window |
docs/tests/CI.md、docs/RELEASE-PROCEDURE.md |
| 提交信息 | [area]: 短描述 + 72 列正文;使用 Fixes/Ref: 等关键词 |
docs/CONTRIBUTE.md |
按以上规范走完一轮贡献后持续提交高质量补丁,即可向维护者申请 push access,进入直接推送的阶段。
atomcodeClaude Code 的开源替代方案。连接任意大模型,编辑代码,运行命令,自动验证 — 全自动执行。用 Rust 构建,极致性能。 | An open-source alternative to Claude Code. Connect any LLM, edit code, run commands, and verify changes — autonomously. Built in Rust for speed. Get StartedRust0623
Hy4-previewHy4 preview 是由腾讯混元团队研发的新一代混合专家(MoE)旗舰模型。模型总参数量 770B,每个 token 激活 49B,主干共包含78层,第一层采用标准 FFN,其余 77 层均为 MoE 结构,每层包含 256 个路由专家与 1 个共享专家,每个 token 激活 top-8 路由专家及共享专家。主干之外原生内置 1 层 MTP(总参数量 10B,激活 0.7B)以支持投机解码。Python00
GLM-5.3GLM-5.3 与 GLM-5.2 使用相同的基座模型——所有提升均来自后训练。与 GLM-5.2 相比,它在复杂编程和长程任务上的表现显著提升。Jinja00
GLM-5.3-FlashGLM-5.3-Flash (320B-A18B),是GLM-5系列的首个原生多模态模型。320B总参数,能力超过GLM-5.2Jinja00
Spark-X2.5-4BSpark-X2.5-4B 旨在让强大的 AI 更实用、更高效、更易获得。在广泛日常任务中表现强劲,涵盖对话、写作、翻译、推理、编码、工具调用以及智能体工作流,并在同等规模的开源模型中取得领先成绩。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00
Spark-X2.5-1.7BSpark-X2.5-1.7B 旨在让强大的 AI 更加实用、高效且易于获取。这些模型在广泛的日常任务中表现出色,涵盖对话、写作、翻译、推理、编程、工具调用和智能体工作流,并在同等规模的开源模型中取得领先结果。Spark-X2.5 将面向效率的架构与最高 1M tokens 的原生上下文窗口相结合,并支持 200 多种语言。Python00