编写 kernel-doc 注释

Linux 内核源文件可能包含 kernel-doc 格式的结构化文档注释,用于描述代码的函数、类型和设计。当文档嵌入在源文件中时,更容易保持文档的更新。

注意

由于历史原因,kernel-doc 格式与 javadoc、gtk-doc 或 Doxygen 非常相似,但又明显不同。内核源代码包含数万个 kernel-doc 注释。请坚持使用此处描述的样式。

注意

kernel-doc 不涵盖 Rust 代码:请参阅 通用信息

kernel-doc 结构从注释中提取,并从中生成带有锚点的正确 Sphinx C 域 函数和类型描述。描述会过滤特殊的 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.
 */

您可以用上面的例子中的 unionenum 替换 struct 来描述联合体或枚举。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 域 引用。

注意

以下内容在 kernel-doc 注释中识别,在普通的 reStructuredText 文档中识别。

funcname()

函数引用。

@parameter

函数参数的名称。(无交叉引用,仅格式化。)

%CONST

常量的名称。(无交叉引用,仅格式化。)

``literal``

应按原样处理的文字块。输出将使用 等宽字体

如果您需要使用特殊的字符,否则这些字符会被 kernel-doc 脚本或 reStructuredText 解释,则此项非常有用。

如果您需要在函数描述中使用 %ph 之类的东西,则此项特别有用。

$ENVVAR

环境变量的名称。(无交叉引用,仅格式化。)

&struct name

结构体引用。

&enum name

枚举引用。

&typedef name

类型定义引用。

&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 域 文档。

概述文档注释

为了方便将源代码和注释放在一起,您可以包含自由格式的 kernel-doc 文档块,而不是用于函数、结构体、联合体、枚举或类型定义的 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 中所有已使用 EXPORT_SYMBOLEXPORT_SYMBOL_GPL 导出的函数的文档,无论是在 source 中还是在 source-pattern 指定的任何文件中。

当 kernel-doc 注释放置在头文件中,而 EXPORT_SYMBOLEXPORT_SYMBOL_GPL 紧挨着函数定义时,source-pattern 非常有用。

示例

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

.. kernel-doc:: include/net/mac80211.h
   :export: net/mac80211/*.c
internal: [源模式 ...]

包含 source 中所有 **未** 使用 EXPORT_SYMBOLEXPORT_SYMBOL_GPL 导出的函数和类型的文档,无论是在 source 中还是在 source-pattern 指定的任何文件中。

示例

.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
   :internal:
identifiers: [ 函数/类型 ...]

包含 source 中每个 函数类型 的文档。如果未指定 函数,则将包含 source 中所有函数和类型的文档。类型 可以是结构体、联合体、枚举或类型定义的标识符。

示例

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

.. kernel-doc:: lib/idr.c
   :identifiers:
no-identifiers: [ 函数/类型 ...]

排除 source 中每个 函数类型 的文档。

示例

.. kernel-doc:: lib/bitmap.c
   :no-identifiers: bitmap_parselist
functions: [ 函数/类型 ...]

这是 ‘identifiers’ 指令的别名,已被弃用。

doc: 标题

包含 source 中由 标题 标识的 DOC: 段落的文档。标题 中允许使用空格;请不要用引号括起 标题标题 仅用作段落的标识符,不包含在输出中。请确保在封闭的 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