这些指南适用于使用 Doxygen 风格格式记录所有 libcudf C++ 源文件,尽管实际上只有公共 API 和类被发布。
此处包含版权注释,但也可在编码指南文档中提及。以下是应出现在每个 C++ 源文件开头的许可头注释。
/* * Copyright (c) 2021-2022, NVIDIA CORPORATION. * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * https://apache.ac.cn/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */
注释应以 /*
开头,而不是 /**
,这样 Doxygen 就不会处理它。
此外,以下是关于版权年份的规则。
2019-2021
)如果内容没有改变(例如仅格式化),则无需更改版权年份。
Doxygen 工具用于从源代码中的 C++ 注释生成 HTML 页面。Doxygen 识别并解析块注释,并在遇到Doxygen 命令时执行专门的输出格式化。
Doxygen 在注释块中可识别近 200 个命令(本文档中也称为标签)。本文档提供了关于在 libcudf C++ 源代码中使用哪些命令/标签以及如何使用它们的指南。
Doxygen 过程可以通过Doxyfile中的选项进行定制。
以下是一些 libcudf 的 Doxyfile 中的自定义选项。
选项 | 设置 | 描述 |
---|---|---|
PROJECT_NAME | libcudf | 主页上使用的标题 |
PROJECT_NUMBER | 22.02.00 | 版本号 |
EXTENSION_MAPPING | cu=C++ cuh=C++ | 将 cu 和 cuh 文件视为 C++ 文件处理 |
INPUT | main_page.md regex.md unicode.md ../include | 要处理的嵌入式 Markdown 文件和源代码目录 |
FILE_PATTERNS | *.cpp *.hpp *.h *.c *.cu *.cuh | 要处理的文件扩展名 |
对于描述函数、类和其他类型、组以及文件的块注释,请使用以下风格。
/** * description text and * doxygen tags go here */
Doxygen 注释块仅以 /**
开头并以 */
结尾,这两行上没有其他内容。不要在 Doxygen 块的第一行和最后一行添加破折号 -----
或额外的星号 *****
。注释块必须紧贴在它所引用的源代码行之前。为了垂直对齐所描述的项目,可以适当地缩进注释块。请参见下面的示例部分。
在 /**
和 */
之间的注释块中的每一行都应该以一个空格后跟一个星号开头。这些行上的任何文本,包括标签声明,都应该在星号后的一个空格后开始。
使用 @ 作为 Doxygen 命令的前缀(例如 @brief, @code 等)
Doxygen 工具支持在注释块中使用有限的 Markdown 格式,包括链接、表格、列表等。在某些情况下,需要在源文本文件的可读性与 Doxygen 格式化网页的可读性之间进行权衡。例如,在 Markdown 表格中使用 '' 字符和管道符 '|' 会有一些可读性限制。
避免使用直接的 HTML 标签。尽管 Doxygen 支持 Markdown,且 Markdown 支持 HTML 标签,但 Doxygen 对 Markdown 中 HTML 的支持也是有限的。
以下示例涵盖了在 libcudf 中用于文档化 C++ 代码的大多数 Doxygen 块注释和标签风格。
/** * @file source_file.cpp * @brief Description of source file contents * * Longer description of the source file contents. */ /** * @brief One sentence description of the class. * * @ingroup optional_predefined_group_id * * Longer, more detailed description of the class. * * @tparam T Short description of each template parameter * @tparam U Short description of each template parameter */ template <typename T, typename U> class example_class { void get_my_int(); ///< Simple members can be documented like this void set_my_int( int value ); ///< Try to use descriptive member names /** * @brief Short, one sentence description of the member function. * * A more detailed description of what this function does and what * its logic does. * * @code * example_class<int> inst; * inst.set_my_int(5); * int output = inst.complicated_function(1,dptr,fptr); * @endcode * * @param[in] first This parameter is an input parameter to the function * @param[in,out] second This parameter is used both as an input and output * @param[out] third This parameter is an output of the function * * @return The result of the complex function */ T complicated_function(int first, double* second, float* third) { // Do not use doxygen-style block comments // for code logic documentation. } private: int my_int; ///< An example private member variable }; /** * @brief Short, one sentence description of this free function. * * @ingroup optional_predefined_group_id * * A detailed description must start after a blank line. * * @code * template<typename T> * struct myfunctor { * bool operator()(T input) { return input % 2 > 0; } * }; * free_function<myfunctor,int>(myfunctor{},12); * @endcode * * @throw cudf::logic_error if `input_argument` is negative or zero * * @tparam functor_type The type of the functor * @tparam input_type The datatype of the input argument * * @param[in] functor The functor to be called on the input argument * @param[in] input_argument The input argument passed into the functor * @return The result of calling the functor on the input argument */ template <class functor_type, typename input_type> bool free_function(functor_type functor, input_type input_argument) { CUDF_EXPECTS( input_argument > 0, "input_argument must be positive"); return functor(input_argument); } /** * @brief Short, one sentence description. * * @ingroup optional_predefined_group_id * * Optional, longer description. */ enum class example_enum { first_enum, ///< Description of the first enum second_enum, ///< Description of the second enum third_enum ///< Description of the third enum };
注释描述应清楚详细地说明如何根据任何输入创建输出。包括任何性能和边界考虑因素。还要包括对参数值的任何限制,以及是否声明了任何默认值。不要忘记说明如何处理或生成空值。此外,如果可能,尽量包含一个简短的示例。
@brief 文本应是一个简短的单句描述。Doxygen 在输出页面中显示此文本的空间不大。@brief 行后面始终应有一个空白注释行。
更长的描述是注释文本中未被任何 Doxygen 命令标记的其余部分。
/** * @brief Short description. * * Long description. *
头文件中的声明文档应清晰完整。您可以使用@copydoc标签来避免为函数定义重复注释块。
/** * @copydoc complicated_function(int,double*,float*) * * Any extra documentation. */
此外,当文档化仅因 stream
参数而不同的 detail
函数时,@copydoc 也很有用。
/** * @copydoc cudf::segmented_count_set_bits(bitmask_type const*,std::vector<size_type> const&) * * @param[in] stream Optional CUDA stream on which to execute kernels */ std::vector<size_type> segmented_count_set_bits(bitmask_type const* bitmask, std::vector<size_type> const& indices, rmm::cuda_stream_view stream = cudf::get_default_stream());
注意,您必须指定函数的完整签名,包括可选参数,以便 Doxygen 能够找到它。
以下标签应按此处指定的顺序出现在函数注释块的末尾附近
命令 | 描述 |
---|---|
@throw | 指定函数可能抛出异常的条件 |
@tparam | 每个模板参数的描述 |
@param | 每个函数参数的描述 |
@return | 返回的对象或值的简短描述 |
对于函数可能抛出的每个异常,在 Doxygen 块中添加一个@throw注释行。您只需要包含函数本身抛出的异常。如果函数调用了可能抛出异常的其他函数,则无需在此处记录这些异常。
包含异常名称,不带反引号,以便 Doxygen 可以正确添加引用链接。
* * @throw cudf::logic_error if `input_argument` is negative or zero *
使用 @throws 也是可以接受的,但 VS Code 和其他工具只对 @throw 进行语法高亮。
为函数声明的每个模板参数添加一个@tparam注释行。在 Doxygen 标签后指定的参数名称必须与模板参数名称完全匹配。
* * @tparam functor_type The type of the functor * @tparam input_type The datatype of the input argument *
定义应详细说明参数的要求。例如,如果模板用于仿函数(functor)或谓词(predicate),则描述预期的输入类型和输出。
为传递给此函数的每个函数参数添加一个@param注释行。在 Doxygen 标签后指定的参数名称必须与函数的参数名称匹配。如果从声明和参数名称本身不清楚方向,还应在 @param
后附加 [in]
、[out]
或 [in,out]
。
* * @param[in] first This parameter is an input parameter to the function * @param[in,out] second This parameter is used both as an input and output * @param[out] third This parameter is an output of the function *
如果可能,建议垂直对齐这 3 列文本,以便在源代码编辑器中更容易阅读。
如果函数返回对象或值,请在注释块末尾添加一个单独的@return注释行。包括对返回内容的简要描述。
/** * ... * * @return A new column of type INT32 and no nulls */
不要在 @return
注释中包含返回对象的类型。
在文档化函数或其他声明时,在注释块中包含源代码示例通常很有帮助。使用@code和@endcode对来包含内联示例。
Doxygen 支持 C++ 和其他几种编程语言(例如 Python、Java)的语法高亮。默认情况下,@code 标签根据其所在的源代码使用语法高亮。
* * @code * auto result = cudf::make_column( ); * @endcode *
您可以通过在标签中指定文件扩展名来指定不同的语言
* * @code{.py} * import cudf * s = cudf.Series([1,2,3]) * @endcode *
如果您希望在示例中使用伪代码,请使用以下格式
* * Sometimes pseudocode is clearer. * @code{.pseudo} * s = int column of [ 1, 2, null, 4 ] * r = fill( s, [1, 2], 0 ) * r is now [ 1, 0, 0, 4 ] * @endcode *
编写示例片段时,使用完全限定的类名可以让 Doxygen 为示例添加引用链接。
* * @code * auto result1 = make_column( ); // reference link will not be created * auto result2 = cudf::make_column( ); // reference link will be created * @endcode *
虽然使用三个反引号 ``` 来表示示例块也可以工作,但它们在 VS Code 和其他源代码编辑器中不够突出。
不要在声明的注释中使用@example标签,否则 Doxygen 会将整个源文件解释为示例源代码。然后,该源文件将作为单独的“示例”页面发布在输出中。
对于将在未来版本中移除的 API,在注释块中添加一个单独的@deprecated注释行。在弃用注释中提及替代/替换的 API。
/** * ... * * @deprecated This function is deprecated. Use another new function instead. */
Doxygen 输出包含一个“命名空间”页面,显示处理的文件中所有带有注释块声明的命名空间。以下是一个用于命名空间声明的 Doxygen 描述注释示例。
/** * @brief cuDF interfaces * * This is the top-level namespace which contains all cuDF functions and types. */ namespace CUDF_EXPORT cudf {
每个唯一的命名空间声明只应包含一次描述注释。否则,如果找到多个描述,Doxygen 将在输出页面中以任意顺序聚合这些描述。
如果引入新的命名空间,仅为一个声明提供一个描述块,而不是每个出现的地方都提供。
将声明分组到模块中有助于用户在 Doxygen 页面中找到 API。通常,常用函数已经按逻辑分组到头文件中,但 Doxygen 不会在输出中自动以这种方式分组。Doxygen 输出包含一个“模块”页面,该页面使用分组 Doxygen 命令将项目组织到组中。这些命令可以将头文件、源文件甚至命名空间中的常用函数进行分组。组还可以通过在现有组中定义新组来嵌套。
对于 libcudf,所有组层级都在doxygen_groups.h头文件中定义。doxygen_groups.h文件不需要包含在任何其他源文件中,因为此文件中的定义仅由 Doxygen 工具用于在“模块”页面中生成组。仅修改此文件以添加或更新组。现有组已仔细构建和命名,因此新组应经过深思熟虑后添加。
创建新的 API 时,使用@ingroup标签和doxygen_groups.h文件中的组引用 ID 来指定其所属组。
namespace CUDF_EXPORT cudf { /** * @brief ... * * @ingroup transformation_fill * * @param ... * @return ... */ std::unique_ptr<column> fill(table_view const& input,...); } // namespace cudf
您还可以使用带有 @{ ... @}
对的 @addtogroup 来自动将 Doxygen 注释块包含到组中。
namespace CUDF_EXPORT cudf { /** * @addtogroup transformation_fill * @{ */ /** * @brief ... * * @param ... * @return ... */ std::unique_ptr<column> fill(table_view const& input,...); /** @} */ } // namespace cudf
这样做只是省去了在文件内的每个 Doxygen 注释块中添加 @ingroup 的麻烦。请确保在 @addtogroup 命令块之后包含一个空白行,以便 Doxygen 知道它不适用于源代码中紧随其后的内容。请注意,如果带有 @{ ... @}
对的 @addtogroup 包含了命名空间声明,Doxygen 将不会为其中的项分配组。因此,如上例所示,将 @addtogroup 和 @{ ... @}
放在命名空间声明的大括号之间。
组标签摘要
标签/命令 | 使用位置 |
---|---|
@defgroup | 仅用于doxygen_groups.h,应包含组的标题。 |
@ingroup | 在头文件中的声明语句的单个 Doxygen 块注释内部使用。 |
@addtogroup | 在同一个文件中的命名空间声明内,用于代替 @ingroup 来处理多个声明。不要指定组标题。 |
@{ ... @} | 仅与 @addtogroup 一起使用。 |
我们建议使用 conda (conda install doxygen
) 或 Linux 包管理器 (sudo apt install doxygen
) 安装 Doxygen。或者,您可以从源代码构建和安装 Doxygen。
要构建 libcudf HTML 文档,只需在包含 Doxyfile
的 cpp/doxygen
目录中运行 doxygen
命令。libcudf 文档也可以在 cmake 构建目录(例如 cpp/build
)中使用 cmake --build . --target docs_cudf
命令构建。Doxygen 读取并处理 cpp/include/
目录下的所有相关源文件。输出将生成在 cpp/doxygen/html/
目录中。您可以在任何网络浏览器中加载该目录中生成的本地 index.html
文件来查看结果。
要在远程服务器上查看构建好的文档,您可以使用 Python 运行一个简单的 HTTP 服务器:cd html && python -m http.server
。然后在本地网络浏览器中打开 <IP address>:8000
,将 <IP address>
替换为您运行 HTTP 服务器的机器的 IP 地址。
Doxygen 输出仅用于构建公共 API 和类的文档。例如,输出不应包含 detail
或 /src
文件的文档,这些目录已在 Doxyfile
配置中排除。通过构建/CI 系统发布时,Doxygen 输出将出现在我们的外部RAPIDS 网站上。