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://kernel.linux.club.tw/doc/html/latest/core-api/memory-allocation.html

ALLOC_SIZEOF_STRUCT

分配樣式很糟糕。 一般來說,對於使用 sizeof() 獲取記憶體大小的分配函式系列,構造如下

p = alloc(sizeof(struct foo), ...)

應該為

p = alloc(sizeof(*p), ...)

參見:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#allocating-memory

ALLOC_WITH_MULTIPLY

建議使用 kmalloc_array/kcalloc 而不是 kmalloc/kzalloc 以及 sizeof 乘法。

參見:https://kernel.linux.club.tw/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://kernel.linux.club.tw/doc/html/latest/process/deprecated.html#bug-and-bug-on

CONSIDER_KSTRTO

simple_strtol()simple_strtoll()simple_strtoul()simple_strtoull() 函式顯式忽略溢位,這可能會導致呼叫者出現意外結果。 相應的 kstrtol()kstrtoll()kstrtoul()kstrtoull() 函式往往是正確的替代方法。

參見:https://kernel.linux.club.tw/doc/html/latest/process/deprecated.html#simple-strtol-simple-strtoll-simple-strtoul-simple-strtoull

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://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/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 執行無效操作等。 在新程式碼中應避免這種情況。

參見:https://lore.kernel.org/lkml/5eb299021dec23c1a48fa7d9f2c8b794e967766d.1408730669.git.luto@amacapital.net/

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://kernel.linux.club.tw/doc/html/latest/locking/lockdep-design.html#annotations

UAPI_INCLUDE

include/uapi 中的 #include 語句不應使用 uapi/ 路徑。

USLEEP_RANGE

應優先使用 usleep_range() 而不是 udelay()。 核心文件中提到了使用 usleep_range() 的正確方法。

註釋

BLOCK_COMMENT_STYLE

註釋樣式不正確。 多行註釋的首選樣式為

/*
* This is the preferred style
* for multi line comments.
*/

網路註釋樣式有點不同,第一行不像前者那樣為空

/* This is the preferred comment style
* for files in net/ and drivers/net/
*/

參見:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#commenting

C99_COMMENTS

不應使用 C99 樣式的單行註釋 (//)。 請改用塊註釋樣式。

參見:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#commenting

DATA_RACE

data_race() 的應用應帶有註釋,以便記錄其被認為是安全的原因。

參見:https://lore.kernel.org/lkml/20200401101714.44781-1-elver@google.com/

FSF_MAILING_ADDRESS

核心維護人員拒絕 GPL 樣板段落的新例項,該段落指示人們寫信給 FSF 以獲取 GPL 副本,因為 FSF 過去已搬遷,並且可能再次搬遷。 因此,不要撰寫有關寫信給自由軟體基金會郵件地址的段落。

參見:https://lore.kernel.org/lkml/20131006222342.GT19510@leaf/

提交訊息

BAD_SIGN_OFF

signed-off-by 行不符合社群指定的標準。

參見:https://kernel.linux.club.tw/doc/html/latest/process/submitting-patches.html#developer-s-certificate-of-origin-1-1

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://kernel.linux.club.tw/doc/html/latest/process/submitting-patches.html#describe-your-changes

EMAIL_SUBJECT

在主題行中命名找到問題的工具並不是很有用。 好的主題行總結了補丁帶來的更改。

參見:https://kernel.linux.club.tw/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 行。

參考:https://kernel.linux.club.tw/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin

NO_AUTHOR_SIGN_OFF

補丁的作者沒有簽署補丁。需要在補丁說明的結尾處新增一個簡單的簽名行,表明作者編寫了該補丁,或者擁有將其作為開源補丁傳遞的權利。

參考:https://kernel.linux.club.tw/doc/html/latest/process/submitting-patches.html#sign-your-work-the-developer-s-certificate-of-origin

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://kernel.linux.club.tw/doc/html/latest/process/submitting-patches.html#describe-your-changes

BAD_FIXES_TAG

Fixes: 標籤格式錯誤或不符合社群規範。 如果標籤被分成多行 (例如,在啟用了自動換行的電子郵件程式中貼上時),則可能發生這種情況。

參見:https://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings

LONG_LINE_STRING

字串在最大行長度之前開始,但超出最大行長度。要使用不同的最大行長度,可以在呼叫 checkpatch 時新增 --max-line-length=n 選項。

參考:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#breaking-long-lines-and-strings

LONG_LINE_COMMENT

註釋在最大行長度之前開始,但超出最大行長度。要使用不同的最大行長度,可以在呼叫 checkpatch 時新增 --max-line-length=n 選項。

參考:https://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/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://kernel.linux.club.tw/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

發出此警告的原因有以下幾種

  1. 函式宣告的引數不遵循識別符號名稱。例如

    void foo
    (int bar, int baz)
    

    應該更正為

    void foo(int bar, int baz)
    
  2. 函式定義的一些引數沒有識別符號名稱。例如

    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://kernel.linux.club.tw/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://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#placing-braces-and-spaces

BRACKET_SPACE

禁止在左括號 “[” 之前使用空格。 有一些例外情況

  1. 左側帶有型別

    int [] a;
    
  2. 在切片初始化器的行首

    [0...10] = 5,
    
  3. 在花括號內

    = { [0...10] = 5 }
    
CONCATENATED_STRING

串聯的元素之間應有一個空格。 例如

printk(KERN_INFO"bar");

應該為

printk(KERN_INFO "bar");
ELSE_AFTER_BRACE

else { 應該在同一行上跟隨閉合塊 }

參考:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#placing-braces-and-spaces

LINE_SPACING

當使用多個空行時,鑑於編輯器視窗可以顯示的行數有限,垂直空間會被浪費。

參考:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#spaces

OPEN_BRACE

左大括號應該在下一行跟隨函式定義。 對於任何非功能塊,它應該與最後一個構造位於同一行。

參考:https://kernel.linux.club.tw/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://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#spaces

SPACING

核心源中使用的空格樣式在核心文件中進行了描述。

參考:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#spaces

TRAILING_WHITESPACE

應始終刪除尾隨空格。 某些編輯器會突出顯示尾隨空格,並在編輯檔案時導致視覺干擾。

參考:https://kernel.linux.club.tw/doc/html/latest/process/coding-style.html#spaces

UNNECESSARY_PARENTHESES

在以下情況下不需要括號

  1. 函式指標用法

    (foo->bar)();
    

可以是

foo->bar();
  1. if 中的比較

    if ((foo->bar) && (foo->baz))
    if ((foo == bar))
    

可以是

if (foo->bar && foo->baz)
if (foo == bar)
  1. addressof/解引用單個 Lvalues

    &(foo->bar)
    *(foo->bar)
    

可以是

&foo->bar
*foo->bar
WHILE_AFTER_BRACE

while 應該在同一行上跟隨右括號

do {
        ...
} while(something);

參考:https://kernel.linux.club.tw/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://kernel.linux.club.tw/doc/html/latest/devicetree/bindings/writing-schema.html

DT_SPLIT_BINDING_PATCH

Devicetree bindings 應該是它們自己的補丁。 這是因為 bindings 在邏輯上獨立於驅動程式實現,它們有不同的維護者(即使它們通常透過同一棵樹應用),並且它使使用 git-filter-branch 建立的僅 DT 樹中的歷史記錄更加乾淨。

參考:https://kernel.linux.club.tw/doc/html/latest/devicetree/bindings/submitting-patches.html#i-for-patch-submitters

EMBEDDED_FILENAME

在檔案中嵌入完整的檔名路徑並不是特別有用,因為通常路徑會被移動並變得不正確。

FILE_PATH_CHANGES

每當新增、移動或刪除檔案時,MAINTAINERS 檔案模式可能會不同步或過時。

因此,在這些情況下可能需要更新 MAINTAINERS。

MEMSET

memset 的使用似乎不正確。 這可能是由於引數的順序錯誤造成的。 請重新檢查用法。

NOT_UNIFIED_DIFF

補丁檔案似乎不是 unified-diff 格式。 請在將補丁檔案傳送給維護人員之前重新生成該檔案。

PRINTF_0XDECIMAL

用 0x 字首十進位制輸出是有缺陷的,應該更正。

SPDX_LICENSE_TAG

原始檔缺少或包含不正確的 SPDX 識別符號標籤。 Linux 核心要求所有原始檔中都使用精確的 SPDX 識別符號,並且在核心文件中對此進行了詳盡的記錄。

參考:https://kernel.linux.club.tw/doc/html/latest/process/license-rules.html

TYPO_SPELLING

某些單詞可能拼寫錯誤。 考慮審查它們。