C/C++/Objective-C

C/C++/Objective-C analysis is officially registered as CWE Compatible.

Supported Compilers

  • 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, and Apple Silicon

Prerequisites

SonarScanner

Analysis of C/C++/Objective-C projects requires the SonarScanner CLI.

Build Configuration

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:

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.
  • You are on macOS with Apple Silicon hardware (ARM architecture).

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:

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 makexcodebuild and 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-dump.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. 

 * 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 relative to the project directory (`build_wrapper_output_directory` in these examples).


Sample sonar-project.properties

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

It is recommended to gather all your code trees in a subdirectory of your project to avoid analyzing irrelevant source files like files generated by your build tool. You can specify this subdirectory by setting the property sonar.sources accordingly. In this example, we named it src.

  • 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.

Important Notes

  • 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. While this is straightforward while running these two steps on the same host, it is worth considering 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 necessary and can be neither displaced nor discarded.

Building with Bazel

Bazel recommends that you use the --batch parameter when running in a continuous build context. 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

Compilation Database is a JSON file format introduced by the LLVM project. It contains the compile commands used to build a project. It can be generated by tools like CMake and Ninja.

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 trees 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 src.

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.

Important Notes

  • 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.

Language-Specific Properties

Discover and update the C/C++/Objective-C specific properties in: Project Administration > General Settings > C / C++ / Objective-C

Unsupported Properties

sonar.tests

The sonar.tests property is used to identify the directories containing test source files. Identifying test files helps the analyzers to tune their rules. For example, the analyzers can enable test-specific rules and disable rules that don't make sense in the context of testing.

The C/C++/Objective-C analyzer currently analyzes main and test source files in the same way. Consequently, sonar.tests is not yet supported; the analyzer ignores it.

If you wish to analyze test source files, you should include them in the sonar.sources property.

Analysis cache

The C/C++/Objective-C analyzer can cache the analysis results and reuse them during another analysis.

The cached analysis results speed up subsequent analyses by analyzing the only things that have changed between the two analyses.

  • Enable cache by setting:
sonar.cfamily.cache.enabled=true sonar.cfamily.cache.path=relative_or_absolute_path_to_cache_location.

 Note that each project should use a dedicated path. To fully benefit from this feature you should configure your CI system to persist the cache path between runs.

  • If you prefer not to enable cache and want to turn off the console and UI warnings, you should explicitly disable it by setting: 
* sonar.cfamily.cache.enabled=false


Parallel Code Scan

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.

Targeted C++ standard

The analyzer targets a specific version of the C++ language to tune the rules in the activated quality profile. This reporting standard is used to:

  • Suppress rules that cannot be applied. For example, rules that suggest using c++20 features while the code is compiled with c++17.
  • Adjust rules' messages to suggest the proper fix according to the standard used. For example, a rule that suggests using std::ranges::any_of with c++20 will be tuned to suggest using std::any_of with an older standard.

By default, the reporting standard version is the version that is used to compile the code. This is ideal for most projects. However, there are some edge cases where there is a need to use a reporting standard that is different from the compilation standard. For this reason, we provide the following scanner property to adjust the reporting standard:

sonar.cfamily.reportingCppStandardOverride=c++98|c++11|c++14|c++17|c++20

This property is only recommended to be used in the case where a project has to comply with a standard older than the one it is compiled with. This can happen if:

  • The compiler doesn't allow to set a specific standard. For example, MSVC doesn't allow specifying a standard older than c++14.
  • The project wants to be compiled with the latest standard while still being compliant with an older standard.

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 begin step.

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 begin step with the Build Wrapper output parameter /d:sonar.cfamily.build-wrapper-output=<build_wrapper_output_directory>
  • Add execution of Build Wrapper to your normal MSBuild build command
  • Execute the SonarScanner for MSBuild end step to complete the analysis

For example:

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++11since-c++14since-c++17 and since-c++20 mark these rules for the corresponding C++ standard version. C++ rules not carrying any of these three tags have been 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


© 2008-2022, SonarCloud by SonarSource SA. All rights reserved.