tianole/docs/agents/code-style.md

96 lines
5.0 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# Code Style
这个文档记录 agent 修改 Tianole 代码时必须遵守的代码组织和风格规则。
## 总原则
- 参考 Linux 的工程风格,但不机械照抄 Linux 的历史实现。
- 简化实现可以接受,写死架构边界、设备假设、内存布局和调用路径不接受。
- 文件按职责拆分,不按行数拆分。
- 入口文件只编排流程,不承载具体功能细节。
## Include 风格
- 公共头文件使用 `<...>`,例如 `<tianole/boot_info.h>`
- 同目录私有头文件使用 `"..."`,例如 `"file.h"`
- 不使用 `../foo.h` 这类相对 include。
- 如果一个头文件需要跨目录使用,先判断它是否应该成为公共接口。
- `include/tianole/` 放尽量架构无关的共享接口。
- `arch/<arch>/include/` 放架构公开接口。
## 文件组织
- 长文件不是问题,职责混乱才是问题。
- 一个文件可以较长,但必须代表一个清晰子系统、算法或驱动边界。
- 不为了降低行数拆出 `utils.c`、`helpers.c` 这类无边界文件。
- 按职责、生命周期、所有权和调用边界拆分。
- `kernel/main.c`、`boot/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`
- 避免 `temp`、`tmp` 这类临时语义进入函数名、类型名和长期变量名。
- 一次性局部变量也应尽量使用具体含义命名。
- 名字应表达长期职责,不表达当前实现的临时状态。
## 注释
- 注释优先解释硬件约束、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`,只增加当前内核实际使用的值。