Bazel: Bazel incompatible with clang scan-build static analysis

Created on 10 Aug 2016  路  7Comments  路  Source: bazelbuild/bazel

I would like to use bazel with clang's static analysis tool, scan-build, but it appears scan-build doesn't pick up bazel's build execution steps.

If I preface bazel build with scan-build it doesn't detect any compilation:

$ /usr/bin/scan-build-3.8 bazel build //...
scan-build: Using '/usr/lib/llvm-3.8/bin/clang' for static analysis
...compiling a bunch of stuff...
scan-build: Removing directory '/tmp/scan-build-2016-08-10-002447-6841-1' because it contains no reports.
scan-build: No bugs found.

I can force every compilation step to run scan-build by modifying CROSSTOOL as follows, but this isn't ideal as it creates a scan-build report for every file:

  # Inject scan-build before clang
  tool_path { name: "gcc" path: "/usr/bin/scan-build-3.8" }
  compiler_flag: "/usr/lib/llvm-3.8/bin/clang"

Has anyone else looked into scan-build support?

P4 team-Configurability feature request

Most helpful comment

I was finally able to get clang analyzer working with bazel. The trick was to build a compilation database during the build and then execute a script to convert those compile commands into clang --analyze commands.

Here are the steps I took:
Add an experimental_action_listener that generates the compilation database. Forked from this gist, but I had to fix up some json formatting that the clang tools didn't like.
Install the scan-build clang analyzer wrapper tool.
Fiddle with bazel paths and permissions for hours until it finally worked.

Readme and a scattering of files that worked for me:
https://github.com/cybrown-zoox/bazel-clang-analyzer

I was pointed to all this from this discussion thread.

All 7 comments

@lberki do you have any idea?

I don't think you can work around this without telling Bazel about scan-build. Quoting its web page:

_"scan-build has little or no knowledge about how you build your code. It works by overriding the CC and CXX environment variables to (hopefully) change your build to use a "fake" compiler instead of the one that would normally build your project"_

Bazel does use the CC environment variable to look up the C++ compiler, but once it finds it, further changes to CC are not detected, unless you do a bazel clean in between.

Whereas we now have a good story about handling environment variables during actions (http://www.bazel.io/docs/designs/2016/06/21/environment.html), we haven't made up our minds yet about environment variables for environment detection.

@damienmg thinks things are fine the way they are today. @aehlig also had a strong opinion on the matter.

My goal is to get clang static analysis running regularly against our codebase. scan-build (and the associated scan-view) are handy because they give you a full report on precisely how clang static analysis discovered a problem.

If I didn't care about understanding how clang found a problem--only that there was a problem--then I can accomplish that by passing the --analyze option to clang. This produces a warning for every static analysis issue detected by clang.

Problem with --analyze is it writes an XML report into the file specified for output with -o instead of an object file. It skips compilation. So if I add --analyze to my cpp options then bazel blows up on the linker step with "file format not recognized" errors.

So is there a way to either:

  1. Get bazel to run all compilation steps, but skip linking?
  2. Get bazel to run _two_ compilation commands per compilation unit? This way I could run regular clang and clang --analyze in parallel?

For (1), you can try the --compile_only command line option.

For (2), the usual solution is to write your own CROSSTOOL file where the "compiler" Bazel calls is a script that calls the actual compiler twice.

I was finally able to get clang analyzer working with bazel. The trick was to build a compilation database during the build and then execute a script to convert those compile commands into clang --analyze commands.

Here are the steps I took:
Add an experimental_action_listener that generates the compilation database. Forked from this gist, but I had to fix up some json formatting that the clang tools didn't like.
Install the scan-build clang analyzer wrapper tool.
Fiddle with bazel paths and permissions for hours until it finally worked.

Readme and a scattering of files that worked for me:
https://github.com/cybrown-zoox/bazel-clang-analyzer

I was pointed to all this from this discussion thread.

Side note - I assume you could also modify the action_listener to just directly execute the clang --analyze command at the same time as the build, rather than doing this in steps.

Yes, action_listener / extra_action is intended for exactly this use case, and that's how we use it internally.

Was this page helpful?
0 / 5 - 0 ratings