Skip to content

ament 代码规范

目标: 学习如何使用 ament_lint 及相关工具来识别和修复代码质量问题。

教程级别: 高级

预计耗时: 10 分钟

ament 系列 CLI 工具是一组专为 ROS 2 软件开发设计的 Python 工具。它们可以配合任何构建系统使用,其中 ament_cmake 子集专门简化基于 CMake 的开发流程。ament 还附带了一组 CLI 程序,帮助你编写符合 ROS 项目编码规范 的代码。善用这些工具可以大幅提升开发效率,确保你的 ROS 应用和核心代码符合编码规范。建议 ROS 开发者熟悉这些工具,并在提交 pull request 前运行一遍。

在常规的 ROS 2 安装过程中,你应该已经安装了 ament 相关包。

如果你需要安装 ROS 2,请参阅 安装指南。

所有 ament lint 工具都采用相似的 CLI 调用方式:接收一个或多个目录/文件作为输入,分析这些文件后输出报告。它们都提供以下内置选项。如需获取某个 ament 工具最准确、最新的文档,请使用该工具的 --help 功能。

  • -h, --help - 显示帮助信息并退出。帮助信息通常是该工具最准确、最新的文档。
  • --exclude [filename ...] - 要从分析中排除的文件名,支持通配符。
  • --xunit-file XUNIT_FILE - 生成符合 xunit 标准的 XML 文件。这些文件最常被 IDE 和 CI 系统用来自动化地收集测试结果。

ament_copyright CLI 可用于检查和更新 ROS 源代码中的版权声明,还能检查源代码中是否包含合适的许可证、版权年份和版权持有人信息。ament_copyright 以调用时所在的目录为根,递归遍历子目录并检查每个源文件。你只需切换到合适的根目录并运行该命令,就可以检查整个 ROS 包、工作空间、目录或单个源文件。此外,ament_copyright 还能自动为缺少版权和许可证信息的文件补上相应内容。

默认情况下,ament_copyright 会遍历调用时所在的目录(包括子目录),报告所有缺少版权声明的文件。该程序接受一个可选参数,即要扫描的目录列表。例如,如果你只想扫描源文件和头文件中的版权声明,可以调用 ament_copyright ./src ./include。

ament_copyright 支持以下选项:

  • --add-missing COPYRIGHT_NAME LICENSE - 使用传入的版权持有人和许可证,为缺少版权声明的文件添加版权声明和许可证信息。LICENSE 参数指定要使用的许可证名称。可以通过调用 ament_copyright --list-licenses 获取所有可用许可证的完整列表。
  • --add-copyright-year - 将当前年份添加到现有的版权声明中。
  • --list-copyright-names - 列出已知的版权持有人名称。
  • --list-licenses - 列出已知的许可证名称。
  • --verbose - 显示所有文件,而不仅仅是存在错误或被修改的文件。

要检查你的 ROS 包是否具有合适的版权和许可证文件,直接不带参数调用 ament_copyright 即可。加上 --verbose 选项会列出所有被检查的文件。

Terminal window
$ ament_copyright --verbose
my_package/src/new_file.cpp: could not find copyright notice
my_package/src/old_file.cpp: copyright=Open Source Robotics Foundation, Inc. (2023), license=apache2
my_package/include/new_file.h: could not find copyright notice
my_package/include/old_file.h: copyright=Open Source Robotics Foundation, Inc. (2023), license=apache2

ament_cppcheck 命令行工具用于对 C++ 源代码文件执行静态分析。静态分析 是指在不运行代码的情况下,自动审查源代码以发现可能在运行时引发问题的模式。ament_cppcheck 底层使用的 cppcheck 工具的某些版本可能较慢,因此在部分系统上 ament_cppcheck 可能会被禁用。如需启用,设置 AMENT_CPPCHECK_ALLOW_SLOW_VERSIONS 环境变量即可。

默认情况下,ament_cppcheck 会遍历调用时所在的目录(包括子目录),报告源代码文件中所有潜在的问题。该程序接受一个可选参数,即要扫描的目录列表。例如,如果你只想扫描某个最近修改的文件,可以调用 ament_cppcheck ./src/my_cpp_file.cpp。

ament_cppcheck 支持以下选项:

  • --libraries [LIBRARIES ...] - 除 C 和 C++ 标准库之外要加载的库配置。每个库以 --library=<library_name> 的形式传递给 cppcheck。
  • --include_dirs [INCLUDE_DIRS ...] - 正在检查的 C/C++ 文件的包含目录。每个目录以 -I <include_dir> 的形式传递给 cppcheck(默认值:None)
  • --cppcheck-version - 获取 cppcheck 版本,打印后退出。

创建一个名为 example.cpp 的文件,内容为以下简单的 C++ 程序。

int main()
{
char a[10];
a[10] = 0;
return 0;
}

这个简单的程序越界访问了内存。在该文件所在目录中运行 ament_cppcheck 会产生以下结果:

Terminal window
$ ament_cppcheck
[example.cpp:4]: (error: arrayIndexOutOfBounds) Array 'a[10]' accessed at index 10, which is out of bounds.

ament_cpplint 可用于根据 Google 代码风格指南 检查你的 C++ 代码,底层使用的是 cpplint。ament_cpplint 会扫描当前目录及子目录中的所有 C++ 头文件和源文件,对每个文件运行 CppLint 并输出结果。目前 ament_cpplint 无法自动修复发现的问题,如需自动修复格式问题,请参阅 ament_uncrustify。

该程序接受一个可选参数,即要扫描的目录列表。例如,如果你只想扫描源文件和头文件,可以调用 ament_cpplint ./src ./include。

  • --filters FILTER,FILTER,... - 以逗号分隔的类别过滤器列表。
  • --linelength N - 最大行长度(默认值:100)。
  • --root ROOT - cpplint 的 —root 选项。

下面创建一个名为 example.cpp 的简单 C++ 程序,并故意加入几行违反编码规范的代码:

int main()
{
int a = 10;
int b = 10;
int c = 0;/*<trailing whitespace>*/
if( a == b) {/*<tab>*/ c=a;}/*<trailing whitespace>*/
return 0;
}

对该文件运行 ament_cpplint 将报告以下错误:

Terminal window
example.cpp:0: No copyright message found. You should have a line: "Copyright [year] <Copyright Owner>" [legal/copyright] [5]
example.cpp:6: Line ends in whitespace. Consider deleting these extra spaces. [whitespace/end_of_line] [4]
example.cpp:6: Tab found; better to use spaces [whitespace/tab] [1]
example.cpp:6: Line ends in whitespace. Consider deleting these extra spaces. [whitespace/end_of_line] [4]
example.cpp:6: Missing spaces around = [whitespace/operators] [4]

Flake8 是一个用于 Python 代码检查和风格强制的工具。ament_flake8 命令行工具借助 Flake8 快速对 Python 源代码文件执行 lint 检查,帮助你发现 ROS Python 程序中的小错误和风格问题,例如行尾空格、代码行过长、函数参数间距不当等。请注意,flake8 和 ament_flake8 无法自动重新格式化代码来修复这些问题。

该程序接受一个可选参数,即要扫描的目录列表。例如,如果你只想扫描工作空间中的某个包,可以直接在该包的工作目录中调用 ament_flake8,或者将目录路径传递给它。

ament_flake8 支持以下选项:

  • --config path - 指定使用的配置文件。默认配置文件可以在安装目录的 site-packages 目录中找到。不建议更改默认设置。
  • --linelength N - 手动设置最大行长度。

创建一个名为 example.py 的文件,内容为以下简单的 Python 程序。

def uglyPythonFunction(a,b, c):
if a != b:
print("A does not match b")
thisIsAVariableNameThatIsWayTooLongLongLong = 2
extra_long =(thisIsAVariableNameThatIsWayTooLongLongLong*thisIsAVariableNameThatIsWayTooLongLongLong )
return(c)

对该文件运行 ament_flake8 将报告以下错误。

Terminal window
example.py:1:25: E231 missing whitespace after ','
def uglyPythonFunction(a,b, c):
example.py:5:5: F841 local variable 'extra_long' is assigned to but never used
extra_long =(thisIsAVariableNameThatIsWayTooLongLongLong*thisIsAVariableNameThatIsWayTooLongLongLong )
^
example.py:5:17: E225 missing whitespace around operator
extra_long =(thisIsAVariableNameThatIsWayTooLongLongLong*thisIsAVariableNameThatIsWayTooLongLongLong )
^
example.py:5:100: E501 line too long (106 > 99 characters)
extra_long =(thisIsAVariableNameThatIsWayTooLongLongLong*thisIsAVariableNameThatIsWayTooLongLongLong )
^
example.py:5:105: E202 whitespace before ')'
extra_long =(thisIsAVariableNameThatIsWayTooLongLongLong*thisIsAVariableNameThatIsWayTooLongLongLong )
^
1 E202 whitespace before ')'
1 E225 missing whitespace around operator
1 E231 missing whitespace after ','
1 E501 line too long (106 > 99 characters)
1 F841 local variable 'extra_long' is assigned to but never used
1 files checked
5 errors
'E'-type errors: 4
'F'-type errors: 1
Checked files:
* example.py

Uncrustify 是一个 C++ lint 工具,类似于 ament_cpplint,但它的优势在于可以自动修复发现的问题!它可以帮助你发现和修复 C++ ROS 程序中的小错误和风格问题,例如行尾空格、代码行过长、函数参数间距不当等。

该程序接受一个可选参数,即要扫描的目录列表。例如,如果你只想扫描工作空间中的某个包,可以直接在该包的工作目录中调用 ament_uncrustify,或者将目录路径传递给它。

ament_uncrustify 支持以下选项:

  • -c CFG - 如果你想使用自己的设置,可以指定 Uncrustify 应使用的配置文件。建议使用默认配置。
  • --linelength N - 最大行长度。
  • --language - 取值为 C、C++、CPP 之一,以 -l <language> 的形式传递给 uncrustify,强制指定语言而不是根据文件扩展名自动选择。
  • --reformat - 就地重新格式化文件,即修复遇到的格式错误。建议在运行 ament_uncrustify 时使用此选项,可以为你节省大量时间!

回到之前那个名为 example.cpp 的简单 C++ 程序。

int main()
{
int a = 10;
int b = 10;
int c = 0;<trailing whitespace>
if( a == b)<trailing whitespace>{
<tab> c=a;}<trailing whitespace>
return 0;
}

对该文件运行 ament_uncrustify example.cpp 会产生以下输出。

--- example.cpp
+++ example.cpp.uncrustify
@@ -1,9 +1,10 @@
- int main()
- {
- int a = 10;
- int b = 10;
- int c = 0;<trailing whitespace>
- if( a == b)<trailing whitespace>{
- <tab> c=a;}<trailing whitespace>
- return 0;
- }
+int main()
+{
+ int a = 10;
+ int b = 10;
+ int c = 0;
+ if (a == b) {
+ c = a;
+ }
+ return 0;
+}
1 files with code style divergence

要将这些更改应用到文件中,我们可以使用 --reformat 选项运行 ament_uncrustify。使用此选项时,uncrustify 会就地应用所有更改,能帮你节省大量时间,尤其是在处理大型代码库时。

ROS Desktop Full 附带了一些值得关注的 ament 开发工具,下面列出其中几个:

  • ament_lint_cmake - 根据 CMake 风格规范检查 CMake 文件。
  • ament_xmllint - 使用 xmllint 检查 XML 标记,例如 XML launch 文件。
  • ament_pep257 - 根据 PEP 257 风格规范检查 Python 文档字符串。

ament 具有高度可扩展性,鼓励 ROS 用户构建和使用能够提升自身效率的 ament 工具。你可以使用 apt search 或在 ROS Index 上搜索 ament 来查找社区贡献的其他 ament lint 工具。