编写代码文档

[English]

本文简要介绍了 espressif/esp-idf 项目库采用的文件风格以及如何在项目库中添加新文件。

概述

在项目库内编写代码文档时,请遵循 Doxygen 代码注释风格。要采用这一风格,您可以将 @param 等特殊命令插入到标准注释块中,比如:

/**
 * @param ratio this is oxygen to air ratio
 */

Doxygen 会解析代码,提取命令和后续文本,生成代码文档。

注释块通常包含对功能的记述,如下所示。

内联代码样本文档

Doxygen 支持多种排版风格,对于文档中可以包含的细节非常灵活。请参考数据丰富、条理清晰的 Doxygen 手册 熟悉 Doxygen 特性。

为什么需要 Doxygen?

使用 Doxygen 的最终目的是确保所有代码编写风格一致,以便在代码变更时使用 SphinxBreathe 等工具协助筹备、自动更新 API 文档。

使用这类工具时,上文代码渲染后呈现效果如下:

渲染后的内联代码样本文档

尝试一下!

在本项目库编写代码文档时,请遵守下列准则。

  1. 写明代码的基本内容:函数、结构、类型定义、枚举、宏等。请详细说明代码的用途、功能和限制,因为在阅读他人的文档时你也想看到这些信息。

  2. 函数文档需简述该函数的功能,并解释输入参数和返回值的含义。

  3. 请不要在参数或除空格外的其他字符前面添加数据类型。所有空格和换行符都会压缩为一个空格。如需换行,请执行换行操作两次。

    内联函数样本文档及渲染后的效果
  4. 如果函数没有输入参数或返回值,请跳过 @param@return

    隐式内联函数样本文档及渲染后的效果
  5. definestructenum 的成员编写文档时,请在每一项后添加注释,如下所示。

    内联函数成员样本文档及渲染后的效果
  6. 请在命令后换行(如下文中的 @return ),呈现排版精美的列表。

    *
    * @return
    *    - ESP_OK if erase operation was successful
    *    - ESP_ERR_NVS_INVALID_HANDLE if handle has been closed or is NULL
    *    - ESP_ERR_NVS_READ_ONLY if handle was opened as read only
    *    - ESP_ERR_NVS_NOT_FOUND if the requested key doesn't exist
    *    - other error codes from the underlying storage driver
    *
    
  7. 头文件的功能概览和库文件应当存在同一个项目库之下,放入单独的 README.rst 文件。如果目录下包含不同 API 的头文件,应将文件命名为 apiname-readme.rst

进阶

以下小贴士可以帮助你进一步提高文档质量,增强可读性。

  1. 添加代码片段举例说明。请在片段前后添加 @code{c}@endcode 命令。

    *
    * @code{c}
    * // Example of using nvs_get_i32:
    * int32_t max_buffer_size = 4096; // default value
    * esp_err_t err = nvs_get_i32(my_handle, "max_buffer_size", &max_buffer_size);
    * assert(err == ESP_OK || err == ESP_ERR_NVS_NOT_FOUND);
    * // if ESP_ERR_NVS_NOT_FOUND was returned, max_buffer_size will still
    * // have its default value.
    * @endcode
    *
    

    代码片段应放入所介绍功能的注释块中。

  2. 使用 @attention@note 命令高亮显示重要信息。

    *
    * @attention
    *     1. This API only impact WIFI_MODE_STA or WIFI_MODE_APSTA mode
    *     2. If the ESP32 is connected to an AP, call esp_wifi_disconnect to disconnect.
    *
    

    上述例子介绍了如何使用编号列表。

  3. 给相似的函数编写文档时,可在前后使用 /**@{*//**@}*/ 标记命令。

    /**@{*/
    /**
     * @brief common description of similar functions
     *
     */
    void  first_similar_function (void);
    void second_similar_function (void);
    /**@}*/
    

    示例请参照 nvs_flash/include/nvs.h

  4. 如果想跳过重复的宏定义、枚举项等代码,不添加描述,请在代码前后添加 /** @cond *//** @endcond */ 命令。示例请参照 driver/include/driver/gpio.h

  5. 使用 markdown 增强文档可读性,添加页眉、链接、表格及更多内容。

    *
    * [ESP32 技术参考手册](https://www.espressif.com/sites/default/files/documentation/esp32_technical_reference_manual_cn.pdf)
    *
    

注解

代码片段、注释、链接等内容如没有附在所述对象对应的注释块中,将不会添加到文档中。

  1. 准备一个或更多完整的代码示例和描述,将描述放入单独的 README.md 文件中,置于 examples 目录的特定文件夹中。

添加图例

请考虑使用图表和图片解释表述的概念。

相比于长篇的表述,图例有时可以更好地描述复杂的理念、数据结构或算法。本项目库使用`blockdiag <http://blockdiag.com/en/index.html>`_ 工具包由简单的文本文件生成图表。

工具包支持下列图表类型:

使用该工具包,可以将简单的文本(与 graphviz 的 DOT 格式类似)转换成美观的图片。图中内容自动排版。图标代码之后会转换为 “.png” 图片,在后台添加进 Sphinx 文档中。

要查看图表的渲染效果,可使用线上的 interactive shell 即时显示生成的图片。

下面是一些图表示例:

尝试修改源代码,看看图表会发生什么变化。

注解

interactive shell 使用的字体和 esp-idf 文档使用的字体略有不同。

添加注释

写文档时,您可能需要:

  • 留下建议,说明之后需添加会修改哪些内容。

  • 提醒自己或其他人跟进。

这时,您可以使用 .. todo:: 命令在 reST 文件中添加待做事项。如:

.. todo::

   Add a package diagram.

如果在 reST 文件中添加 .. todolist:: 命令,整篇文档中的所有待做事项将会罗列成表。

默认情况下,文档生成器会忽视 .. todo::.. todolist:: 命令。如果您想在本地生成的文档中显示注释和注释列表,请执行下列步骤:

  1. 打开本地的 conf_common.py 文件。

  2. 找到 todo_include_todos 参数。

  3. 将该参数的值由 False 改为 True

将改动推送到远端分支之前,请把 todo_include_todos 的值重置为 False

更多关于扩展的信息,请参阅 sphinx.ext.todo 的相关文档。

汇总文档

文档准备好后,请参照 API Documentation Template 的要求创建一个文件,汇总所有准备好的文档。最后,在文件中添加链接指向 /docs 文件夹或子文件夹下 index.rst 文件的 .. toctree::

Sphinx 新手怎么办

  1. 不要担心。所有需要的软件均有详细文档,并且开源、免费。您可以先查看 Sphinx 文档。如果您不清楚如何用 rst markup 语言写作,请查看 reStructuredText Primer。您也可以使用 markdown (.md) 文件,查找更多在 Recommonmark parser’ 文档页面 使用的特定 markdown 句法信息。

  2. 查看本文档的源文件,了解本文档使用的代码。源文件存储于 GitHub espressif/esp-idf 项目库的 docs 文件夹下。您可以滑动到页面上方,点击右上角的链接,直接查看本页面的源文件。您也可以通过点击 Raw 按键打开源文件,在 GitHub 上查看文件的代码。

  3. 想要查看在上传至 GitHub 前文档如何生成、呈现,有两种方式:

    • 安装`Sphinx`_、 BreatheBlockdiagDoxygen 本地生成文档,具体可查看下文。

    • Read the Docs 建立账号,在云端生成文档。 Read the Docs 免费提供文档生成和存储,且速度快、质量高。

  4. 在生成文档前预览,可使用 Sublime Text 编辑器和 OmniMarkupPreviewer 插件。

搭建环境本地生成文档

您可以安装下列包,通过搭建环境在电脑上本地生成文档:

  1. Doxygen - http://doxygen.nl/

  2. Sphinx - https://github.com/sphinx-doc/sphinx/#readme-for-sphinx

  3. Breathe - https://github.com/michaeljones/breathe#breathe

  4. Document theme “sphinx_idf_theme” - https://github.com/rtfd/sphinx_idf_theme

  5. Custom 404 page “sphinx-notfound-page” - https://github.com/rtfd/sphinx-notfound-page

  6. Blockdiag - http://blockdiag.com/en/index.html

  7. Recommonmark - https://github.com/rtfd/recommonmark

添加 “sphinx_idf_theme” 包之后,文档将与 ESP-IDF 编程指南 的风格保持一致。

不用担心需要安装太多包。除 Doxygen 和 sphinx_idf_theme 之外,其他包均使用纯 Python 语言,可一键安装。

Doxygen 的安装取决于操作系统:

Linux

sudo apt-get install doxygen

Windows - 在 MSYS2 控制台中安装

pacman -S doxygen

MacOS

brew install doxygen

注解

如果您是在 Windows 系统上安装(Linux 和 MacOS 用户可以跳过此说明),在安装 之前,请完成以下两步。这是安装 添加图例 提到的 “blockdiag” 依赖项的必须步骤。

  1. 更新所有系统包:

    $ pacman -Syu
    

    该过程可能需要重启 MSYS2 MINGW32 控制台重复上述命令,直至更新完成。

  2. 安装 blockdiag 的依赖项之一 pillow

    $ pacman -S mingw32/mingw-w64-i686-python-pillow
    

    查看屏幕上的记录,确定 mingw-w64-i686-python-pillow-4.3.0-1 已安装。旧版本 pillow 无法运行。

Windows 安装 Doxygen 的缺点是 blockdiag pictures 字体不能正确加载,可能会存在乱码。在此问题解决之前,您可以使用 interactive shell 查看完整图片。

sphinx_idf_theme

编译 sphinx_idf_theme 需要同时使用 Python 和 JavaScript。因此,目前要进行本地编译还必须安装 node.js ,命令如下:

cd ~/esp
git clone https://github.com/espressif/sphinx_idf_theme.git
cd sphinx_idf_theme
npm install
python setup.py build
python setup.py install

我们计划在不久的将来支持安装预编译 sphinx_idf_theme,给您带来的暂时不便,敬请谅解。

其他所有应用都是 Python 包,可以按照下列步骤一键安装:

cd ~/esp/esp-idf/docs
pip install --user -r requirements.txt

注解

安装步骤设定将 ESP-IDF 放在 ~/esp/esp-idf 目录下,这是文档中使用的 ESP-IDF 默认地址。

更换到特定语言文件所在的目录:

cd en

现在可以调用如下命令生成文档:

make html

这一步骤需要几分钟时间。完成后,文档会放置在 ~/esp/esp-idf/docs/en/_build/html 文件夹下。您可以在网页浏览器中打开 index.html 查看。

大功告成

我们喜欢可以做酷炫事情的好代码。 但我们更喜欢有清晰文档的好代码,可以让读者快速上手,做酷炫的事情。

尝试一下,贡献你的代码和文档!