C/C++/Objective-C analysis is officially registered as CWE Compatible.
- Any version of Clang, GCC, and Microsoft C/C++ compilers
- Any version of Intel compiler for Linux and macOS
- ARM5 and ARM6 compilers
- IAR compilers for ARM, Atmel AVR32, Atmel AVR, Renesas H8, Renesas RL78, Renesas RX, Renesas V850, Texas Instruments MSP430, and for 8051
- QNX compilers
- Texas Instruments compilers on Windows and macOS for ARM, C2000, C6000, C7000, MSP430, and PRU
- Wind River Diab and GCC compilers
- Compilers based wholly on GCC including, for instance, Linaro GCC are also supported
Supported Language Standards
- C89, C99, C11, C18, C++03, C++11, C++14, C++17, and C++20 standards
- GNU extensions
Supported Runtime Environments
- Microsoft Windows on x86-64
- Linux on x86-64
- macOS with version 10.14.3 and later on x86-64
Analysis of C/C++/Objective-C projects requires the SonarScanner CLI.
For a C/C++/Objective-C analysis to be accurate, the analyzer needs to understand how the code is meant to be compiled. Compilation options, like macro definitions and include directories, can have a huge impact on the generated code and consequently on the analysis results.
There are two alternative ways to provide the build configuration to the analyzer:
- SonarSource Build Wrapper
- Compilation Database
Choosing The Right Tool
The general recommendation is to use Build Wrapper unless you have a good reason not to.
Reasons To Use Build Wrapper
- Build Wrapper enforces running the build before the analysis which ensures that the code is in a good shape for analysis: the code is compilable, the configuration file is not outdated, and the generated source files are available during the analysis.
- In case your build relies on environment variables, Build Wrapper, unlike Compilation Database, stores these variables and uses them during the analysis.
Reasons To Use Compilation Database
- Your build system is not supported by Build Wrapper.
- You don't want to run a clean build of your project, which is required by Build Wrapper, before the analysis.
Analysis Steps Using Build Wrapper
Build Wrapper is a tool developed by SonarSource to collect information in a JSON file about your build configuration during build time. To run Build Wrapper you should prepend your clean build command with the Build Wrapper executable.
When you wrap your build command with the Build Wrapper, it will run the given command and gather all the configuration required for a correct analysis of C/C++/Objective-C projects such as macro definitions and include directories. The Build Wrapper does not impact your build; it merely monitors it and writes what it learns into files in a directory you specify.
You should download the Build Wrapper directly from SonarCloud:
- Download Build Wrapper for Linux
- Download Build Wrapper for macOS
- Download Build Wrapper for Windows
Unzip the downloaded Build Wrapper and configure it in your
PATH because doing so is just more convenient.
- Execute Build Wrapper as a prefix to your usual clean build command. A clean build command should always build the project from scratch. The examples below use
MSBuild, but any build tool that performs a full build can be used:
// example for linux build-wrapper-linux-x86-64 --out-dir build_wrapper_output_directory make clean all // example for macOS build-wrapper-macosx-x86 --out-dir build_wrapper_output_directory xcodebuild clean build // example for Windows build-wrapper-win-x86-64.exe --out-dir build_wrapper_output_directory MSBuild.exe /t:Rebuild /nodeReuse:False
At the end of your build, a build-wrapper.json file should be generated in the specified output directory. This file contains information about the translation units that were built by your build command. Any file that doesn't end up in a compiled translation unit will not be analyzed. As a consequence, source files that are not compiled and header files that are not included in any compiled source file will not be analyzed. Note that executing build-wrapper doesn't interfere with your build command. There is no need to build a second time without a build-wapper. Just make one build and wrap it up.
Add the property
sonar.cfamily.build-wrapper-output in the sonar-project.properties file at the root of your project. You should set it to the path of the Build Wrapper output directory relatively to the project directory (
build_wrapper_output_directory in these examples)
sonar.projectKey=myFirstProject sonar.projectName=My First C++ Project sonar.projectVersion=1.0 sonar.sources=src sonar.cfamily.build-wrapper-output=build_wrapper_output_directory sonar.sourceEncoding=UTF-8 sonar.host.url=YourSonarCloud/SonarQubeURL
You should structure your project so that all the code to be analyzed in a distinct subdirectory. This lets you ignore generated files and other irrelevant material simply by setting the
sonar.sources property accordingly. In this example, we named it
- Execute the SonarScanner (
sonar-scanner) from the root directory of your project. For more SonarScanner related options, consult SonarScanner CLI.
- Follow the link provided at the end of the analysis to browse your project's quality metrics in the UI.
- The Build Wrapper collects information about the build including absolute file paths (source files, standard headers, libraries, etc...). Later on, SonarScanner uses this information and needs to access those paths. Whereas this is straightforward while running these 2 steps on the same host, it is worth some consideration when using any sort of containerization. A consequence of this is that C / C++ / Objective-C analysis is NOT supported by SonarScanner CLI Docker image.
- The Build Wrapper generates the files build-wrapper.log and build-wrapper-dump.json in its output directory. Both these files contain a dump of the environment. In some contexts, it can be a security concern. Whereas the former is a log file and is not needed for the analysis to run, the latter is needed and cannot be either displaced or discarded.
Building with Bazel
When using the BuildWrapper, you are in such context.
Also, you need to deactivate the sandbox mechanism of Bazel so that the compiled file paths can be retrieved after the compilation phase.
Here is an example of the BuildWrapper command with Bazel parameters on macOS:
build-wrapper-macosx-x86 --out-dir bw bazel --batch build --spawn_strategy=local --strategy=Genrule=local --bazelrc=/dev/null //main:hello-world
Building with MsBuild
Instead of starting new nodes when building your code, MsBuild can reuse previously launched build nodes. In that case, the Build Wrapper will not be able to monitor files compiled on these nodes. Therefore, we advise disabling this feature by using the nodeReuse:False command-line option.
Analysis Steps Using Compilation Database
First, generate the Compilation Database file.
Then, add the property
sonar.cfamily.compile-commands in the sonar-project.properties file at the root of your project. You should set it to the path of the Compilation Database file relatively to the project directory (
compile_commands.json in these examples). Here is an example sonar-project.properties file:
sonar.projectKey=myFirstProject sonar.projectName=My First C++ Project sonar.projectVersion=1.0 sonar.sources=src sonar.cfamily.compile-commands=compile_commands.json sonar.sourceEncoding=UTF-8 sonar.host.url=YourSonarCloud/SonarQubeURL
It is recommended to gather all your code tree in a subdirectory of your project to avoid analyzing irrelevant source files like third-party dependencies. You can specify this subdirectory by setting the property
sonar.sources accordingly. In this example, we named it
Execute the SonarScanner (
sonar-scanner) from the root directory of your project:
sonar-scanner. For more SonarScanner related options, consult SonarScanner CLI. Follow the link provided at the end of the analysis to browse your project's quality metrics in the UI.
- The analysis environment should be the same as the build environment, the analyzer may need to access the build-related environment variables. For example, when using Microsoft Visual C++ compiler make sure to execute the analysis from the same Visual Studio Developer Command Prompt you use to build your project. The command prompt sets some environment variables, like
INCLUDE, that need to be set during the analysis.
- Make sure that the tool you are using generates the right compile commands. To do so, you should verify that the Compilation Database contains your actual build commands. Also, you can run one of the compilation commands and verify that it succeeds.
Discover and update the C/C++/Objective-C specific properties in: Project Administration > General Settings > C / C++ / Objective-C
The plugin is able to cache the results of the analysis and reuse them during another analysis. This has the benefit of speeding up subsequent analysis by analyzing only things that changed between the two analyses.
- Enable cache by setting:
sonar.cfamily.cache.path=relative_or_absolute_path_to_cache_location. Note that each project should use its own path. To fully benefit from this feature you should configure your CI system to persist the cache path between runs.
- If you prefer to not enable cache and want to turn off the console and UI warnings you should explicitly disable it by setting:
Parallel Code Scan
It is possible to use all the cores available on the machine running the code scan. This can be activated by configuring the property
sonar.cfamily.threads at the scanner level. Its default value is 1.
By default, the analyzer tries to parallelize the analysis of compilation units; it spawns as many jobs as logical CPUs available on the machine.
If required, it is possible to customize the number of scheduled parallel jobs by configuring the property
sonar.cfamily.threads=n at the scanner level, where
n is an integer indicating the maximum number of parallel jobs.
You should consider setting the
sonar.cfamily.threads property only when the automatic detection of the number of logical CPUs cannot detect the desired number. A typical example is when the analysis should not consume all the available computing resources to leave room for other tasks running in parallel on the same machine.
When setting the
sonar.cfamily.threads property, you should set it to a value less or equal to the number of logical CPUs available. Over-committing doesn't accelerate the analysis and can even slow it down.
Solution with a Mix of C# and C++
When you have a Solution made of C++ and C#, in order to both use the Build Wrapper and have an accurate analysis of the C# code, you must use the SonarScanner for MSBuild. The SonarScanner for MSBuild does not handle the
sonar-project.properties files so the Build Wrapper output directory will have to be set during the MSBuild
Note that in this scenario source code stored in shared folders, not considered as a "Project" by Visual Studio, won't be scanned.
- Download and install both the SonarScanner for MSBuild and the Build Wrapper (see Prerequisites section).
- Execute the SonarScanner for MSBuild
beginstep with the Build Wrapper output parameter
- Add execution of Build Wrapper to your normal MSBuild build command
- Execute the SonarScanner for MSBuild
endstep to complete the analysis
SonarScanner.MSBuild.exe begin /k:"cs-and-cpp-project-key" /n:"My C# and C++ project" /v:"1.0" /d:sonar.cfamily.build-wrapper-output="build_wrapper_output_directory" build-wrapper-win-x86-64.exe --out-dir build_wrapper_output_directory MSBuild.exe /t:Rebuild /nodeReuse:False SonarScanner.MSBuild.exe end
Measures for Header Files
Each time we analyze a header file as part of a compilation unit, we compute for this header the measures: statements, functions, classes, cyclomatic complexity and cognitive complexity. That means that each measure may be computed more than once for a given header. In that case, we store the largest value for each measure.
Language-Specific Rule Tags
On top of the built-in rule tags, a few additional rule tags are specific to C/C++/Objective-C rules.
C++ Standard Version Related Rule Tags
Some rules are relevant only since a specific version of the C++ standard. These rules will run only when analyzing a C++ code compiled against a later or equal standard version. Tags
since-c++20 mark these rules for the corresponding C++ standard version. C++ rules not carrying any of these 3 tags start running since C++98.
Implementation Related Rule Tags
full-project: this tag is for rules that do cross translation units analysis. For these rules to work properly, it is important to analyze the entire project. Excluding part of the project from the analysis will impact the accuracy of these rules: it might lead to false positives or false negatives.
symbolic-execution: this tag is for rules that reason about the state of the program. They usually work together to find path-sensitive bugs and vulnerabilities. Once a fatal state of the program is reached, one issue will be raised and the symbolic execution analysis of the current path will stop. For that reason, it is not recommended to evaluate these rules independently of each other as it might give a false sense of undetected issues. It is important to keep in mind that we are always working on improving these rules, as symbolic execution can never be perfect.
External standard Rule Tags
- based-on-misra: this tag is for rules that address the same kind of issues as MISRA rules, but that do not entirely correspond to what MISRA specifies (usually to make them less strict).