Skip to content

Improving Software Quality

Introduction

You have now run your own, simple, application developed for Zephyr RTOS. Before you develop a more complex application, we need to ensure that it meets certain quality standards. The aim of this codelab is to add this dimension to your project, providing a solid foundation for future work.

What you’ll build

This codelab will teach you the tools and guidelines required for building high-quality software. These should, of course, be used when creating any type of software. You will also learn how to interpret the results delivered by the tools in order to improve your work.

What you’ll learn

  • How to set up the tools for ensuring certain quality standards.
  • Start ensuring quality throughout the entire development lifecycle.
  • Understand the different elements composing quality and how to interpret the results provided by the different analysis tools.

What you’ll need

  • You need to have completed the Getting started with Zephyr RTOS.
  • You need to have started the C++ Basics and completed the related exercices.
  • You need to install a number of additional software components as documented in the codelab.
  • You need python3 to be installed on your machine, which is the case since we are using west to develop our_Zephyr RTOS_ applications.

Enforcing a common coding style: clang-format

In most cases, software is developed by many contributors. Imposing a common coding style can improve the readability and maintainability of the code of and by all contributors. Code consistency is also important for code reviews, where different contributors revise code written by others.

In this course, we will use clang-format, which is a relatively easy-to-use tool for enforcing a common code style for your projects written in C++.

Installation

In a terminal of your virtual Python environment, run python -m pip install clang-format. This will install the clang-format Python package in your virtual environment.

Once you have installed clang-format, run the command clang-format --version. It should print the version of the software installed. At the time of writing, the latest version was v21.1.1.

Run a first clang-format operation

For using clang-format, you first need to create a configuration file named .clang-format at the root of your project - where you will run the clang-format tool. This file contains various configuration parameters such as:

---
BasedOnStyle: Google
IndentWidth: 2
---
Language: Cpp
ColumnLimit: 90
AlignConsecutiveAssignments: true
DerivePointerAlignment: false
PointerAlignment: Left
BinPackArguments: false
BinPackParameters: false
IndentAccessModifiers: false
The parameters for configuring clang-format are described here. From this documentation, you should be able to understand the options used in the configuration file illustrated above.

For using clang-format, you may then run the command clang-format -i blinky/src/main.cpp. In this command, -i means that the file is edited in place. This means that if clang-format detects required changes in the file, it will modify the file with the required changes. Without the -i option, clang-format simply outputs the modified file on the console without modifying the file itself.

Guideline checker: cpplint

cpplint is a command-line tool used for checking that C++ code follows the Google’s C++ style guide.

The guidelines cover a wide range of rules, ranging from notation to dos and dont’s for writing C++ code. The overall goal is to make the code more readable and more robust.

Whether or not it is a good idea to apply Google’s guidelines to our project is certainly a good question. For now, it is important to apply one guideline, although it is debatable whether this is the best existing tool.

Installation

You simply need to enter pip3 install cpplint for installing the cpplint tool on your system. Run cpplint --version for checking that the installation was successful. At the time of writing, the latest version was v2.0.2.

Run a first cpplint analysis

Before running your first analysis, you may add the file “CPPLINT.cfg” at the root of your code repository, with the following content:

linelength=90
filter=-build/include_subdir,-whitespace/indent,-build/namespaces,-build/c++11
By default, this configuration file is read by cpplint and the configuration is applied for all files analyzed in this directories and in the sub-directories.

To see a list of all category filters in cpplint, you may simply type cpplint --filter= (with no argument). This will list all available filters. Available options may be listed with cpplint --help. Options may be entered in the command line or in the “cpplint.cfg” file.

Once you created the configuration file, you may simply enter cpplint blinky/src/main.cpp.

Run an example that produces errors/warnings

One of the common errors detected by cpplint for C++ programs is the use of C-style type casts. The error is detected because in C++, one should use the C++ type cast operators rather than C-style casts (e.g. (int) value). This makes conversions more robust and better documented. For more details, you may read the task of the embedded C++ lessons dedicated to the conversion topic.

For demonstrating how cpplint detects the issue, it is enough to add the following code in your main() function.

int val = 3;
float fval = val * 4.0;
val = (int) fval;
If you run cpplint main.cpp with the modified “main.cpp” file, you should get the following error message:
main.cpp:21:  Using C-style cast.  Use static_cast<int>(...) instead  [readability/casting] [4]
If you modify the code as
val = static_cast<int>(fval);
then the correction should be accepted by cpplint.

Issues detected by cpplint

There may be issues flagged by cpplint that may seem not trivial. If some issues are not clear to you, you may:

  • check Google’s Styleguide concerning the rationale of the rule
  • have a look at the Styleguide Script as it may help the understanding
  • disable a rule with the --filter option, with a clear written justification.

Copyrighting your work

No matter what software one writes, a copyright shall always be specified - no matter whether open source or proprietary in its nature. With cpplint, in case you forget to apply this rule, the following error will be shown ” No copyright message found. You should have a line: Copyright [year] <Copyright Owner>” in any file containing code.

An example of such copyright can be found below:

  /**
  ******************************************************************************
  * @file        : monnalisa.hpp
  * @brief       : pensive woman module
  * @author      : Leonardo Da Vinci <leo@davinci.net>
  * @date        : 19. March 1503
  ******************************************************************************
  * @copyright   : Copyright (c) 1503 
  *                Haute école de peinture de Florence
  * @attention   : SPDX-License-Identifier: MIT OR Apache-2.0
  ******************************************************************************
  * @details
  * Pensive woman module for impressing humankind
  ******************************************************************************
  */

Static C++ Code Analysis: cppcheck

cppcheck is a static analysis tool for C/C++ code. It helps to detect bugs based on pre-defined rules that may be adapted to different needs - also for embedded software.

Static analysis means that the analysis happens on the code itself and not on a running program. It focuses on detecting code that:

  • may produce undefined behavior,
  • uses patterns that may be dangerous, or
  • do not follow the defined coding style.

Installation

In order to install it, head to cppcheck - Download, download and install the appropriate package (while ignoring Windows warning as the installer is not signed) - make sure you install Python Addons as well.

Do not forget to add the application to your $PATH (as the installer is not doing it for you…).

Run cppcheck --version for checking that the installation was successful. At the time of writing, the latest version was v2.18.0.

Run a first cppcheck analysis

For our first analysis - to ensure all works - we will make use of the blinky program.

Run the cppcheck tool and inspect the results. You can run the tool for analyzing the “src/main.cpp” file by running cppcheck blinky/src/main.cpp The analysis should run smoothly and you should not get any warning.

Run an analysis that produces errors/warnings

If you add the following two lines in your main() function:

char a[10];
a[10] = 0;
then when running cppcheck again, you should get the following error:
main.cpp:25:7: error: Array 'a[10]' accessed at index 10, which is out of bounds. [arrayIndexOutOfBounds]
     a[10] = 0;
The bug of accessing an array element that is out of bounds is detected by cppcheck.

It is important to point out that, depending on the compiler configuration, this bug may also be detected by the compiler. When compiling the modified code, you may indeed see a similar warning in the compile output:

[Warning] main.cpp@25,6: array index 10 is past the end of the array (which contains 10 elements) [-Warray-bounds]
This demonstrates that the compiler itself does perform some static analysis and can generate warnings or errors. Since C++ does not perform any range check at runtime, detecting possible out of bounds access at compile time is even more important. With the standard compiler flags, such a bug may not be considered as an error but it is possible to turn it to an error by adding the “-Werror=array-bounds” compiler flag.

Adding exceptions

For adding exceptions to cppcheck analyses, one solution is as follows :

  • Add a “cppcheck_suppressions.txt” file at the root of your workspace or at the root of your application. In this file, add the required exceptions such as:
    cppcheck_suppressions.txt
    // suppress missing system include and standard include
    missingIncludeSystem:*
    missingInclude:*
    unusedStructMember:*.hpp
    unusedFunction:*.hpp
    
  • When launching cppcheck, add --suppressions-list=cppcheck_suppressions.txt as parameter of the command.

In this way, the exceptions added to the file will prevent these errors to be notified by cppcheck.

Fixing issues found by any of the tools

It is important that any fix/bug correction made to your code are done using the proper git branch process. For this purpose, you need to:

  • Create a dedicated branch on your repository: you should create a different dedicated branch for a specific code release and you should name it accordingly.
  • Fix the identified issues in this branch: no other changes should be implemented in this particular branch and in particular, implementing fixes and features should not be mixed.
  • Commit your changes: add a clear commit message for each specific change implemented in this branch. Remember that small commits are usually better than larger ones. So, you should commit one change at a time and not all changes at once.

Putting all together: pre-commit

You are now capable of checking your code and of implementing fixes to it by following the proper git guidelines. We still need to make sure that any change in the code goes through the entire continuous checking pipeline. How can one ensure this?

One way would be to check it centrally using a CI/CD pipeline on a git repository, but that would be late (and consume energy for nothing). One probably better approach is to use pre-commit, that does exactly what its name implies. pre-commit allows to run a serie of checks prior to committing.

Installation

In order to install it, head to https://pre-commit.com/ and follow the instructions.

Using it

So, once installed, we add all the tools seen so far in the pre-commit phase by following these instructions:

  • create a “.pre-commit-config.yaml” file at the root of your git project with the following content:

    .pre-commit-config.yaml
    files: ^(bike_computer/src/main.cpp)|^(bike_computer/src/common)|^(bike_computer/src/static_scheduling)|^(bike_computer/tests)
    exclude: .*\.(yaml|conf|overlay|txt|bmp|png)$|(Kconfig)$
    repos:
    - repo: https://github.com/pre-commit/pre-commit-hooks
      rev: v6.0.0
      hooks:
      -   id: check-yaml
          args: [--allow-multiple-documents]
      -   id: end-of-file-fixer
      -   id: trailing-whitespace
    - repo: https://github.com/pre-commit/mirrors-clang-format
      rev: 'v21.1.1'
      hooks:
      -   id: clang-format
    - repo: https://github.com/cpplint/cpplint
      rev: '2.0.2'
      hooks:
      -   id: cpplint
    - repo: local
      hooks:
      -   id: lizard
          name: lizard
          entry: lizard
          language: system
          args: [-C 20]
    - repo: local
      hooks:
      -   id: cppcheck
          name: cppcheck
          require_serial: true
          entry: cppcheck --enable=all --suppressions-list=cppcheck_suppressions.txt --inline-suppr -i ../zephyr --std=c++14 --error-exitcode=1 -v --checkers-report=cppcheck-report.txt
          language: system
    

  • add .pre-commit-config.yaml to your git repository

  • install the hooks with pre-commit install
  • run the command manually by issuing pre-commit run --all-files
  • if you did a good job in fixing the issues manually, all will be green.

For a better understanding of pre-commit configuration, answer to the questions in Configuring .pre-commit.

That’s it!. From now on, all code changes will undergo the specified checks.

Wrap-Up

At this point, your git repository should contain the following:

  • the code developed in the Getting started codelab.
  • the test programs developed in the Testing codelab.
  • the configuration files for all tools presented in this codelab, including the “.pre-commit-config.yaml” file.

The code should be compliant with all adopted rules and you should be capable of implementing features and fixes to the program by following all guidelines and applying the appropriate git process.

If you have accomplished all of it, you are ready to deliver the project, phase 1.

Metrics and static analysis - Going beyond

Although we will use the above tools throughout the course, there is a multitude of other metrics that will help you assess the code quality. Scitool Understand offers you many metrics or static analysis options. Free academic licenses exist for the tool and you are free to explore this further possibility.