編寫 kernel-doc 註釋

Linux 核心原始檔可能包含 kernel-doc 格式的結構化文件註釋,用於描述程式碼的函式、型別和設計。當文件嵌入在原始檔中時,更容易保持文件的更新。

注意

由於歷史原因,kernel-doc 格式表面上與 javadoc、gtk-doc 或 Doxygen 相似,但又截然不同。核心原始碼包含數萬條 kernel-doc 註釋。請堅持此處描述的風格。

注意

kernel-doc 不涵蓋 Rust 程式碼:請參閱 通用資訊

kernel-doc 結構從註釋中提取,並從中生成帶有錨點的適當的 Sphinx C Domain 函式和型別描述。這些描述會過濾掉特殊的 kernel-doc 高亮顯示和交叉引用。詳見下文。

每個使用 EXPORT_SYMBOLEXPORT_SYMBOL_GPL 匯出到可載入模組的函式都應該有一個 kernel-doc 註釋。標頭檔案中打算被模組使用的函式和資料結構也應該有 kernel-doc 註釋。

為其他核心檔案可見的外部函式(未標記為 static)提供 kernel-doc 格式的文件也是一種好的做法。我們還建議為私有(檔案 static)例程提供 kernel-doc 格式的文件,以保持核心原始碼佈局的一致性。這是較低的優先順序,由該核心原始檔的維護者自行決定。

如何格式化 kernel-doc 註釋

開頭的註釋標記 /** 用於 kernel-doc 註釋。kernel-doc 工具將提取以此方式標記的註釋。註釋的其餘部分格式化為普通的多行註釋,左側有一列星號,以單獨一行的 */ 結尾。

函式和型別的 kernel-doc 註釋應放置在被描述的函式或型別之前,以最大限度地提高更改程式碼的人員也更改文件的機會。概述 kernel-doc 註釋可以放置在頂層縮排的任何位置。

可以使用增加詳細程度且不生成實際輸出的 kernel-doc 工具來驗證文件註釋的正確格式。例如

scripts/kernel-doc -v -none drivers/foo/bar.c

當請求執行額外的 gcc 檢查時,核心構建會驗證文件格式

make W=n

函式文件

函式和類函式宏 kernel-doc 註釋的一般格式是

/**
 * function_name() - Brief description of function.
 * @arg1: Describe the first argument.
 * @arg2: Describe the second argument.
 *        One can provide multiple line descriptions
 *        for arguments.
 *
 * A longer description, with more discussion of the function function_name()
 * that might be useful to those using or modifying it. Begins with an
 * empty comment line, and may include additional embedded empty
 * comment lines.
 *
 * The longer description may have multiple paragraphs.
 *
 * Context: Describes whether the function can sleep, what locks it takes,
 *          releases, or expects to be held. It can extend over multiple
 *          lines.
 * Return: Describe the return value of function_name.
 *
 * The return value description can also have multiple paragraphs, and should
 * be placed at the end of the comment block.
 */

函式名後面的簡短描述可以跨越多行,並以引數描述、空白註釋行或註釋塊的結尾結束。

函式引數

每個函式引數都應按順序描述,緊隨函式簡短描述之後。不要在函式描述和引數之間,或引數之間留空行。

每個 @argument: 描述可以跨越多行。

注意

如果 @argument 描述有多行,則描述的延續應從與前一行相同的列開始

* @argument: some long description
*            that continues on next lines

* @argument:
*         some long description
*         that continues on next lines

如果函式有可變數量的引數,則應以 kernel-doc 表示法將其描述為

* @...: description

函式上下文

應該在名為 Context 的部分中描述可以呼叫函式的上下文。這應包括函式是否休眠或可以從中斷上下文中呼叫,以及它獲取、釋放和期望其呼叫者持有的鎖。

示例

* Context: Any context.
* Context: Any context. Takes and releases the RCU lock.
* Context: Any context. Expects <lock> to be held by caller.
* Context: Process context. May sleep if @gfp flags permit.
* Context: Process context. Takes and releases <mutex>.
* Context: Softirq or process context. Takes and releases <lock>, BH-safe.
* Context: Interrupt context.

返回值

返回值(如果有)應在名為 Return(或 Returns)的專用部分中描述。

注意

  1. 您提供的多行描述性文字識別換行符,因此如果您嘗試很好地格式化一些文字,如

    * Return:
    * %0 - OK
    * %-EINVAL - invalid argument
    * %-ENOMEM - out of memory
    

    這將全部一起執行併產生

    Return: 0 - OK -EINVAL - invalid argument -ENOMEM - out of memory
    

    因此,為了產生所需的換行符,您需要使用 ReST 列表,例如

    * Return:
    * * %0            - OK to runtime suspend the device
    * * %-EBUSY       - Device should not be runtime suspended
    
  2. 如果您提供的描述性文字的行以短語開頭,後跟冒號,則每個短語都將被視為新的節標題,這可能不會產生所需的效果。

結構體、聯合體和列舉文件

結構體、聯合體和列舉 kernel-doc 註釋的一般格式是

/**
 * struct struct_name - Brief description.
 * @member1: Description of member1.
 * @member2: Description of member2.
 *           One can provide multiple line descriptions
 *           for members.
 *
 * Description of the structure.
 */

您可以將上述示例中的 struct 替換為 unionenum 來描述聯合體或列舉。member 用於表示結構體和聯合體成員名稱以及列舉中的列舉。

結構體名稱後面的簡短描述可以跨越多行,並以成員描述、空白註釋行或註釋塊的結尾結束。

成員

結構體、聯合體和列舉的成員應以與函式引數相同的方式記錄;它們緊隨簡短描述之後,並且可以是多行的。

在結構體或聯合體描述中,您可以使用 private:public: 註釋標記。位於 private: 區域內的結構體欄位不會在生成的輸出文件中列出。

private:public: 標記必須緊跟在 /* 註釋標記之後開始。它們可以選擇在 : 和結尾的 */ 標記之間包含註釋。

示例

/**
 * struct my_struct - short description
 * @a: first member
 * @b: second member
 * @d: fourth member
 *
 * Longer description
 */
struct my_struct {
    int a;
    int b;
/* private: internal use only */
    int c;
/* public: the next one is public */
    int d;
};

巢狀的結構體/聯合體

可以記錄巢狀的結構體和聯合體,例如

/**
 * struct nested_foobar - a struct with nested unions and structs
 * @memb1: first member of anonymous union/anonymous struct
 * @memb2: second member of anonymous union/anonymous struct
 * @memb3: third member of anonymous union/anonymous struct
 * @memb4: fourth member of anonymous union/anonymous struct
 * @bar: non-anonymous union
 * @bar.st1: struct st1 inside @bar
 * @bar.st2: struct st2 inside @bar
 * @bar.st1.memb1: first member of struct st1 on union bar
 * @bar.st1.memb2: second member of struct st1 on union bar
 * @bar.st2.memb1: first member of struct st2 on union bar
 * @bar.st2.memb2: second member of struct st2 on union bar
 */
struct nested_foobar {
  /* Anonymous union/struct*/
  union {
    struct {
      int memb1;
      int memb2;
    };
    struct {
      void *memb3;
      int memb4;
    };
  };
  union {
    struct {
      int memb1;
      int memb2;
    } st1;
    struct {
      void *memb1;
      int memb2;
    } st2;
  } bar;
};

注意

  1. 當記錄巢狀的結構體或聯合體時,如果結構體/聯合體 foo 已命名,則其中的成員 bar 應記錄為 @foo.bar:

  2. 當巢狀的結構體/聯合體是匿名的時,其中的成員 bar 應記錄為 @bar:

行內成員文件註釋

結構體成員也可以在定義中以內聯方式記錄。有兩種樣式,單行註釋,其中開頭 /** 和結尾 */ 都在同一行上,以及多行註釋,其中它們各自位於自己的行上,就像所有其他 kernel-doc 註釋一樣

/**
 * struct foo - Brief description.
 * @foo: The Foo member.
 */
struct foo {
      int foo;
      /**
       * @bar: The Bar member.
       */
      int bar;
      /**
       * @baz: The Baz member.
       *
       * Here, the member description may contain several paragraphs.
       */
      int baz;
      union {
              /** @foobar: Single line description. */
              int foobar;
      };
      /** @bar2: Description for struct @bar2 inside @foo */
      struct {
              /**
               * @bar2.barbar: Description for @barbar inside @foo.bar2
               */
              int barbar;
      } bar2;
};

Typedef 文件

typedef kernel-doc 註釋的一般格式是

/**
 * typedef type_name - Brief description.
 *
 * Description of the type.
 */

也可以記錄帶有函式原型的 Typedef

/**
 * typedef type_name - Brief description.
 * @arg1: description of arg1
 * @arg2: description of arg2
 *
 * Description of the type.
 *
 * Context: Locking context.
 * Returns: Meaning of the return value.
 */
 typedef void (*type_name)(struct v4l2_ctrl *arg1, void *arg2);

類物件宏文件

類物件宏與類函式宏不同。它們的區別在於宏名稱是否緊跟一個左括號('(')表示類函式宏,而類物件宏則不跟括號。

scripts/kernel-doc 將類函式宏像函式一樣處理。它們可以有一個引數列表。類物件宏沒有引數列表。

類物件宏 kernel-doc 註釋的一般格式是

/**
 * define object_name - Brief description.
 *
 * Description of the object.
 */

示例

/**
 * define MAX_ERRNO - maximum errno value that is supported
 *
 * Kernel pointers have redundant information, so we can use a
 * scheme where we can return either an error code or a normal
 * pointer with the same return value.
 */
#define MAX_ERRNO     4095

示例

/**
 * define DRM_GEM_VRAM_PLANE_HELPER_FUNCS - \
 *    Initializes struct drm_plane_helper_funcs for VRAM handling
 *
 * This macro initializes struct drm_plane_helper_funcs to use the
 * respective helper functions.
 */
#define DRM_GEM_VRAM_PLANE_HELPER_FUNCS \
      .prepare_fb = drm_gem_vram_plane_helper_prepare_fb, \
      .cleanup_fb = drm_gem_vram_plane_helper_cleanup_fb

高亮顯示和交叉引用

以下特殊模式在 kernel-doc 註釋描述性文字中被識別,並轉換為適當的 reStructuredText 標記和 Sphinx C Domain 引用。

注意

以下內容在 kernel-doc 註釋中識別,在普通的 reStructuredText 文件中識別。

funcname()

函式引用。

@parameter

函式引數的名稱。(沒有交叉引用,只有格式化。)

%CONST

常量的名稱。(沒有交叉引用,只有格式化。)

``literal``

應按原樣處理的文字塊。輸出將使用 等寬字型

如果您需要使用特殊字元,否則這些字元會被 kernel-doc 指令碼或 reStructuredText 解釋,這將非常有用。

如果您需要在函式描述中使用類似 %ph 的內容,這將特別有用。

$ENVVAR

環境變數的名稱。(沒有交叉引用,只有格式化。)

&struct name

結構體引用。

&enum name

列舉引用。

&typedef name

Typedef 引用。

&struct_name->member&struct_name.member

結構體或聯合體成員引用。交叉引用將指向結構體或聯合體定義,而不是直接指向成員。

&name

通用型別引用。最好使用上面描述的完整引用。這主要用於遺留註釋。

從 reStructuredText 交叉引用

無需額外的語法即可從 reStructuredText 文件交叉引用 kernel-doc 註釋中定義的函式和型別。只需在函式名稱後新增 (),並在型別之前寫 structunionenumtypedef。例如

See foo().
See struct foo.
See union bar.
See enum baz.
See typedef meh.

但是,如果您想在交叉引用連結中使用自定義文字,可以透過以下語法實現

See :c:func:`my custom link text for function foo <foo>`.
See :c:type:`my custom link text for struct bar <bar>`.

有關更多詳細資訊,請參閱 Sphinx C Domain 文件。

概述文件註釋

為了便於將原始碼和註釋放在一起,您可以包含 kernel-doc 文件塊,這些文件塊是自由格式的註釋,而不是函式、結構體、聯合體、列舉或 typedef 的 kernel-doc。例如,這可以用於驅動程式或庫程式碼的操作理論。

這是透過使用帶有節標題的 DOC: 節關鍵字來完成的。

概述或高階文件註釋的一般格式是

/**
 * DOC: Theory of Operation
 *
 * The whizbang foobar is a dilly of a gizmo. It can do whatever you
 * want it to do, at any time. It reads your mind. Here's how it works.
 *
 * foo bar splat
 *
 * The only drawback to this gizmo is that is can sometimes damage
 * hardware, software, or its subject(s).
 */

DOC: 後面的標題充當原始檔中的標題,也充當提取文件註釋的識別符號。因此,標題在檔案中必須是唯一的。

包含 kernel-doc 註釋

可以使用專用的 kernel-doc Sphinx 指令擴充套件將文件註釋包含在任何 reStructuredText 文件中。

kernel-doc 指令的格式為

.. kernel-doc:: source
   :option:

source 是指向原始檔的路徑,相對於核心原始碼樹。支援以下指令選項

export: [source-pattern ...]

包含 source 中所有函式的文件,這些函式已使用 EXPORT_SYMBOLEXPORT_SYMBOL_GPLsource 中或在 source-pattern 指定的任何檔案中匯出。

當 kernel-doc 註釋已放置在標頭檔案中時,source-pattern 非常有用,而 EXPORT_SYMBOLEXPORT_SYMBOL_GPL 位於函式定義旁邊。

示例

.. kernel-doc:: lib/bitmap.c
   :export:

.. kernel-doc:: include/net/mac80211.h
   :export: net/mac80211/*.c
internal: [source-pattern ...]

包含 source 中所有函式和型別的文件,這些函式和型別使用 EXPORT_SYMBOLEXPORT_SYMBOL_GPLsource 中或在 source-pattern 指定的任何檔案中匯出。

示例

.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
   :internal:
identifiers: [ function/type ...]

包含 source 中每個 functiontype 的文件。如果未指定 function,則將包含 source 中所有函式和型別的文件。type 可以是結構體、聯合體、列舉或 typedef 識別符號。

示例

.. kernel-doc:: lib/bitmap.c
   :identifiers: bitmap_parselist bitmap_parselist_user

.. kernel-doc:: lib/idr.c
   :identifiers:
no-identifiers: [ function/type ...]

排除 source 中每個 functiontype 的文件。

示例

.. kernel-doc:: lib/bitmap.c
   :no-identifiers: bitmap_parselist
functions: [ function/type ...]

這是“identifiers”指令的別名,已棄用。

doc: title

包含 source 中由 title 標識的 DOC: 段落的文件。空格允許出現在 title 中;不要引用 titletitle 僅用作段落的識別符號,不包含在輸出中。請確保在封閉的 reStructuredText 文件中有一個適當的標題。

示例

.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
   :doc: High Definition Audio over HDMI and Display Port

如果沒有選項,kernel-doc 指令將包含來自原始檔的所有文件註釋。

kernel-doc 擴充套件包含在核心原始碼樹中,位於 Documentation/sphinx/kerneldoc.py。在內部,它使用 scripts/kernel-doc 指令碼從原始碼中提取文件註釋。

如何使用 kernel-doc 生成 man 手冊頁

如果您只想使用 kernel-doc 生成 man 手冊頁,您可以從核心 git 樹中執行此操作

$ scripts/kernel-doc -man \
  $(git grep -l '/\*\*' -- :^Documentation :^tools) \
  | scripts/split-man.pl /tmp/man

一些舊版本的 git 不支援某些路徑排除的語法變體。以下命令之一可能適用於這些版本

$ scripts/kernel-doc -man \
  $(git grep -l '/\*\*' -- . ':!Documentation' ':!tools') \
  | scripts/split-man.pl /tmp/man

$ scripts/kernel-doc -man \
  $(git grep -l '/\*\*' -- . ":(exclude)Documentation" ":(exclude)tools") \
  | scripts/split-man.pl /tmp/man