本文档翻译自sched-eevdf.rst,翻译时文件的最新提交是23a0bc28515934ed081169257f5b76167f07df4a doc-guide: kernel-doc: document Returns: spelling。大部分借助于ChatGPT翻译,仅作为我个人的参考,如果你想查阅,建议看英文文档,因为我不确定我记录的中文翻译是否完整和正确。
Kernel-doc 注释
Linux 内核源文件可能包含 kernel-doc 格式的结构化文档注释,用于描述函数、类型和代码设计。当文档嵌入到源文件中时,更容易保持其最新。
Note
kernel-doc 格式看似与 javadoc、gtk-doc 或 Doxygen 相似,但由于历史原因,实际上有显著不同。内核源代码包含成千上万的 kernel-doc 注释。请坚持遵循此处描述的样式。
Note
kernel-doc 不涵盖 Rust 代码:请参阅 Documentation/rust/general-information.rst。
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
工具,以验证文档注释的正确格式。例如:
scripts/kernel-doc -v -none drivers/foo/bar.c
当请求执行额外的 gcc 检查时,内核构建将验证文档格式:
make W=n
函数和类似宏的 kernel-doc 注释的一般格式为:
/**
* function_name() - 函数的简要描述。
* @arg1: 描述第一个参数。
* @arg2: 描述第二个参数。
* 可以为参数提供多行描述。
*
* 对 function_name() 函数进行更长的描述,讨论其使用或修改时的有用信息。以一个空的注释行开头,并可以包括额外的嵌入式空注释行。
*
* 更长的描述可以包含多个段落。
*
* Context: 上下文:描述函数是否会休眠,它获取、释放或期望持有的锁。这部分可以跨多行。
* Return: 描述 function_name 的返回值。
*
* 返回值的描述也可以包含多个段落,并应放在注释块的末尾。
*/
紧随函数名后的简要描述可以跨多行,结束于参数描述、空的注释行或注释块的结尾。
每个函数参数应按顺序描述,紧跟在简短的函数描述之后。不要在函数描述与参数之间,或参数之间留空行。
每个 @argument:
描述可以跨多行。
Note
如果 @argument
的描述有多行,描述的续行应与上一行保持相同的列对齐:
* @argument: 一些长描述
* 继续在接下来的几行中
或者:
* @argument:
* 一些长描述
* 继续在接下来的几行中
如果一个函数有可变数量的参数,应按 kernel-doc 记法书写描述:
* @...: 描述
函数可以被调用的上下文应在名为 Context
的部分中描述。这应包括函数是否休眠或可以从中断上下文中调用,以及它获取、释放和期望由调用者持有的锁。
示例:
* Context: 任何上下文。
* Context: 任何上下文。获取并释放 RCU 锁。
* Context: 任何上下文。期望 <lock> 由调用者持有。
* Context: 进程上下文。如果 @gfp 标志允许,可能会休眠。
* Context: 进程上下文。获取并释放 <mutex>。
* Context: 软中断或进程上下文。获取并释放 <lock>,BH 安全。
* Context: 中断上下文。
如果有返回值,应在专门的部分中描述,部分名称为 Return
(或 Returns
)。
Note
- Return:
- %0 - OK
- %-EINVAL - 无效参数
- %-ENOMEM - 内存不足
这些文本将会连在一起,产生如下结果:
返回: 0 - OK -EINVAL - 无效参数 -ENOMEM - 内存不足
因此,为了产生所需的换行,你需要使用 ReST 列表,例如:
* Return: * * %0 - 设备可以进行运行时挂起 * * %-EBUSY - 设备不应进行运行时挂起
结构、联合和枚举 kernel-doc 注释的一般格式为:
/**
* struct struct_name - 简短描述。
* @member1: 对 member1 的描述。
* @member2: 对 member2 的描述。
* 可以为成员提供多行描述。
*
* 对该结构的描述。
*/
在上面的示例中,您可以用 union
或 enum
替换 struct
来描述联合或枚举。member
用来表示结构体和联合体成员名以及枚举中的枚举项。
结构名称后的简短描述可以跨多行,并以成员描述、空的注释行或注释块的结束为止。
结构体、联合体和枚举的成员应与函数参数的文档相同;它们紧随简短描述之后,并且可以是多行的。
在结构体或联合体描述中,您可以使用 private:
和 public:
注释标签。位于 private:
区域内的结构字段不会在生成的输出文档中列出。
private:
和 public:
标签必须紧随 /*
注释标记之后开始。它们可以选择性地在 :
和结束的 */
标记之间包含注释。
示例:
/**
* struct my_struct - 简短描述
* @a: 第一个成员
* @b: 第二个成员
* @d: 第四个成员
*
* 更长的描述
*/
struct my_struct {
int a;
int b;
/* private: 仅供内部使用 */
int c;
/* public: 下一个是公有的 */
int d;
};
可以为嵌套的结构体和联合体编写文档,例如:
/**
* struct nested_foobar - 一个带有嵌套联合体和结构体的结构
* @memb1: 匿名联合体/结构体的第一个成员
* @memb2: 匿名联合体/结构体的第二个成员
* @memb3: 匿名联合体/结构体的第三个成员
* @memb4: 匿名联合体/结构体的第四个成员
* @bar: 非匿名联合体
* @bar.st1: 联合体 bar 中的结构体 st1
* @bar.st2: 联合体 bar 中的结构体 st2
* @bar.st1.memb1: 联合体 bar 中结构体 st1 的第一个成员
* @bar.st1.memb2: 联合体 bar 中结构体 st1 的第二个成员
* @bar.st2.memb1: 联合体 bar 中结构体 st2 的第一个成员
* @bar.st2.memb2: 联合体 bar 中结构体 st2 的第二个成员
*/
struct nested_foobar {
/* 匿名联合体/结构体 */
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;
};
Note
foo
有名字,里面的成员 bar
应当写为 @foo.bar:
bar
应当写为 @bar:
结构体成员也可以在定义中进行行内文档编写。有两种风格,一种是单行注释,开头的 /**
和结尾的 */
在同一行,另一种是多行注释,它们分别位于各自的行上,像其他所有的 kernel-doc 注释一样:
/**
* struct foo - 简短描述。
* @foo: Foo 成员。
*/
struct foo {
int foo;
/**
* @bar: Bar 成员。
*/
int bar;
/**
* @baz: Baz 成员。
*
* 此处,成员描述可以包含多个段落。
*/
int baz;
union {
/** @foobar: 单行描述。 */
int foobar;
};
/** @bar2: @foo 内部结构体 @bar2 的描述 */
struct {
/**
* @bar2.barbar: @foo.bar2 内部 @barbar 的描述
*/
int barbar;
} bar2;
};
类型定义 kernel-doc 注释的一般格式为:
/**
* typedef type_name - 简短描述。
*
* 类型的描述。
*/
带有函数原型的类型定义也可以进行文档编写:
/**
* typedef type_name - 简短描述。
* @arg1: 对 arg1 的描述
* @arg2: 对 arg2 的描述
*
* 类型的描述。
*
* 上下文: 锁上下文。
* 返回: 返回值的含义。
*/
typedef void (*type_name)(struct v4l2_ctrl *arg1, void *arg2);
类似对象的宏与类似函数的宏不同。它们的区别在于宏名后是否紧跟一个左括号 ('(')。如果是类似函数的宏,会紧跟左括号,否则就是类似对象的宏。
类似函数的宏由 scripts/kernel-doc
处理。它们可能有一个参数列表。而类似对象的宏没有参数列表。
类似对象的宏 kernel-doc 注释的一般格式为:
/**
* define object_name - 简短描述。
*
* 对该对象的描述。
*/
示例:
/**
* define MAX_ERRNO - 支持的最大 errno 值
*
* 内核指针有冗余信息,因此我们可以使用一种方案,其中返回值可以是错误码或正常指针。
*/
#define MAX_ERRNO 4095
示例:
/**
* define DRM_GEM_VRAM_PLANE_HELPER_FUNCS - \
* 初始化用于 VRAM 处理的 struct drm_plane_helper_funcs
*
* 此宏初始化 struct drm_plane_helper_funcs 以使用相应的辅助函数。
*/
#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
类型定义引用。
&struct_name->member
或 &struct_name.member
结构体或联合体成员引用。交叉引用将指向结构体或联合体定义,而不是直接指向成员。
&name
泛型类型引用。建议优先使用上面描述的完整引用。这主要用于遗留注释。
无需额外语法即可从 reStructuredText 文档中交叉引用 kernel-doc 注释中定义的函数和类型。 只需以 ()
结尾函数名,并在类型前写上 struct
、union
、enum
或 typedef
。 例如:
参见 foo()。
参见 struct foo。
参见 union bar。
参见 enum baz。
参见 typedef meh。
但是,如果需要在交叉引用链接中使用自定义文本,可以通过以下语法完成:
参见 :c:func:`函数 foo 的自定义链接文本 <foo>`。
参见 :c:type:`结构体 bar 的自定义链接文本 <bar>`。
有关更多详细信息,请参阅 Sphinx C Domain 文档。
为了便于源代码和注释靠得更近,你可以包含 kernel-doc 文档块,这些块是自由格式的注释,而不是用于函数、结构体、联合体、枚举或类型定义的 kernel-doc。这可以用于例如驱动程序或库代码的操作理论等内容。
这是通过使用 DOC:
部分关键字和部分标题来实现的。
概述或高层文档注释的一般格式是:
/**
* DOC: 操作理论
*
* whizbang foobar 是一个神奇的小玩意。它可以随时做你想做的任何事情。它能读取你的思想。以下是它的工作原理。
*
* foo bar splat
*
* 这个小玩意唯一的缺点是,它有时会损坏硬件、软件或其目标。
*/
DOC:
后面的标题在源文件中充当标题,同时也是提取文档注释的标识符。因此,标题在文件中必须唯一。
可以使用专用的 kernel-doc Sphinx 指令扩展在任何 reStructuredText 文档中包含文档注释。
kernel-doc 指令的格式为:
.. kernel-doc:: source
:option:
source 是源文件的路径,相对于内核源代码树。支持以下指令选项:
包含 source 中使用 EXPORT_SYMBOL
或 EXPORT_SYMBOL_GPL
导出的所有函数的文档, 无论是在 source 还是 source-pattern 指定的文件中。
source-pattern 在内核文档注释放在头文件中,而 EXPORT_SYMBOL
和 EXPORT_SYMBOL_GPL
位于函数定义旁时很有用。
示例:
.. kernel-doc:: lib/bitmap.c
:export:
.. kernel-doc:: include/net/mac80211.h
:export: net/mac80211/*.c
包含 source 中*未使用 ``EXPORT_SYMBOL`` 或 ``EXPORT_SYMBOL_GPL`` 导出的所有函数和类型的文档, 无论是在source* 还是 source-pattern 指定的文件中。
示例:
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
:internal:
包含 source 中每个 function 和 type 的文档。 如果未指定 function,则包含 source 中所有函数和类型的文档。
示例:
.. kernel-doc:: lib/bitmap.c
:identifiers: bitmap_parselist bitmap_parselist_user
.. kernel-doc:: lib/idr.c
:identifiers:
排除 source 中每个 function 和 type 的文档。
示例:
.. kernel-doc:: lib/bitmap.c
:no-identifiers: bitmap_parselist
这是 'identifiers' 指令的别名,已被弃用。
包含 source 中由 title 标识的 DOC:
段落的文档。 title 中允许有空格;不要引用 title。*title* 仅用作段落的标识符,不会包含在输出中。 请确保在封闭的 reStructuredText 文档中有适当的标题。
示例:
.. kernel-doc:: drivers/gpu/drm/i915/intel_audio.c
:doc: HDMI 和 Display Port 上的高清音频
如果没有选项,kernel-doc 指令将包含源文件中的所有文档注释。
kernel-doc 扩展包含在内核源代码树中,位于 Documentation/sphinx/kerneldoc.py
。 内部使用 scripts/kernel-doc
脚本从源文件中提取文档注释。
如果你只想使用 kernel-doc 生成手册页,可以从内核 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