Issues with compile_commands.json generated from bazel

We’re using bazel as our build system along with GitHub - hedronvision/bazel-compile-commands-extractor: Goal: Enable awesome tooling for Bazel users of the C language family. to extract a compilation database. The compilation database is not directly referencing the compiler that was used, but rather a build wrapper script like external/local_config_cc/cc_wrapper.sh. I’ve had to manually replace this string in the compilation database by e.g. clang++ to have SonarLint (in VS Code) work, otherwise the following log message is output in the debug messages and no analysis is done:

[Info - 10:11:20.489] [com.sonar.cpp.analyzer.UnknownDriver : sonarlint-analysis-engine] Ignore unknown compiler: external/local_config_cc/cc_wrapper.sh

It would be great if there was a setting to override the compiler, or alternatively, if SonarLint tried to figure out what the compiler was based on other flags etc.

I’m using v4.18.0 of sonarsource.sonarlint-vscode .

Hello @reimerix, and thank you for taking the time to share the feedback and the suggestions with us,

The analyzer currently relies on the compiler identification to determine how to interpret the flags. It additionally needs to communicate with the compiler to retrieve some information (e.g. system include directories, …etc).

A problem that comes to mind is that the compilation database may contain different entries that use different compilers. The way I see this at the moment, is that such a setting would need to accept a map of compiler paths to remain useful in such a case, which makes it less convenient for users.

Currently, recognizing the compiler is a prerequisite to interpreting the flags (as described above). I think it is possible in theory to have a heuristic to “guess” the compiler based on the seen flags, but in some of the supported compilers, they are similar, and my concern is that it may result in confusing behavior if the guess was incorrect.

Do you know more details about the purpose of this wrapper script, and in what conditions it is used by bazel-compile-commands-extractor? For example, is it known to always wrap clang/gcc? Is it generated on all platforms? What is its purpose and how different are the flags provided to the script different from the ones seen by the compiler executable?

For example, if it is an internal implementation detail of bazel, maybe the bazel-compile-commands-extractor might be interested in “seeing through” these wrapper scripts and writing the actual command that was passed to the compiler instead?

I think that the answers to these questions may help us think about other solutions to provide better support for this case…

Thanks again for the feedback,
Michael

Hi all,

This is a big problem for my organisation also, as we use Bazel throughout and haven’t been able to fully adopt SonarQube because of this limitation.

The wrapper in question is generated from these bazel templates:

Basically, they append some env variables and possibly other options, but mostly just template in the compiler selected by the bazel toolchain (gcc, clang etc) and forward the arguments provided to it.

As for solutions:

  1. Is there a way to override/default which compiler is assumed by sonarqube? Can we set a setting in the vscode extension that falls back to for example clang when the compiler in compile commands isn’t recognised?
  2. I’ve started a PR to that specific tool with a fix that unwraps which compiler is used in compile commands - Added patch to resolve compiler from inside cc_wrapper.sh script. by Attempt3035 · Pull Request #248 · hedronvision/bazel-compile-commands-extractor · GitHub

The solution to determine which compiler is used is the equivalent of this script:

#!/bin/bash

# DEBUG & Traps need to be inherited by subshells
set -T

# shellcheck disable=SC2154
# A trap to capture the compiler command, even if it's a path to the executable
trap 'if [[ $BASH_COMMAND =~ ^[[:space:]]*(/[^[:space:]]*/)?(clang|gcc)([[:space:]]|$|[^-]) ]]; then
          echo $(read -ra arr <<< "$BASH_COMMAND" && echo "${arr[0]}") # Split BASH_COMMAND into an array and read just the first element
          exit 0  # End execution now that we have the compiler command
      fi' DEBUG

# shellcheck disable=SC1090
# Run the passed-in script within this script's context
source "$1"

It might be good if SonarQube could implement something similar to this to attempt to query the script in question to find a suitable compiler, although I’m guessing if this happens with other tools they may have less controlled scripts which may do other unnecessary tasks when being sourced (the bazel wrapper is very simple so this works well)