facebook / infer

A static analyzer for Java, C, C++, and Objective-C
http://fbinfer.com/
MIT License
14.99k stars 2.02k forks source link

any plans for bazel support ? #457

Open darkcrawler01 opened 8 years ago

darkcrawler01 commented 8 years ago

https://github.com/bazelbuild/bazel

sblackshear commented 8 years ago

No current plans. If you have experience building Bazel plugins and are interested in contributing one for Infer, that would be awesome!

jeremydubreil commented 8 years ago

Infer has support for Buck which is similar to Bazel. It works by redirecting to Infer the compiler invocations. Using the same approach may work for Bazel too. The code is here: https://github.com/facebook/infer/blob/master/infer/lib/python/inferlib/bucklib.py

rahul-malik commented 7 years ago

@jeremydubreil @sblackshear - With the last release I noticed that Infer has support for clang compilation databases. Assuming we can get Bazel to output this would that be the preferred method for integration?

[Clang] Improved support for cmake and Xcode compilation databases. Use with infer --compilation-database compile_commands.json (for cmake and Buck), or with infer --compilation-database-escaped compile_commands.json (for xcbuild and xcpretty).

https://github.com/facebook/infer/releases/tag/v0.10.0

jvillard commented 7 years ago

@rahul-malik I would recommend using compilation dbs to integrate with Bazel. I don't think infer can reasonably support a large range of build systems "natively". Going through an intermediate compilation DB is a more scalable solution.

Note however that infer doesn't support running its Java frontend using compilation DBs yet. Let us know if that'd be helpful to add for you (are there tools out there that output Java compilation databases?).

rahul-malik commented 7 years ago

@jvillard - Thanks! The compilation db should work well since we're only interested in analyzing our targets which are compiled with llvm/clang which already supports outputting a compilation database (I'm unaware of any Java compilation db as well).

jvillard commented 7 years ago

@shs96c Is there any issue with getting the clang database out then passing that to infer capture --compilation-database compile_commands.json?

shs96c commented 7 years ago

I'd like to also check java code :)

rahul-malik commented 7 years ago

If we're adding support for multiple languages and couldn't use a clang db, the extra actions API could be used to capture the compiler invocations:

https://docs.bazel.build/versions/master/be/extra-actions.html

jeremydubreil commented 7 years ago

@shs96c: For the Java side, could we reuse for Bazel the same strategy as used with Buck, which is to specify the path to an external javac compiler pointing to Infer? Buck basically calls Infer this way:

  buck build --config tools.javac=/path/to/infer <rest of the buck command>

This option to specify an external Java compiler was originally added to Buck specifically for the integration with Infer so I don't know if there is something equivalent for Bazel.

shs96c commented 7 years ago

I remember it being added very well :) There's a java_toolchain option in Bazel that might work:

https://docs.bazel.build/versions/master/be/java.html#java_toolchain

I'm not sure what a JavaBuilder is in this context, but the docs suggest it expects the javac to be a jar, not an executable.

On Thu, Sep 14, 2017 at 8:25 AM, Jeremy Dubreil notifications@github.com wrote:

@shs96c https://github.com/shs96c: For the Java side, could we reuse for Bazel the same strategy as used with Buck, which is to specify the path to an external javac compiler pointing to Infer? Buck basically calls Infer this way:

buck build --config tools.javac=/path/to/infer

This option to specify an external Java compiler was originally added to Buck specifically for the integration with Infer so I don't know if there is something equivalent for Bazel.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/facebook/infer/issues/457#issuecomment-329397095, or mute the thread https://github.com/notifications/unsubscribe-auth/AABuRW5F8kBJYBVBzbSs7Npgke60h_Gnks5siNTpgaJpZM4J2eRG .

davido commented 6 years ago

@shs96c JavaBuilder is Bazel wrapper around Javac invocation, that does some magic:

However, in very recent Bazel version there is an easy way to use so called VanillaJavaBuilder to skip all the magic I mentioned above.

Gerrit Code Review uses this invocation to support most recent Java versions, that are not supported yet by Bazel natively. With this CL: [1] pending for review you could say something like this in gerrit tree:

  $ bazel build --host_javabase=:absolute_javabase \
    --define=ABSOLUTE_JAVABASE=/usr/lib64/jvm/java-11 \
    --define=USE_ABSOLUTE_JAVABASE=true \
    --host_java_toolchain=//:toolchain_vanilla \
    --java_toolchain=//:toolchain_vanilla \
    :release

Instead of passing /usr/lib64/jvm/java-11 I could pass the path to infer and that would probably solve infer integration for Bazel?

[1] https://gerrit-review.googlesource.com/c/gerrit/+/194040

davido commented 6 years ago

If I try to pass: bazel build --define=ABSOLUTE_JAVABASE=/usr/local/bin/infer, then it doesn't work, as Bazel tries to add bin/java to this Java home directory:

java.io.IOException: Cannot run program "/usr/local/bin/infer/bin/java" (in directory "/home/jenkins/.cache/bazel/_bazel_jenkins/bb2dc09ec74ab7b7157cd89c2ef96641/execroot/gerrit"): error=20, Not a directory

Next attempt is to try to pass: --define=ABSOLUTE_JAVABASE=/opt/infer and link /opt/infer/bin/java to infer itself:

  $ /opt/infer/bin/java --version
Infer version v0.15.0
Copyright 2009 - present Facebook. All Rights Reserved.

Then calling bazel build still failing with /opt/infer-linux64-v0.15.0/lib/infer/infer/bin/infer: unknown option '-jar'.:

$ bazel build --define=ABSOLUTE_JAVABASE=/opt/infer \
  --host_javabase=@bazel_tools//tools/jdk:absolute_javabase \
  --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_vanilla \
  --java_toolchain=@bazel_tools//tools/jdk:toolchain_vanilla :headless
[...]
INFO: Analysed target //:headless (0 packages loaded, 0 targets configured).
INFO: Found 1 target...
ERROR: /home/jenkins/gerrit/java/com/google/gerrit/server/BUILD:9:1: Building java/com/google/gerrit/server/libconstants.jar (1 source file) failed: Worker process did not return a WorkResponse:

---8<---8<--- Start of log, file at /home/jenkins/.cache/bazel/_bazel_jenkins/bb2dc09ec74ab7b7157cd89c2ef96641/bazel-workers/worker-9-Javac.log ---8<---8<---
/opt/infer-linux64-v0.15.0/lib/infer/infer/bin/infer: unknown option '-jar'.
Infer version v0.15.0
Copyright 2009 - present Facebook. All Rights Reserved.
Usage: infer command [options]
See `infer --help` for more information.
---8<---8<--- End of log ---8<---8<---

I think it might be easier to migrate build tool chain from Bazel to Buck to make infer work.

davido commented 6 years ago

@cushon Any idea, how we could hijack javac to call infer in Bazel driven build?

The problem is, that before switch from Buck to Bazel JGit/Gerrit community was able to run all the code base through infer. After migration to Bazel we lost that ability ;-(

libratiger commented 5 years ago

is there any update or plan for this topic? bazel become more and more popular, it would be cool to support it.

uri-canva commented 5 years ago

Also interested! @martinoluca don't think you can escape from my feature requests just because I'm on the other side of the world.

giphy

shs96c commented 5 years ago

An aspect to provide alternative targets would probably work too.

shs96c commented 4 years ago

Gentle nudge :)

TomMD commented 4 years ago

@shs96c At @muse-dev we decompose many build systems into a machine readable description of the build steps (think javac ... ; javac ... ; ... or gcc ...) then feed those steps to several analyzers, infer among them. It shouldn't be hard to support bazel if we could just gain some insight into how to extract the invocations. Since you seem interested in this topic perhaps you are well-versed enough in Bazel and invested enough to teach me?

krlvi commented 4 years ago

@TomMD extracting build steps in that fashion sounds interesting but I presume you would be using internal APIs which historically have been changing a lot.

davido commented 4 years ago

As pointed out in my previous comment, the inspiration could be the current implementation of VanillaJavaBuilder.java#run:[1] method that is calling vanilla javac:

CompilationTask task =
            javaCompiler.getTask(
                new PrintWriter(output, true),
                fileManager,
                diagnosticCollector,
                JavacOptions.removeBazelSpecificFlags(optionsParser.getJavacOpts()),
                ImmutableList.<String>of() /*classes*/,
                sources);
        setProcessors(optionsParser, fileManager, task);
        ok = task.call();

The idea would be to have InferJavaBuilder.java and shell out to infer instead of vanilla javac.

Another question is how to teach infer to run preprocessors for code generation? One approach would be to let javac run the preprocessors, and then run infer with only (second) compile task.

Moreover, new toolchain should be added to bazel that understands new InferJavabuilder, and invoked like this:

  $ bazel build \
    --define=PATH_TO_INFER=/opt/infer \
    --host_java_toolchain=@bazel_tools//tools/jdk:toolchain_infer \
    --java_toolchain=@bazel_tools//tools/jdk:toolchain_infer \
  //...

To make it even more generic, it could be called GenericJavaBuilder.java so that it would work with any static analyser and not just with infer.

[1] https://github.com/bazelbuild/bazel/blob/7f0ba75ae6da3ceca8e5e865a1ce9b8c71a5249e/src/java_tools/buildjar/java/com/google/devtools/build/buildjar/VanillaJavaBuilder.java#L145-L223

ulfjack commented 4 years ago

It's pretty straightforward to create an extra action that runs Infer. Here's a Gist link: https://gist.github.com/ulfjack/c66180584f9efb9e9768bf8999ffcd8a

Use like this:

bazel build //src/main/java/... --experimental_action_listener=//src/infer/java/com/engflow/infer --spawn_strategy=local
cpsauer commented 2 years ago

If anyone is still interested this for (Objective-)C(++) and wants to use compile_commands.json, we built https://github.com/hedronvision/bazel-compile-commands-extractor which should make getting a compile_commands.json from Bazel easy and fast.

(extra_actions have been deprecated, unfortunately, though that otherwise seems like a great solution for running it alongside a build.)

Does anyone have experience running infer via compile_commands.json and caching/getting fast incremental rebuilds?