Skip to content

Robust Development Methodologies (II)

Introduction

Thus far, you have created, run and debugged your own application developed with ARM Keil. However, you have little to no knowledge whether this application could be used - from a qualitative standpoint - in a safety environment. This codelab aims at adding this dimension to your project so as to have sound foundations for future work.

What you’ll build

In this codelab, you will understand the required tools and guidelines for building qualitatively good SW - attitude that should be used while creating any type of SW. You will also understand how to interpret the results delivered by the tools used in order to improve your work.

What you’ll learn

  • How to set up the tools for ensuring sufficiently good SW quality.
  • Continue ensuring quality throughout the development lifecycle.
  • Understand the different elements composing quality and to interpret the results provided by the different analysis tools.

What you’ll need

Install the SW Quality checkers - cloc, lizard, clang-formatand cpplint

You need python3 installed

You likely have it already - but in case you did not, follow the following instructions

During this course, we will use cloc, lizard, clang-format, cpplint (and pre-commit later) for ensuring our code conforms to expected quality.

In order to install the checker tools:

  • head to clang-format - LLVM Download Page, download and install the appropriate package ( here a direct link ). Important: make sure to ignore the warning during installation and install the tool in the PATH for all users. This tool will be used for formatting the C/C++ code.
  • enter pip3 install cpplint to install a linter for our code. This will be used for ensuring compliancy to Google styleguide . Remember, it is important to have 1 styleguide. Whether this is the best is up to debate (as we should tailor it to C anyhow for instance).
  • head to cloc - releases to download and install the appropriate package ( here a direct link ). Save it on your harddisk and add it to the $PATH.
    IMPORTANT: do not yet use version 2.xx (or at your own risk).
  • issue pip3 install lizard to install lizard.

Note

In case you had a different operating system, you can also issue:

  • clang-format:
    • MacOS: brew install clang-format
    • Linux: sudo apt install clang-format
  • cloc
    • MacOS: brew install cloc
    • Linux: pip3 install cloc

  • cpplint
    • MacOS: brew install cpplint
    • Linux: pip3 install cpplint

Obviously, these tools may be available as plugin in various IDEs ( VsCode, CLion, …) you may use regularly.

Test your tools from the command line before continuing

Ensure that your tools are working by issuing the following commands:

  • clang-format --version
  • cpplint --version
  • cloc --version

Not finding the tool from the command line?

In case Windows did not find the tool, check that it is indeed present in your $PATH.

Configure the tools

Now that you have installed the tools, it is time to make use of them. You first start by checking they do work and then move on to test what your code looks like.

Run a first analysis

To test lizard functionality (and be surprised by the complexity of a function), go to where your simple car project is located and issue: lizard RTE/Device/STM32L475VGTx/STCubeGenerated/Drivers/STM32L4xx_HAL_Driver/Src/stm32l4xx_hal_spi.c

You should be able to see that HAL_SPI_TransmitReceive has a whopping cyclomatic complexity of 62. Open the file and see it yourself what that 62 means as far understanding a foreign piece of SW.

In order to analyze your own project, head to the root of your simple car project, run the lizard tool and inspect the results. You can run the tool by entering:

// use lizard (note: "Application" is the folder in which you put your own application)
lizard Application RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c

Question 1

  1. With lizard, what does the option -C mean?
  2. What C value would you set according to the theory?
Solution
  1. Threshold for cyclomatic complexity number warning
  2. Ideally 10 (12 topmost value)

Subsequently, run the cloc tool and inspect the results. You can run the tool by entering:

// use cloc (note: "Application" is the folder in which you put your own application)
cloc Application RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c

Afterwards, check out what clang-format does. For doing so, first create a .clang-format at the root of your project with the following content:

---
  BasedOnStyle: Google
  IndentWidth: 4
---
  Language: Cpp
  ColumnLimit: 100
  AlignConsecutiveAssignments: true
  DerivePointerAlignment: false
  PointerAlignment: Left
  BinPackArguments: false
  BinPackParameters: false
Subsequently, run the command clang-format -i RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c.

Question 2

Respond to the following questions:

  1. has the file been modified?
  2. how can you check that? (write down the command)
  3. what is the meaning of option -i?
  4. what does ColumnLimit in .clang-format mean?
Solution
  1. Yes, it has
  2. git diff RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c
  3. Inplace edit files, if specified
  4. the maximum length of a line


Lastly, have a look at what cpplint. Issue:

  cpplint Application/* RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c
and check how many violations there are. You will fix those in the next section.

Fixing the issues

You have tested most tools and inspected results. However, the goal is to ensure qualitatively good code. As a result:

  • create a dedicated git branch for fixing the eventual issues
  • use lizard -C 10 Application RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c .
    Fix all the functions - if any - crossing the 10 maximal value for the cyclomatic complexity.
  • commit your changes (git add * and git commit -m "Fixed cyclomatic complecity issues")
  • apply clang-format -i Application/* RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c
  • commit your changes (git add * and git commit -m "Fixed formatting issues with clang-format")
  • run cpplint Application/* RTE/Device/STM32L475VGTx/STCubeGenerated/Core/src/main.c
  • commit your changes (git add * and git commit -m "Fixed Google Styleguides issues")

REMEMBER: make small commits!

As we learned, small commits are instrumental to a proper way of developing. Make sure to respect it when you are fixing the issues. That is, you will commit only one step at a time - not all changes at once.

Use spaces, not tabs

Make sure your editor (including ARM Keil) makes use of spaces instead of tabs. Here the link to ARM Keil’s user manual to change the behaviour accordingly (and act according to the chosen styleguide).

Note

There may be issues flagged by cpplint that may not seem trivial. However:

  • check Google’s Styleguide concerning the rationale of the rule
  • control the Styleguide Script as it may help the understanding
  • be aware of compiler’s behaviours. For instance const static aVariable is accepted by the compiler but it is not standard compliant ( static const aVariable is)
  • although one could disable a rule with -filter, it is strongly suggested not to - and if so, only with a written justification

Warning

Be sure you have created a CPPLINT.cfg file at the root of your project containing, at least, the line length aligned with .clang-format. Moreover, prevent cpplint from expecting include files in the same directory.

# Stop searching for additional config files.
set noparent
# Limit line length.
linelength=100
# Header files are not always placed in the same directory
filter=-build/include
You will find other filters that can be activated in cpplint manual (aka ccplint.py 😉).

Copyrighting your work

No matter what SW one writes, a copyright shall always be specified - no matter whether open source or proprietary in its nature. With cpplint, in case one forgot, the following error will be shown ” No copyright message found. You should have a line: Copyright [year] <Copyright Owner> “. An example of such copyright can be found below:

  /**
  ******************************************************************************
  * @file        : monnalisa.h
  * @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 mankind
  ******************************************************************************
  */

Putting all together: pre-commit

Now that you are capable of checking the code, a question arises: how to ensure to always remember to execute this? One way would be to check it centrally on a CI/CD pipeline, but that would be late (and consume energy for nothing). Do not worry!

We got you covered: pre-commit does exactly what its name implies. It will run a serie of checks prior to committing. In order to install it, head to https://pre-commit.com/ and follow the instructions.

So, once installed, we put all the tools seen so far by following the following instructions:

  • create a .pre-commit-config.yaml at the root of your git project with the following content:
files: ^(Application)|^(RTE\/Device\/STM32L475VGTx\/STCubeGenerated\/Core\/src\/main\.c)
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
  rev: v4.3.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: 'v14.0.6'
  hooks:
  -   id: clang-format
- repo: https://github.com/cpplint/cpplint
  rev: '1.6.1'
  hooks:
  -   id: cpplint
- repo: local
  hooks:
  -   id: lizard
      name: lizard
      entry: lizard
      language: system
      args: [-C 12]
  • 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, all will be green
  • That’s it!. From now on, all code changes will undergo the specified checks

Question 3

Respond to the following questions:

  1. what does ^(Application)|^(RTE\/Device\/STM32L475VGTx\/STCubeGenerated\/Core\/src\/main\.c) under files mean? (hint: check https://regex101.com/)
  2. what does [-C 12] mean?
  3. what are the implications of language: system?
  4. is there a way to ensure that MISRA C:2012 checks are run automatically?
Solution
  1. It is a regex specifying on what the hooks will be applied
  2. It specifies the maximum cyclomatic complexity accepted
  3. One needs to a) ensure the presence of the tool on the machine, b) handle the updates manually and c) manage the accessibility of the tool (e.g. tool present in the $PATH)
  4. Yes, there is. One can run pre-commit run cppcheck --all-files once .pre-commit-config.yaml is configured as follows (or similar):
       - repo: local
         hooks:
         -   id: cppcheck
             name: cppcheck
             entry: cppcheck
             language: system
             args: [--addon=misra.json --force --inline-suppr --suppress=*:RTE/Device/STM32L475VGTx/STCubeGenerated/Inc/* -IRTE/Device/STM32L475VGTx/STCubeGenerated/Inc -IApplication]
    
    Obviously, it would be best not to rely on language: system ;-)

Run the analysis on your code

On a dedicated branch, run the analysis on your code to find eventual issues in your application (including MISRA). Go about fixing them one at a time and commit the fixes on a dedicated branch (named going_professional).

Important: only run the analysis on main.c contained in YOUR_PROJECT_LOCATION\RTE\Device\STM32L475VGTx\STCubeGenerated\src and Application (or whatever folder you put your own implementation), not those coming from 3rd party. pre-commit will be part of the git repository and will throw no errors.

Metrics - 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, for which you have now received a license, will offer you a plethora of options under the “Metrics->Metrics Browser”. You have access to the metrics definitions by clicking on the following icon: