编写 kernel-doc 注释¶
Linux 内核源文件可能包含 kernel-doc 格式的结构化文档注释,用于描述代码的函数、类型和设计。当文档嵌入在源文件中时,更容易保持文档的更新。
注意
由于历史原因,kernel-doc 格式表面上与 javadoc、gtk-doc 或 Doxygen 相似,但又截然不同。内核源代码包含数万条 kernel-doc 注释。请坚持此处描述的风格。
注意
kernel-doc 不涵盖 Rust 代码:请参阅 通用信息。
kernel-doc 结构从注释中提取,并从中生成带有锚点的适当的 Sphinx C Domain 函数和类型描述。这些描述会过滤掉特殊的 kernel-doc 高亮显示和交叉引用。详见下文。
每个使用 EXPORT_SYMBOL
或 EXPORT_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
)的专用部分中描述。
注意
您提供的多行描述性文本不识别换行符,因此如果您尝试很好地格式化一些文本,如
* 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
如果您提供的描述性文本的行以短语开头,后跟冒号,则每个短语都将被视为新的节标题,这可能不会产生所需的效果。
结构体、联合体和枚举文档¶
结构体、联合体和枚举 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
替换为 union
或 enum
来描述联合体或枚举。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;
};
注意
当记录嵌套的结构体或联合体时,如果结构体/联合体
foo
已命名,则其中的成员bar
应记录为@foo.bar:
当嵌套的结构体/联合体是匿名的时,其中的成员
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 注释中定义的函数和类型。只需在函数名称后添加 ()
,并在类型之前写 struct
、union
、enum
或 typedef
。例如
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_SYMBOL
或EXPORT_SYMBOL_GPL
在 source 中或在 source-pattern 指定的任何文件中导出。当 kernel-doc 注释已放置在头文件中时,source-pattern 非常有用,而
EXPORT_SYMBOL
和EXPORT_SYMBOL_GPL
位于函数定义旁边。示例
.. kernel-doc:: lib/bitmap.c :export: .. kernel-doc:: include/net/mac80211.h :export: net/mac80211/*.c
- internal: [source-pattern ...]
包含 source 中所有函数和类型的文档,这些函数和类型未使用
EXPORT_SYMBOL
或EXPORT_SYMBOL_GPL
在 source 中或在 source-pattern 指定的任何文件中导出。示例
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c :internal:
- identifiers: [ function/type ...]
包含 source 中每个 function 和 type 的文档。如果未指定 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 中每个 function 和 type 的文档。
示例
.. kernel-doc:: lib/bitmap.c :no-identifiers: bitmap_parselist
- functions: [ function/type ...]
这是“identifiers”指令的别名,已弃用。
- doc: title
包含 source 中由 title 标识的
DOC:
段落的文档。空格允许出现在 title 中;不要引用 title。title 仅用作段落的标识符,不包含在输出中。请确保在封闭的 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