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:
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…
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:
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?
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)
Thank you very much for sharing the information with us. This is really helpful. I took some time to look at the issue you created on bazel-compile-commands-extractor, and IIRC, this wrapper script was introduced in Bazel 7.
I am interested in understanding the problem further. I tried to reproduce by using hedron_compile_commands on one of the Bazel official examples (using Bazelisk and .bazelversion set to 7.6.0), but the generated compilation database always contained the path to gcc or clang on my Linux machine and I wasn’t able to see this wrapper script on my end. Are you able to reproduce on any of these official examples? Do you know if I need to use any specific Bazel features to get this wrapper script? This information can help us understand the impact of the issue…
Unfortunately, there is no such way at the moment. For the time being, and with the information I currently have, I can only suggest the following workarounds:
Pre-process the compilation database generated by hedron_compile_commands before feeding it to SonarQube for IDE, by replacing the wrapper script with the path to the actual compiler being used.
Use SonarQube build-wrapper to generate the compilation database for your project. See the docs here. Note that build-wrapper requires to wrap a clean build in order to generate a full compilation database. Additionally, it is recommended to deactivate Bazel’s sandbox, see here.
Look for another alternative to generate the compilation database for the project.
This looks really nice, thanks for sharing the information. I think it would be great if hedron_compile_commands could unwrap this in the generated compilation database.