tianole/docs/agents/code-style.md

5.3 KiB
Raw Blame History

Code Style

这个文档记录 agent 修改 Tianole 代码时必须遵守的代码组织和风格规则。

总原则

  • 参考 Linux 的工程风格,但不机械照抄 Linux 的历史实现。
  • 简化实现可以接受,写死架构边界、设备假设、内存布局和调用路径不接受。
  • 文件按职责拆分,不按行数拆分。
  • 入口文件只编排流程,不承载具体功能细节。

Include 风格

  • 公共头文件使用 <...>,例如 <tianole/boot_info.h>
  • 同目录私有头文件使用 "...",例如 "file.h"
  • 不使用 ../foo.h 这类相对 include。
  • 如果一个头文件需要跨目录使用,先判断它是否应该成为公共接口。
  • include/tianole/ 放尽量架构无关的共享接口。
  • arch/<arch>/include/ 放架构公开接口。

文件组织

  • 长文件不是问题,职责混乱才是问题。
  • 一个文件可以较长,但必须代表一个清晰子系统、算法或驱动边界。
  • 不为了降低行数拆出 utils.chelpers.c 这类无边界文件。
  • 按职责、生命周期、所有权和调用边界拆分。
  • kernel/main.cboot/main.c 这类入口文件应保持短,只串联阶段。
  • mm/ 是顶层内存管理子系统目录,不放在 kernel/mm/ 下。
  • 顶层目录参考 docs/agents/linux-layout.md;可以预留目录,但不要放临时代码。

命名

  • 内部 C API 不加 tianole_ 前缀。
  • 架构目录内部不要重复架构名前缀;例如 arch/x86/kernel/ 内使用 gdt_init(),不要写成 x86_gdt_init()
  • 跨通用层暴露的架构入口使用 arch_ 前缀,例如 arch_traps_init()
  • 描述硬件规格的文档文字可以写 x86_64,但代码文件名和内部符号不需要反复带 x86
  • 避免 temptmp 这类临时语义进入函数名、类型名和长期变量名。
  • 一次性局部变量也应尽量使用具体含义命名。
  • 名字应表达长期职责,不表达当前实现的临时状态。

注释

  • 注释优先解释硬件约束、ABI 决策、内存所有权、并发语义和不明显的不变量。
  • 不写重复描述简单代码行为的注释。
  • 如果代码依赖硬件手册、启动协议、调用顺序或特殊寄存器状态,应写明约束。
  • 如果一个实现是临时简化,应写清楚后续替换边界,而不是写成永久接口。
  • 公共头文件 include/tianole/*.h 中的函数声明必须使用 Linux kernel-doc 风格块注释。
  • 公共结构体、枚举、typedef 和长期宏常量也必须使用 kernel-doc 风格块注释。
  • 公共函数注释至少说明函数职责、关键参数、返回值或副作用;不要只复述函数名。
  • 公共类型注释要说明字段含义、所有权、生命周期或并发约束。
  • 公共宏注释要说明它代表的协议常量、标志位或长期 ABI 含义。
  • 公共函数声明和前一个声明/注释块之间必须留一个空行,避免 API 挤在一起。
  • 私有 static 小函数不要求每个都写函数头注释;只有逻辑、数据流、锁语义或硬件约束不明显时才写。
  • 多行注释要控制行宽,优先写职责、数据流和调用约束,而不是描述每一行代码。

C 格式

  • 使用 .clang-format 作为当前格式化规则。
  • 使用 tab 缩进。
  • 函数左花括号另起一行。
  • if/for/while 左花括号留在行尾。
  • 文本文件使用 LF 行尾。

构建文件

  • Makefile 只做总控和通用规则。
  • 架构配置放在 arch/<arch>/Makefile
  • 目录自己的源文件列表放在对应目录的 Makefile
  • 顶层子系统目录可以有自己的 Makefile,例如 mm/Makefile
  • 不新增独立 mk/ 目录,除非后续有明确且无法避免的理由。

脚本组织

  • scripts/check.sh 是本地和 CI 共用的检查入口,只做编排。
  • 可独立执行的检查放在 scripts/checks/
  • 多个检查共享的函数放在 scripts/lib/
  • 不把所有检查逻辑持续堆进 scripts/check.sh
  • 项目结构规则放在 scripts/tools/check_structure.py,由 scripts/checks/structure.sh 调用;优先用宿主 Linux/LLVM 工具实现底层检查,把 Tianole 自己的目录和 include 约束固化在轻量 Python 工具里。
  • 启动阶段内核自测集中放在 kernel/selftest/,不要散落在具体实现目录里。

验证

  • 新增或大改 C/H 文件后运行 clang-format
  • 提交前至少运行 scripts/check.sh
  • 如果只是文档修改,至少运行 git diff --check

错误码

  • 可恢复的内核内部错误优先返回 Linux 风格的负 errno例如 -EINVAL-ENOMEM-ENOENT-EBUSY-EEXIST-ETIMEDOUT
  • 不要用裸 -1 表达多个失败原因;调用者需要能区分输入错误、资源耗尽、 对象已存在和超时。
  • 不要直接返回 -22 这类负数字面量;使用 -EINVAL 这类符号化 errno 结构检查会拒绝裸负数返回。
  • errno 常量放在 include/tianole/errno.h,只增加当前内核实际使用的值。

调度状态

  • 线程状态转换必须通过 kernel/sched/sched.h 中的 helper 完成。
  • 不要在调度实现或其他子系统里直接写 thread->state = ...;结构检查会拒绝 这种写法。
  • 新增状态或转换规则时,必须同步更新状态转换 helper 和 scheduler selftest。