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
python3to be installed on your machine, which is the case since we are usingwestto 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
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
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;
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]
val = static_cast<int>(fval);
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
--filteroption, 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;
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;
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]
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.txtas 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
gitproject with the following content:.pre-commit-config.yamlfiles: ^(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.yamlto yourgitrepository - 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.