Ament Lint CLI Utilities

Goal: Learn how to use ament_lint and related tools to identify and fix code quality issues.

Tutorial level: Advanced

Time: 10 minutes

Background

The ament family of CLI tools are Python tools used for software development with ROS 2. Ament tools can be used from any build system, but a subset of these tools, the ament_cmake tools, are designed specifically to CMake-based development easier. Ament ships with a collection of CLI programs that can help users write code that meet the ROS 2 coding standards. Using these tools can greatly increase development velocity and help users write ROS applications and core code that meet the ROS project's coding standards. We recommend that ROS developers familiarize themselves with these tools and use them before submitting their pull requests.

Prerequisites

You should have the ament packages installed as part of your regular ROS 2 setup.

If you need to install ROS 2, see the Installation instructions.

Ament Lint CLI Tools

All ament linting tools use a similar CLI pattern. They take in a directory, a list of directories, file, or list of files, analyze the input files, and generate a report. All ament linting tools have the following built-in options. The most up to date and accurate documentation for a given ament tool can be found by using the tools built in ``–help`` functionality.

  • -h, --help - shows a help message and exit. The built-in help messages usually have the most accurate and up-to-date documentation of the tool.

  • --exclude [filename ...] - The filenames to exclude from analysis, including wildcards.

  • --xunit-file XUNIT_FILE - Generate a xunit compliant XML file. These files are most commonly used by IDEs and CI to automate the ingestion of test results.

2 ament_cppcheck

The ament_cppcheck command line tool can be used to perform static analysis of C++ source code files. Static analysis is the process of automatically reviewing source code files for patterns that can often cause issues after compilation. Some versions of cppcheck, the underlying utility used by ament_cppcheck, can be rather slow. For this reason ament_cppcheck may be disabled on some systems. To enable it, you simply need to set the AMENT_CPPCHECK_ALLOW_SLOW_VERSIONS environment variable.

2.1 ament_cppcheck Arguments

By default ament_cppcheck walks the directory in which it is called, including subdirectories and returns a report that lists all of the potential issues in a source code file. The program takes a single optional argument which is a list of directories that should be scanned for the report. For example, if you wish to scan just a recently modified file you can call ament_cppcheck ./src/my_cpp_file.cpp.

2.2 ament_cppcheck Options

ament_cppcheck supports the following options:

  • --libraries [LIBRARIES ...] - Library configurations to load in addition to the standard libraries of C and C++. Each library is passed to cppcheck as ‘–library=<library_name>’

  • --include_dirs [INCLUDE_DIRS ...] - Include directories for C/C++ files being checked.Each directory is passed to cppcheck as ‘-I <include_dir>’ (default: None)

  • --cppcheck-version - Get the cppcheck version, print it, and then exit.

2.3 ament_cppcheck Example

Create the following simple C++ program in a file named example.cpp.

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

This simple program accesses a part of memory out of bounds of the allocated array. Running ament_cppcheck in the directory with the file will yield the following results:

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

3 ament_cpplint

ament_cpplint can be used to check your C++ code against the Google style conventions using cpplint. ament_cpplint will scan the current directory and subdirectories for all C++ header and source files and apply the CppLint application to the file and return the results. At this time ament_cpplint is unable to address issues it finds automatically, if you would like to fix the formatting issues automatically please see ament_uncrustify.

3.1 ament_cpplint Arguments

The program takes a single optional argument which is a list of directories that should be scanned for the report. For example, if you wish to scan just source and header files for copyright notices you can call: ament_copyright ./src ./include.

3.2 ament_cpplint Options

  • --filters FILTER,FILTER,... - A comma separated list of category filters to apply.

  • --linelength N - The maximum line length (default: 100).

  • --root ROOT - The –root option for cpplint.

3.3 ament_cpplint Example

Let’s create a simple C++ program named example.cpp. We will add a few lines of code that violate coding standards:

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

Applying ament_cpplint to this file will yield the following errors:

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]

4 ament_flake8

Flake8 is a Python tool for linting and style enforcement. The ament_flake8 command line tool can be used to quickly perform linting of Python source code files using Flake8. This tool will help you locate minor errors and style problems with your ROS Python programs such as trailing whitespace, overly long lines of code, poorly spaced function arguments, and much more! Note, however, that flake8 and ament_flake8 cannot automatically reformat code to fix these issues.

4.1 ament_flake8 Arguments

The program takes a single optional argument which is a list of directories that should be scanned for the report. For example, if you wish to scan just one package in your workspace you can call ament_flake8 directly in the package’s working directory or pass it a path to the directory.

4.2 ament_flake8 Options

  • --config path - The config file used. The default config file can be found in your installation’s site packages directory. We do not recommend changing the default settings.

  • --linelength N - Manually set the maximum line length.

4.3 ament_flake8 Example

Create the following simple Python program in a file named example.py.

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

Applying ament_flake8 to this file will result in the following errors.

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

5 ament_uncrustify

Uncrustify is a C++ linting tool, similar to ament_cpplint, that has the advantage that it can automatically fix the issues it finds! This tool will help you locate and fix minor errors and style problems with your C++ ROS programs such as trailing whitespace, overly long lines of code, poorly spaced function arguments, and much more!

5.1 ament_uncrustify Arguments

The program takes a single optional argument which is a list of directories that should be scanned for the report. For example, if you wish to scan just one package in your workspace you can call ament_uncrustify directly in the package’s working directory or pass it a path to the directory.

5.2 ament_uncrustify Options

  • -c CFG - The config file that Uncrustify should use if you would prefer to use your own settings. We recommend you stick to the defaults

  • --linelength N - The maximum line length.

  • --language - One of {C,C++,CPP}, passed to uncrustify as ‘-l <language>’ to force a specific language rather then choosing one based on file extension.

  • --reformat - Reformat the files in place, i.e. fix the formatting errors encountered. We recommend you use this option when running ``ament_uncrustify`` as it will save you quite a bit of time!

5.3 ament_uncrustify Example

Let’s return to the simple C++ program named example.cpp.

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;
 }

Applying ament_uncrustify example.cpp to this file will yield the following output.

--- 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

To apply these changes to the file we can run ament_uncrustify with the --reformat flag. With this option specified uncrustify will apply the necessary changes in place, saving us a lot of time, especially when working with a larger codebase!

6 Other Ament Tools Of Note

ROS Desktop Full ships with a handful of ament development tools that are worth noting. A few of these tools are listed below.

  • ament_lint_cmake - Check CMake files against the style conventions.

  • ament_xmllint - Check XML markup, such as XML launch files, using xmllint.

  • ament_pep257 - Check Python docstrings against the style conventions in PEP 257.

Ament is highly extensible and ROS users are encouraged to build and use ament tools that make them more productive. You can search for other community contributed ament lint tools by using the apt search or by searching for ament on ROS Index.