Checkpatch¶
Checkpatch (scripts/checkpatch.pl) 是一个 perl 脚本,用于检查补丁中的琐碎样式违规,并可以选择性地更正它们。 Checkpatch 也可以在文件上下文中运行,而无需内核树。
Checkpatch 并不总是正确的。 你的判断优先于 checkpatch 消息。 如果你的代码在违反规则的情况下看起来更好,那么最好保持原样。
选项¶
本节将介绍 checkpatch 可以运行的选项。
用法
./scripts/checkpatch.pl [OPTION]... [FILE]...
可用选项
-q, --quiet
启用静默模式。
-v, --verbose 启用详细模式。 将输出额外的详细测试描述,以便提供有关为何显示该特定消息的信息。
--no-tree
在没有内核树的情况下运行 checkpatch。
--no-signoff
禁用 “Signed-off-by” 行检查。 签名是补丁说明末尾的简单行,用于证明你编写了它或者有权将其作为开源补丁传递。
示例
Signed-off-by: Random J Developer <random@developer.example.org>设置此标志可有效阻止补丁上下文中缺少 signed-off-by 行的消息。
--patch
将 FILE 视为补丁。 这是默认选项,无需显式指定。
--emacs
将输出设置为 emacs 编译窗口格式。 这允许 emacs 用户从编译窗口中的错误直接跳转到补丁中的违规行。
--terse
每个报告仅输出一行。
--showfile
显示差异文件位置而不是输入文件位置。
-g, --git
将 FILE 视为单个提交或 git 修订范围。
单个提交,使用
<rev>
<rev>^
<rev>~n
多个提交,使用
<rev1>..<rev2>
<rev1>...<rev2>
<rev>-<count>
-f, --file
将 FILE 视为常规源文件。 在内核中的源文件上运行 checkpatch 时,必须使用此选项。
--subjective, --strict
在 checkpatch 中启用更严格的测试。 默认情况下,作为 CHECK 发出的测试不会默认激活。 使用此标志来激活 CHECK 测试。
--list-types
checkpatch 发出的每个消息都有一个关联的 TYPE。 添加此标志以显示 checkpatch 中的所有类型。
请注意,当此标志处于活动状态时,checkpatch 不会读取输入 FILE,并且不会发出任何消息。 仅输出 checkpatch 中的类型列表。
--types TYPE(,TYPE2...)
仅显示具有给定类型的消息。
示例
./scripts/checkpatch.pl mypatch.patch --types EMAIL_SUBJECT,BRACES--ignore TYPE(,TYPE2...)
Checkpatch 将不会发出指定类型的消息。
示例
./scripts/checkpatch.pl mypatch.patch --ignore EMAIL_SUBJECT,BRACES--show-types
默认情况下,checkpatch 不显示与消息关联的类型。 设置此标志以在输出中显示消息类型。
--max-line-length=n
设置最大行长度(默认为 100)。 如果一行超过指定的长度,则会发出 LONG_LINE 消息。
消息级别对于补丁和文件上下文是不同的。 对于补丁,会发出 WARNING。 而对于文件,则发出较温和的 CHECK。 因此,对于文件上下文,还必须启用 --strict 标志。
--min-conf-desc-length=n
设置 Kconfig 条目的最小描述长度,如果更短,则发出警告。
--tab-size=n
设置制表符的空格数(默认为 8)。
--root=PATH
内核树根的 PATH。
从内核根目录外部调用 checkpatch 时,必须指定此选项。
--no-summary
禁止显示每个文件的摘要。
--mailback
仅在出现 Warnings 或 Errors 时生成报告。 较温和的 Checks 不包括在内。
--summary-file
在摘要中包含文件名。
--debug KEY=[0|1]
打开/关闭 KEY 的调试,其中 KEY 是 'values'、'possible'、'type' 和 'attr' 之一(默认为全部关闭)。
--fix
这是一个实验性功能。 如果存在可更正的错误,则会创建一个文件 <inputfile>.EXPERIMENTAL-checkpatch-fixes,其中包含已自动修复的错误。
--fix-inplace
实验性 - 类似于 --fix,但输入文件会被修复覆盖。
除非你绝对确定并且有备份,否则不要使用此标志。
--ignore-perl-version
覆盖 perl 版本的检查。 如果 perl 版本不符合指定的最小值,则在启用此标志后可能会遇到运行时错误。
--codespell
使用 codespell 字典来检查拼写错误。
--codespellfile
使用指定的 codespell 文件。 默认为 ‘/usr/share/codespell/dictionary.txt’。
--typedefsfile
从此文件读取其他类型。
--color[=WHEN]
使用颜色 ‘always’、‘never’ 或仅当输出是终端时使用 (‘auto’)。 默认为 ‘auto’。
--kconfig-prefix=WORD
将 WORD 用作 Kconfig 符号的前缀(默认为 CONFIG_)。
-h, --help, --version
显示帮助文本。
消息级别¶
checkpatch 中的消息分为三个级别。 checkpatch 中的消息级别表示错误的严重性。 它们是
ERROR
这是最严格的级别。 必须认真对待 ERROR 类型的消息,因为它们表示很可能出错的事情。
WARNING
这是下一个更严格的级别。 WARNING 类型的消息需要更仔细的审查。 但它比 ERROR 更温和。
CHECK
这是最温和的级别。 这些是可能需要考虑的事情。
类型描述¶
本节包含 checkpatch 中所有消息类型的描述。
分配样式¶
- ALLOC_ARRAY_ARGS
kcalloc 或 kmalloc_array 的第一个参数应该是元素数量。 sizeof() 作为第一个参数通常是错误的。
参见:https://linuxkernel.org.cn/doc/html/latest/core-api/memory-allocation.html
- ALLOC_SIZEOF_STRUCT
分配样式很糟糕。 一般来说,对于使用 sizeof() 获取内存大小的分配函数系列,构造如下
p = alloc(sizeof(struct foo), ...)应该为
p = alloc(sizeof(*p), ...)参见:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#allocating-memory
- ALLOC_WITH_MULTIPLY
建议使用 kmalloc_array/kcalloc 而不是 kmalloc/kzalloc 以及 sizeof 乘法。
参见:https://linuxkernel.org.cn/doc/html/latest/core-api/memory-allocation.html
API 使用¶
- ARCH_DEFINES
应尽可能避免特定于架构的定义。
- ARCH_INCLUDE_LINUX
每当包含 asm/file.h 并且 linux/file.h 存在时,如果 linux/file.h 包含 asm/file.h,则可以进行转换。 但是,情况并非总是如此(请参阅 signal.h)。 仅针对来自 arch/ 的包含项发出此消息类型。
- AVOID_BUG
应完全避免 BUG() 或 BUG_ON()。 改用 WARN() 和 WARN_ON(),并尽可能优雅地处理“不可能”的错误情况。
参见:https://linuxkernel.org.cn/doc/html/latest/process/deprecated.html#bug-and-bug-on
- CONSIDER_KSTRTO
simple_strtol()
、simple_strtoll()
、simple_strtoul()
和simple_strtoull()
函数显式忽略溢出,这可能会导致调用者出现意外结果。 相应的kstrtol()
、kstrtoll()
、kstrtoul()
和kstrtoull()
函数往往是正确的替代方法。- CONSTANT_CONVERSION
不鼓励为以下函数使用 __constant_<foo> 形式
__constant_cpu_to_be[x] __constant_cpu_to_le[x] __constant_be[x]_to_cpu __constant_le[x]_to_cpu __constant_htons __constant_ntohs在 include/uapi/ 之外使用任何这些函数都不是首选,因为当参数是常量时,使用没有 __constant_ 的函数是相同的。
在 big endian 系统中,像 __constant_cpu_to_be32(x) 和 cpu_to_be32(x) 这样的宏会扩展为相同的表达式
#define __constant_cpu_to_be32(x) ((__force __be32)(__u32)(x)) #define __cpu_to_be32(x) ((__force __be32)(__u32)(x))在 little endian 系统中,宏 __constant_cpu_to_be32(x) 和 cpu_to_be32(x) 会扩展为 __constant_swab32 和 __swab32。 __swab32 具有 __builtin_constant_p 检查
#define __swab32(x) \ (__builtin_constant_p((__u32)(x)) ? \ ___constant_swab32(x) : \ __fswab32(x))因此,它们最终会对常量进行特殊处理。 列表中的所有宏也是如此。 因此,使用 __constant_... 形式是不必要的冗长,并且在 include/uapi 之外不是首选。
参见:https://lore.kernel.org/lkml/1400106425.12666.6.camel@joe-AO725/
- DEPRECATED_API
检测到已弃用的 RCU API 的使用。 建议将旧的、具有风格的 RCU API 替换为新的 vanilla-RCU 对应 API。
可以从内核文档中查看可用 RCU API 的完整列表。
参见:https://linuxkernel.org.cn/doc/html/latest/RCU/whatisRCU.html#full-list-of-rcu-apis
- DEVICE_ATTR_FUNCTIONS
在 DEVICE_ATTR 中使用的函数名称是不寻常的。 通常,store 和 show 函数与 <attr>_store 和 <attr>_show 一起使用,其中 <attr> 是设备的命名属性变量。
考虑以下示例
static DEVICE_ATTR(type, 0444, type_show, NULL); static DEVICE_ATTR(power, 0644, power_show, power_store);函数名称最好遵循上述模式。
参见:https://linuxkernel.org.cn/doc/html/latest/driver-api/driver-model/device.html#attributes
- DEVICE_ATTR_RO
可以使用 DEVICE_ATTR_RO(name) 辅助宏而不是 DEVICE_ATTR(name, 0444, name_show, NULL);
请注意,宏会自动将 _show 附加到设备的命名属性变量,以用于 show 方法。
参见:https://linuxkernel.org.cn/doc/html/latest/driver-api/driver-model/device.html#attributes
- DEVICE_ATTR_RW
可以使用 DEVICE_ATTR_RW(name) 辅助宏而不是 DEVICE_ATTR(name, 0644, name_show, name_store);
请注意,宏会自动将 _show 和 _store 附加到设备的命名属性变量,以用于 show 和 store 方法。
参见:https://linuxkernel.org.cn/doc/html/latest/driver-api/driver-model/device.html#attributes
- DEVICE_ATTR_WO
可以使用 DEVICE_AATR_WO(name) 辅助宏而不是 DEVICE_ATTR(name, 0200, NULL, name_store);
请注意,宏会自动将 _store 附加到设备的命名属性变量,以用于 store 方法。
参见:https://linuxkernel.org.cn/doc/html/latest/driver-api/driver-model/device.html#attributes
- DUPLICATED_SYSCTL_CONST
Commit d91bff3011cf (“proc/sysctl:添加用于范围检查的共享变量”) 添加了一些共享 const 变量,以代替每个源文件中的本地副本。
考虑将 sysctl 范围检查值替换为 include/linux/sysctl.h 中的共享值。 可以使用以下转换方案
&zero -> SYSCTL_ZERO &one -> SYSCTL_ONE &int_max -> SYSCTL_INT_MAX参见
- ENOSYS
ENOSYS 表示调用了不存在的系统调用。 之前,它被错误地用于对原本有效的 syscall 执行无效操作等。 在新代码中应避免这种情况。
- ENOTSUPP
ENOTSUPP 不是标准错误代码,应在新补丁中避免使用。 应改用 EOPNOTSUPP。
参见:https://lore.kernel.org/netdev/20200510182252.GA411829@lunn.ch/
- EXPORT_SYMBOL
EXPORT_SYMBOL 应紧跟要导出的符号。
- IN_ATOMIC
in_atomic() 不适合驱动程序使用,因此任何此类使用都会报告为 ERROR。 此外,in_atomic() 通常用于确定是否允许睡眠,但在此使用模型中不可靠。 因此,强烈建议不要使用它。
但是,in_atomic() 适用于核心内核使用。
参见:https://lore.kernel.org/lkml/20080320201723.b87b3732.akpm@linux-foundation.org/
- LOCKDEP
lockdep_no_validate 类被添加为一种临时措施,以防止在将 device->sem 转换为 device->mutex 时发出警告。 不应将其用于任何其他目的。
参见:https://lore.kernel.org/lkml/1268959062.9440.467.camel@laptop/
- MALFORMED_INCLUDE
#include 语句的路径格式不正确。 发生这种情况是因为作者在路径名中意外包含了双斜杠 “//”。
- USE_LOCKDEP
基于 lockdep_assert_held() 的注释应优先于基于 spin_is_locked() 的断言
参见:https://linuxkernel.org.cn/doc/html/latest/locking/lockdep-design.html#annotations
- UAPI_INCLUDE
include/uapi 中的 #include 语句不应使用 uapi/ 路径。
- USLEEP_RANGE
应优先使用
usleep_range()
而不是udelay()
。 内核文档中提到了使用usleep_range()
的正确方法。
提交消息¶
- BAD_SIGN_OFF
signed-off-by 行不符合社区指定的标准。
- BAD_STABLE_ADDRESS_STYLE
稳定的电子邮件格式不正确。 一些有效的稳定地址选项是
1. stable@vger.kernel.org 2. stable@kernel.org要添加版本信息,应使用以下注释样式
stable@vger.kernel.org # version info- COMMIT_COMMENT_SYMBOL
git 会忽略以 “#” 开头的提交日志行作为注释。 为了解决这个问题,在日志行前面添加一个空格就足够了。
- COMMIT_MESSAGE
补丁缺少提交描述。 应添加对补丁所做更改的简要描述。
参见:https://linuxkernel.org.cn/doc/html/latest/process/submitting-patches.html#describe-your-changes
- EMAIL_SUBJECT
在主题行中命名找到问题的工具并不是很有用。 好的主题行总结了补丁带来的更改。
参见:https://linuxkernel.org.cn/doc/html/latest/process/submitting-patches.html#describe-your-changes
- FROM_SIGN_OFF_MISMATCH
作者的电子邮件与 Signed-off-by: 行中的电子邮件不匹配。 这有时可能是由于未正确配置的电子邮件客户端引起的。
由于以下任何原因,会发出此消息
- The email names do not match. - The email addresses do not match. - The email subaddresses do not match. - The email comments do not match.- MISSING_SIGN_OFF
补丁缺少 Signed-off-by 行。 应根据开发人员的原始证书添加 signed-off-by 行。
- NO_AUTHOR_SIGN_OFF
补丁的作者没有签署补丁。需要在补丁说明的结尾处添加一个简单的签名行,表明作者编写了该补丁,或者拥有将其作为开源补丁传递的权利。
- DIFF_IN_COMMIT_MSG
避免在提交信息中包含 diff 内容。这会导致当尝试应用包含变更日志和 diff 的文件时出现问题,因为 patch(1) 会尝试应用在变更日志中找到的 diff。
参考:https://lore.kernel.org/lkml/20150611134006.9df79a893e3636019ad2759e@linux-foundation.org/
- GERRIT_CHANGE_ID
为了能被 gerrit 拾取,提交信息的页脚可能包含类似以下的 Change-Id:
Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b Signed-off-by: A. U. Thor <author@example.com>提交前必须删除 Change-Id 行。
- GIT_COMMIT_ID
引用提交 ID 的正确方法是:commit <sha1 的 12+ 个字符> (“<标题行>”)
一个例子可能是
Commit e21d2170f36602ae2708 ("video: remove unnecessary platform_set_drvdata()") removed the unnecessary platform_set_drvdata(), but left the variable "dev" unused, delete it.参见:https://linuxkernel.org.cn/doc/html/latest/process/submitting-patches.html#describe-your-changes
- BAD_FIXES_TAG
Fixes: 标签格式错误或不符合社区规范。 如果标签被分成多行 (例如,在启用了自动换行的电子邮件程序中粘贴时),则可能发生这种情况。
参见:https://linuxkernel.org.cn/doc/html/latest/process/submitting-patches.html#describe-your-changes
比较风格¶
- ASSIGN_IN_IF
不要在 if 条件中使用赋值。例如
if ((foo = bar(...)) < BAZ) {应该写成
foo = bar(...); if (foo < BAZ) {- BOOL_COMPARISON
将 A 与 true 和 false 进行比较最好写成 A 和 !A。
参考:https://lore.kernel.org/lkml/1365563834.27174.12.camel@joe-AO722/
- COMPARISON_TO_NULL
与 NULL 进行比较,例如 (foo == NULL) 或 (foo != NULL) 最好写成 (!foo) 和 (foo)。
- CONSTANT_COMPARISON
应避免将常量或大写标识符放在测试的左侧。
缩进和换行¶
- CODE_INDENT
代码缩进应使用制表符而不是空格。在注释、文档和 Kconfig 之外,空格永远不用作缩进。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#indentation
- DEEP_INDENTATION
6 个或更多制表符的缩进通常表示代码缩进过度。
建议重构 if/else/for/do/while/switch 语句的过度缩进。
参考:https://lore.kernel.org/lkml/1328311239.21255.24.camel@joe2Laptop/
- SWITCH_CASE_INDENT_LEVEL
switch 应该与 case 处于相同的缩进级别。例如
switch (suffix) { case 'G': case 'g': mem <<= 30; break; case 'M': case 'm': mem <<= 20; break; case 'K': case 'k': mem <<= 10; fallthrough; default: break; }参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#indentation
- LONG_LINE
该行超过了指定的最大长度。要使用不同的最大行长度,可以在调用 checkpatch 时添加 --max-line-length=n 选项。
之前,默认行长度为 80 列。Commit bdc48fa11e46 (“checkpatch/coding-style: deprecate 80-column warning”) 将限制增加到 100 列。 这也不是一个硬性限制,并且最好尽可能保持在 80 列内。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings
- LONG_LINE_STRING
字符串在最大行长度之前开始,但超出最大行长度。要使用不同的最大行长度,可以在调用 checkpatch 时添加 --max-line-length=n 选项。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings
- LONG_LINE_COMMENT
注释在最大行长度之前开始,但超出最大行长度。要使用不同的最大行长度,可以在调用 checkpatch 时添加 --max-line-length=n 选项。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings
- SPLIT_STRING
出现在用户空间中并且可以被 grepped 的带引号的字符串不应跨越多行。
参考:https://lore.kernel.org/lkml/20120203052727.GA15035@leaf/
- MULTILINE_DEREFERENCE
像下面这样跨越多行的单个解引用标识符
struct_identifier->member[index]. member = <foo>;通常难以理解。它很容易导致拼写错误,从而使代码容易出现错误。
如果修复多行解引用导致违反 80 列规则,则可以以更简单的方式重写代码,或者如果解引用标识符的起始部分相同并在多个位置使用,则将其存储在临时变量中,并且仅在所有位置使用该临时变量。例如,如果有两个解引用标识符
member1->member2->member3.foo1; member1->member2->member3.foo2;然后将 member1->member2->member3 部分存储在临时变量中。它不仅有助于避免违反 80 列规则,还可以通过删除不必要的解引用来减小程序大小。
但是,如果上述方法都不起作用,则忽略 80 列违规,因为在单行上读取解引用标识符要容易得多。
- TRAILING_STATEMENTS
尾随语句(例如在任何条件语句之后)应该在下一行。诸如
if (x == y) break;应该为
if (x == y) break;
宏、属性和符号¶
- ARRAY_SIZE
对于查找数组中元素的数量,应优先使用 ARRAY_SIZE(foo) 宏,而不是 sizeof(foo)/sizeof(foo[0])。
该宏定义在 include/linux/kernel.h 中
#define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0]))- AVOID_EXTERNS
函数原型不需要在 .h 文件中声明为 extern。编译器会假定这一点,因此不必要。
- AVOID_L_PREFIX
应避免使用以 .L 为前缀的局部符号名称,因为这对于汇编器具有特殊含义;符号条目将不会被发出到符号表中。这会阻止 objtool 生成正确的展开信息。
仍然可以使用具有 STB_LOCAL 绑定的符号,并且通常仍然可以在函数中使用以 .L 为前缀的局部符号名称,但不应使用以 .L 为前缀的局部符号名称通过 SYM_CODE_START_LOCAL/SYM_CODE_END 来表示代码区域的开始或结束
- BIT_MACRO
诸如:1 << <数字> 的定义可以是 BIT(数字)。BIT() 宏通过 include/linux/bits.h 定义
#define BIT(nr) (1UL << (nr))- CONST_READ_MOSTLY
当变量被标记为 __read_mostly 注释时,它会向编译器发出信号,表明对该变量的访问主要是读取,很少 (但并非从不) 写入。
const __read_mostly 没有任何意义,因为 const 数据已经是只读的。因此,应删除 __read_mostly 注释。
- DATE_TIME
通常希望使用相同的工具集构建相同的源代码是可重现的,即输出始终完全相同。
内核不使用
__DATE__
和__TIME__
宏,如果使用它们,则会启用警告,因为它们可能导致非确定性构建。参考:https://linuxkernel.org.cn/doc/html/latest/kbuild/reproducible-builds.html#timestamps
- DEFINE_ARCH_HAS
ARCH_HAS_xyz 和 ARCH_HAVE_xyz 模式是错误的。
对于大型概念性功能,请改用 Kconfig 符号。对于较小的事情,如果我们有兼容性回退函数但希望体系结构能够使用优化的函数来覆盖它们,我们应该使用弱函数(适用于某些情况),或者保护它们的符号应该是我们使用的相同符号。
参考:https://lore.kernel.org/lkml/CA+55aFycQ9XJvEOsiM3txHL5bjUc8CeKWJNR_H+MiicaddB42Q@mail.gmail.com/
- DO_WHILE_MACRO_WITH_TRAILING_SEMICOLON
do {} while(0) 宏不应包含尾随分号。
- INIT_ATTRIBUTE
Const init 定义应使用 __initconst 而不是 __initdata。
同样,没有 const 的 init 定义需要单独使用 const。
- INLINE_LOCATION
inline 关键字应位于存储类和类型之间。
例如,以下代码段
inline static int example_function(void) { ... }应该为
static inline int example_function(void) { ... }- MISPLACED_INIT
可以使用 section 标记变量,但 gcc 不理解 (或者至少不是开发人员的意图)
static struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = {不会将 exynos4_plls 放入 .initdata section 中。__initdata 标记可以位于该行中的几乎任何位置,除了在 “struct” 之后。首选位置是在 “=” 符号之前(如果有),否则在尾随 “;” 之前。
参考:https://lore.kernel.org/lkml/1377655732.3619.19.camel@joe-AO722/
- MULTISTATEMENT_MACRO_USE_DO_WHILE
具有多个语句的宏应包含在 do - while 块中。以 if 开头的宏也应如此,以避免逻辑缺陷
#define macrofun(a, b, c) \ do { \ if (a == 5) \ do_this(b, c); \ } while (0)参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#macros-enums-and-rtl
- PREFER_FALLTHROUGH
使用 fallthrough; 伪关键字而不是像 /* fallthrough */ 这样的注释。
- TRAILING_SEMICOLON
宏定义不应以分号结尾。宏调用风格应与函数调用一致。这可以防止任何意外的代码路径
#define MAC do_something;如果此宏在 if else 语句中使用,例如
if (some_condition) MAC; else do_something;那么会出现编译错误,因为当宏展开时,会有两个尾随分号,因此 else 分支会被孤立。
参考:https://lore.kernel.org/lkml/1399671106.2912.21.camel@joe-AO725/
- MACRO_ARG_UNUSED
如果类似函数的宏未使用参数,则可能导致构建警告。 我们提倡使用静态内联函数来替换此类宏。 例如,对于像下面这样的宏
#define test(a) do { } while (0)会有如下警告
WARNING: Argument 'a' is not used in function-like macro.参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#macros-enums-and-rtl
- SINGLE_STATEMENT_DO_WHILE_MACRO
对于多语句宏,必须使用 do-while 循环来避免不可预测的代码路径。 do-while 循环有助于将多个语句组合成一个语句,以便类似函数的宏可以仅用作函数。
但是对于单语句宏,没有必要使用 do-while 循环。 虽然代码在语法上是正确的,但是使用 do-while 循环是多余的。 所以删除单语句宏的 do-while 循环。
- WEAK_DECLARATION
使用像 __attribute__((weak)) 或 __weak 这样的弱声明可能会产生意外的链接缺陷。 避免使用它们。
函数和变量¶
- CAMELCASE
避免使用驼峰式标识符。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#naming
- CONST_CONST
使用 const <type> const * 通常意味着写成 const <type> * const。
- CONST_STRUCT
通常来说,使用 const 是一个好主意。 Checkpatch 读取一个常用结构体的列表,这些结构体总是或几乎总是 const 的。
可以从 scripts/const_structs.checkpatch 查看现有的结构体列表。
参考:https://lore.kernel.org/lkml/alpine.DEB.2.10.1608281509480.3321@hadrien/
- EMBEDDED_FUNCTION_NAME
嵌入式函数名称不太适合使用,因为重构会导致函数重命名。 优先使用 “%s”, __func__ 到嵌入式函数名称。
请注意,这不适用于 -f (--file) checkpatch 选项,因为它依赖于提供函数名称的补丁上下文。
- FUNCTION_ARGUMENTS
发出此警告的原因有以下几种
函数声明的参数不遵循标识符名称。例如
void foo (int bar, int baz)应该更正为
void foo(int bar, int baz)函数定义的一些参数没有标识符名称。例如
void foo(int)所有参数都应具有标识符名称。
- FUNCTION_WITHOUT_ARGS
像下面这样没有参数的函数声明
int foo()应该为
int foo(void)- GLOBAL_INITIALISERS
全局变量不应显式初始化为 0(或 NULL、false 等)。你的编译器(或者更确切地说是你的加载器,它负责将相关部分归零)会自动为你执行此操作。
- INITIALISED_STATIC
静态变量不应显式初始化为零。 你的编译器(或者更确切地说是你的加载器)会自动为你执行此操作。
- MULTIPLE_ASSIGNMENTS
单行上的多个赋值会使代码变得不必要地复杂。因此,在单行上仅将值赋给单个变量,这使代码更具可读性并有助于避免拼写错误。
- RETURN_PARENTHESES
return 不是函数,因此不需要括号
return (bar);可以简单地写成
return bar;
权限¶
- DEVICE_ATTR_PERMS
DEVICE_ATTR 中使用的权限不寻常。 通常只使用三个权限 - 0644 (RW)、0444 (RO) 和 0200 (WO)。
参考:https://linuxkernel.org.cn/doc/html/latest/filesystems/sysfs.html#attributes
- EXECUTE_PERMISSIONS
源文件没有理由是可执行文件。 可以安全地删除可执行位。
- EXPORTED_WORLD_WRITABLE
导出全局可写 sysfs/debugfs 文件通常是一件坏事。 如果随意这样做,它们可能会引入严重的安全性错误。 过去,某些 debugfs 漏洞似乎允许任何本地用户将任意值写入设备寄存器 - 预计从中不会出现任何好处的情况。
参考:https://lore.kernel.org/linux-arm-kernel/cover.1296818921.git.segoon@openwall.com/
- NON_OCTAL_PERMISSIONS
权限位应使用 4 位八进制权限 (如 0700 或 0444)。 避免使用任何其他进制(如十进制)。
- SYMBOLIC_PERMS
八进制形式的权限位比它们的符号对应物更具可读性和更容易理解,因为许多命令行工具都使用这种表示法。 经验丰富的内核开发人员已经使用这些传统的 Unix 权限位数十年了,因此他们发现理解八进制表示法比符号宏更容易。 例如,阅读 S_IWUSR|S_IRUGO 比 0644 更难,这掩盖了开发人员的意图,而不是澄清它。
参考:https://lore.kernel.org/lkml/CA+55aFw5v23T-zvDZp-MmD_EYxF8WbafwwB59934FV7g21uMGQ@mail.gmail.com/
间距和括号¶
- ASSIGNMENT_CONTINUATIONS
赋值运算符不应写在行的开头,而应遵循上一行的操作数。
- BRACES
大括号的放置在样式上不正确。 首选的方法是将左大括号放在该行的末尾,并将右大括号放在开头
if (x is true) { we do y }这适用于所有非功能块。 但是,有一个特殊情况,即函数:它们在下一行的开头有左大括号,因此
int function(int x) { body of function }参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#placing-braces-and-spaces
- BRACKET_SPACE
禁止在左括号 “[” 之前使用空格。 有一些例外情况
左侧带有类型
int [] a;在切片初始化器的行首
[0...10] = 5,在花括号内
= { [0...10] = 5 }- CONCATENATED_STRING
串联的元素之间应有一个空格。 例如
printk(KERN_INFO"bar");应该为
printk(KERN_INFO "bar");- ELSE_AFTER_BRACE
else { 应该在同一行上跟随闭合块 }。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#placing-braces-and-spaces
- LINE_SPACING
当使用多个空行时,鉴于编辑器窗口可以显示的行数有限,垂直空间会被浪费。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#spaces
- OPEN_BRACE
左大括号应该在下一行跟随函数定义。 对于任何非功能块,它应该与最后一个构造位于同一行。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#placing-braces-and-spaces
- POINTER_LOCATION
当使用指针数据或返回指针类型的函数时,* 的首选用法是与数据名称或函数名称相邻,而不是与类型名称相邻。 例子
char *linux_banner; unsigned long long memparse(char *ptr, char **retptr); char *match_strdup(substring_t *s);参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#spaces
- SPACING
内核源中使用的空格样式在内核文档中进行了描述。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#spaces
- TRAILING_WHITESPACE
应始终删除尾随空格。 某些编辑器会突出显示尾随空格,并在编辑文件时导致视觉干扰。
参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#spaces
- UNNECESSARY_PARENTHESES
在以下情况下不需要括号
函数指针用法
(foo->bar)();可以是
foo->bar();
if 中的比较
if ((foo->bar) && (foo->baz)) if ((foo == bar))可以是
if (foo->bar && foo->baz) if (foo == bar)
addressof/解引用单个 Lvalues
&(foo->bar) *(foo->bar)可以是
&foo->bar *foo->bar- WHILE_AFTER_BRACE
while 应该在同一行上跟随右括号
do { ... } while(something);参考:https://linuxkernel.org.cn/doc/html/latest/process/coding-style.html#placing-braces-and-spaces
其他¶
- CONFIG_DESCRIPTION
Kconfig 符号应具有完整描述它的帮助文本。
- CORRUPTED_PATCH
补丁似乎已损坏或行已换行。 请在将补丁文件发送给维护人员之前重新生成该文件。
- CVS_KEYWORD
由于 linux 已迁移到 git,因此不再使用 CVS 标记。 因此,不应添加 CVS 样式的关键字 ($Id$, $Revision$, $Log$)。
- DEFAULT_NO_BREAK
switch default case 有时写为 “default:;”。 这可能导致添加到 default 下面的新 case 有缺陷。
应在空的 default 语句后添加 “break;” 以避免不必要的 fallthrough。
- DOS_LINE_ENDINGS
对于 DOS 格式的补丁,行的末尾有多余的 ^M 符号。 应删除这些符号。
- DT_SCHEMA_BINDING_PATCH
DT bindings 迁移到基于 json-schema 的格式,而不是自由格式的文本。
参考:https://linuxkernel.org.cn/doc/html/latest/devicetree/bindings/writing-schema.html
- DT_SPLIT_BINDING_PATCH
Devicetree bindings 应该是它们自己的补丁。 这是因为 bindings 在逻辑上独立于驱动程序实现,它们有不同的维护者(即使它们通常通过同一棵树应用),并且它使使用 git-filter-branch 创建的仅 DT 树中的历史记录更加干净。
- EMBEDDED_FILENAME
在文件中嵌入完整的文件名路径并不是特别有用,因为通常路径会被移动并变得不正确。
- FILE_PATH_CHANGES
每当添加、移动或删除文件时,MAINTAINERS 文件模式可能会不同步或过时。
因此,在这些情况下可能需要更新 MAINTAINERS。
- MEMSET
memset 的使用似乎不正确。 这可能是由于参数的顺序错误造成的。 请重新检查用法。
- NOT_UNIFIED_DIFF
补丁文件似乎不是 unified-diff 格式。 请在将补丁文件发送给维护人员之前重新生成该文件。
- PRINTF_0XDECIMAL
用 0x 前缀十进制输出是有缺陷的,应该更正。
- SPDX_LICENSE_TAG
源文件缺少或包含不正确的 SPDX 标识符标签。 Linux 内核要求所有源文件中都使用精确的 SPDX 标识符,并且在内核文档中对此进行了详尽的记录。
参考:https://linuxkernel.org.cn/doc/html/latest/process/license-rules.html
- TYPO_SPELLING
某些单词可能拼写错误。 考虑审查它们。
注释¶