diff --git a/cmake/sca/clang/sca.cmake b/cmake/sca/clang/sca.cmake new file mode 100644 index 00000000000..9fba161bf07 --- /dev/null +++ b/cmake/sca/clang/sca.cmake @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: Apache-2.0 +# +# Copyright (c) 2025 Alex Fabre + +find_program(CLANG_SCA_EXE NAMES analyze-build REQUIRED) +message(STATUS "Found SCA: clang static analyzer (${CLANG_SCA_EXE})") + +# Get clang analyzer user options +zephyr_get(CLANG_SCA_OPTS) +zephyr_get(LLVM_TOOLCHAIN_PATH) + +# Check analyzer extra options +if(DEFINED CLANG_SCA_OPTS) + foreach(analyzer_option IN LISTS CLANG_SCA_OPTS) + list(APPEND CLANG_SCA_EXTRA_OPTS ${analyzer_option}) + endforeach() +endif() + +# clang analyzer uses the compile_commands.json as input +set(CMAKE_EXPORT_COMPILE_COMMANDS ON) + +# Create an output directory for clang analyzer results +set(output_dir ${CMAKE_BINARY_DIR}/sca/clang) +file(MAKE_DIRECTORY ${output_dir}) + +# Use a dummy file to let clang static analyzer know we can start analyzing +set_property(GLOBAL APPEND PROPERTY extra_post_build_commands COMMAND + ${CMAKE_COMMAND} -E touch ${output_dir}/clang-sca.ready) +set_property(GLOBAL APPEND PROPERTY extra_post_build_byproducts + ${output_dir}/clang-sca.ready) + +# Add a cmake target to run the analyzer after the build is done +add_custom_target(clang-sca ALL + COMMAND ${CLANG_SCA_EXE} --cdb ${CMAKE_BINARY_DIR}/compile_commands.json -o ${CMAKE_BINARY_DIR}/sca/clang/ --analyze-headers --use-analyzer ${LLVM_TOOLCHAIN_PATH}/bin/clang ${CLANG_SCA_EXTRA_OPTS} + DEPENDS ${CMAKE_BINARY_DIR}/compile_commands.json ${output_dir}/clang-sca.ready +) + +# Cleanup dummy file +add_custom_command( + TARGET clang-sca POST_BUILD + COMMAND ${CMAKE_COMMAND} -E rm ${output_dir}/clang-sca.ready +) diff --git a/doc/develop/sca/clang.rst b/doc/develop/sca/clang.rst new file mode 100644 index 00000000000..efc99592b60 --- /dev/null +++ b/doc/develop/sca/clang.rst @@ -0,0 +1,99 @@ +.. _clang: + +Clang static analyzer support +############################# + +Clang Static Analyzer is built on top of Clang and LLVM. +Strictly speaking, the analyzer is part of Clang, as Clang +consists of a set of reusable C++ libraries for building +powerful source-level tools. The static analysis engine used by the +Clang Static Analyzer is a Clang library, and has the capability to +be reused in different contexts and by different clients. + +LLVM provides various methods to run the analyzer on a codebase, +through either a dedicated set of tools (scan-build and analyze-build), +or via command line arguments when running clang ('--analyze'). + +- 'scan-build' utility comes as the most convenient way for projects + using a simple $CC makefile variables, as it will wraps and replace + the compiler calls to perform it's analysis. + +- 'analyze-build' utility is a sub-tool from 'scan-build', it only + relies on a 'compile_commands.json' database to perform the analysis. + +- clang option '--analyze' will run the analyzer alongside the build, but + objects files are not generated, making any link stage impossible. In + our case the first link stage will fail and stop the analysis. + +Because of it's complexe build infrastructure, invoking clang analyzer with +'analyze-build' is the most simple way to analyze a Zephyr project. + +`Clang static analyzer documentation `__ + +Installing clang analyzer +************************* + +'scan-build' and its sub-tool 'analyze-build' come natively with llvm as part of the binaries. +Make sure to have the binary directory accessible into your PATH. + +'scan-build' is also available as a standalone python package available on `pypi `__. + +.. code-block:: shell + + pip install scan-build + +Run clang static analyzer +************************* + +.. note:: + + The analyser requires that the project builds with a LLVM toolchain, and + produces a 'compile_commands.json' database. + +To run clang static analyzer, :ref:`west build ` should be +called with a ``-DZEPHYR_SCA_VARIANT=clang`` parameter, alongside the llvm +toolchain parameters, e.g. + +.. zephyr-app-commands:: + :zephyr-app: samples/userspace/hello_world_user + :board: qemu_x86 + :gen-args: -DZEPHYR_TOOLCHAIN_VARIANT=llvm -DLLVM_TOOLCHAIN_PATH=... -DZEPHYR_SCA_VARIANT=clang + :goals: build + :compact: + +.. note:: + + By default, clang static analyzer produces a html report, but various other + outputs can be selected with options (sarif, plist, html) + +Configuring clang static analyzer +********************************* + +Clang static analyzer can be controlled using specific options. +To get an exaustive list of available options, report to the +'analyze-build' helper and 'scan-build' helper. + +.. code-block:: shell + + analyze-build --help + +Options already activated by default: + +* --analyze-headers : Also analyze functions in #included files. + +.. list-table:: + :header-rows: 1 + + * - Parameter + - Description + * - ``CLANG_SCA_OPTS`` + - A semicolon separated list of 'analyze-build' options. + +These parameters can be passed on the command line, or be set as environment variables. + +.. zephyr-app-commands:: + :zephyr-app: samples/hello_world + :board: stm32h573i_dk + :gen-args: -DZEPHYR_TOOLCHAIN_VARIANT=llvm -DLLVM_TOOLCHAIN_PATH=... -DZEPHYR_SCA_VARIANT=clang -DCLANG_SCA_OPTS="--sarif;--verbose" + :goals: build + :compact: diff --git a/doc/develop/sca/index.rst b/doc/develop/sca/index.rst index c14d1d2df56..0019b10c74a 100644 --- a/doc/develop/sca/index.rst +++ b/doc/develop/sca/index.rst @@ -64,6 +64,7 @@ The following is a list of SCA tools natively supported by Zephyr build system. codechecker sparse gcc + clang cpptest eclair polyspace