doc/guides/build-system/static_analysis.md
Static Analysis is a process of analyzing software without executing it. This is particularly useful for embedded software that requires special hardware to run, as it allows its use in the CI even without integrating the target hardware into the CI infrastructure.
While there are plenty of static analysis tools, the following will focus only on the built-in static analysis capabilities of GCC and LLVM.
With GCC, static analysis is part of the regular build process by setting the
flag STATIC_ANALYSIS=1 (either as an argument to make or as an environment
variable).
Since new warnings pop up during compilation with static analysis that --
unless compiling with WERROR=0 -- are propagated to errors, modules need to
explicitly declare compatibility with static analysis. They do so by adding the
following snippet to the module's Makefile:
# this module is expected to pass static analysis
MODULE_SUPPORTS_STATIC_ANALYSIS := 1
:::note
MODULE_SUPPORTS_STATIC_ANALYSIS can also be passed in as a parameter to
make or via an environment variable to force the use of static analysis, even
for modules that do not declare support. You might want to also pass WERROR=0
to complete the build despite the new issues found by static analysis.
:::
:::caution
Since static analysis is part of the regular build process, incremental builds
will provide only partial coverage. Use make clean to do a fresh build.
:::
By default, GCC will output the static analysis to stdout just like any other
compilation error. It is possible to create output using the
Static Analysis Results Interchange Format (SARIF) format instead by
adding the WRITE_SARIF=1 flag either as a parameter to make or via an
environment variable. SARIF is a cross-vendor standard format based on JSON
(see the SARIF specification for more details). Even though the
format is also human readable, using a dedicated SARIF viewer (either as local
program or as web app) is likely providing a better user experience.
:::caution
All required SARIF output features are
supported since release 15. Compiling with WRITE_SARIF=1
using older releases of GCC will fail.
:::
make STATIC_ANALYSIS=1 BOARD=native64 -C examples/basic/default clean all
make STATIC_ANALYSIS=1 MODULE_SUPPORTS_STATIC_ANALYSIS=1 WERROR=0 BOARD=native64 -C examples/basic/default clean all
make STATIC_ANALYSIS=1 MODULE_SUPPORTS_STATIC_ANALYSIS=1 WRITE_SARIF=1 WERROR=0 BOARD=native64 -C examples/basic/default clean all
With LLVM, static analysis is a distinct make goal: make scan-build. It behaves
similarly to a full build, but creates an HTML summary containing all the
findings and opens that in a browser once it completes.
If no issues are found, no HTML will be created and the browser will not be opened. In that case the console output will look like this:
scan-build: Removing directory '<DIRNAME>' because it contains no reports.
scan-build: No bugs found.
Showing most recent report in your web browser...
No report found
:::note
Unlike GCC's static analysis, make scan-build will perform a full rebuild
automatically. So there is no incremental build footgun to avoid.
:::
The LLVM static analysis does not use the variable
MODULE_SUPPORTS_STATIC_ANALYSIS, so it will enable static analysis for all
modules. However, it will treat the additional findings as warnings rather than
as errors, so that builds won't fail.
make BOARD=native64 -C examples/basic/default scan-build