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 <[email protected]>设置此标志可有效地停止在补丁上下文中缺少 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
仅在出现警告或错误时生成报告。较温和的检查将不包括在内。
--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 而不是带有 sizeof 乘法的 kmalloc/kzalloc。
请参阅: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。建议使用新的 vanilla-RCU 对等 API 替换旧的、具有多种风格的 RCU API。
完整的 RCU API 列表可以从内核文档中查看。
参见:https://linuxkernel.org.cn/doc/html/latest/RCU/whatisRCU.html#full-list-of-rcu-apis
- DEPRECATED_VARIABLE
EXTRA_{A,C,CPP,LD}FLAGS 已弃用,应替换为通过 commit f77bf01425b1(“kbuild: introduce ccflags-y, asflags-y and ldflags-y”)添加的新标志。
可以使用以下转换方案
EXTRA_AFLAGS -> asflags-y EXTRA_CFLAGS -> ccflags-y EXTRA_CPPFLAGS -> cppflags-y EXTRA_LDFLAGS -> ldflags-y参见
- 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: add shared variables for range check”) 添加了一些共享的 const 变量,用于代替每个源文件中的本地副本。
请考虑使用 include/linux/sysctl.h 中的共享变量替换 sysctl 范围检查值。可以使用以下转换方案
&zero -> SYSCTL_ZERO &one -> SYSCTL_ONE &int_max -> SYSCTL_INT_MAX参见
- ENOSYS
ENOSYS 表示调用了不存在的系统调用。以前,它被错误地用于对其他有效的系统调用进行无效操作之类的事情。这应该在新代码中避免。
- ENOTSUPP
ENOTSUPP 不是一个标准的错误代码,应在新补丁中避免。应使用 EOPNOTSUPP 代替。
- EXPORT_SYMBOL
EXPORT_SYMBOL 应紧跟要导出的符号。
- IN_ATOMIC
in_atomic() 不适用于驱动程序,因此任何此类使用都会报告为错误。此外,in_atomic() 通常用于确定是否允许休眠,但在此使用模型中不可靠。因此,强烈建议不要使用它。
但是,in_atomic() 对于核心内核使用是可以的。
- 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
stable 的电子邮件格式不正确。一些有效的 stable 地址选项是
对于添加版本信息,应使用以下注释样式
[email protected] # 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。
- GERRIT_CHANGE_ID
为了被 gerrit 选中,提交消息的页脚可能包含一个类似这样的 Change-Id
Change-Id: Ic8aaa0728a43936cd4c6e1ed590e01ba8f0fbf5b Signed-off-by: A. U. Thor <[email protected]>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
形式为 (foo == NULL) 或 (foo != NULL) 的 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
在用户空间中显示为消息并且可以被 grep 的带引号的字符串,不应跨多行拆分。
参见: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 列的限制,因为在一行上读取解引用标识符要容易得多。
- 尾随语句
尾随语句(例如,在任何条件语句之后)应位于下一行。例如,像这样的语句:
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]))- 避免使用 EXTERNS
函数原型不需要在 .h 文件中声明为 extern。编译器会假定它是 extern,因此没有必要声明。
- 避免使用 L 前缀
应避免使用以 .L 为前缀的局部符号名称,因为这对于汇编器具有特殊含义;符号条目不会被发出到符号表中。这可能会阻止 objtool 生成正确的展开信息。
仍然可以使用具有 STB_LOCAL 绑定的符号,并且在函数中通常仍然可以使用以 .L 为前缀的局部符号名称,但是不应使用以 .L 为前缀的局部符号名称来通过 SYM_CODE_START_LOCAL/SYM_CODE_END 来表示代码区域的开始或结束。
- BIT_MACRO
像 1 <<
这样的定义可以使用 BIT(digit)。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
可以在变量上使用段标记,而 gcc 不理解(或者至少不是开发人员打算的方式)。
static struct __initdata samsung_pll_clock exynos4_plls[nr_plls] = {不会将 exynos4_plls 放入 .initdata 段中。__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 */ 这样的注释。
- 尾随分号
宏定义不应以分号结尾。宏调用样式应与函数调用保持一致。这可以防止任何意外的代码路径。
#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
避免使用 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 会读取一个常用结构体的列表,这些结构体始终或几乎始终是常量。
可以从 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/[email protected]/
- 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/dereference 单个左值
&(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 情况有时写为 “default:;”。这会导致在 default 下面添加的新情况出现缺陷。
应该在空的 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 only 树中历史记录更清晰。
- 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
某些单词可能拼写错误。请考虑复查它们。
注释¶