Search code examples
bazelbazel-java

java_toolchain: how can I use the Eclipse compiler in a Bazel build


I want to migrate an ant build to Bazel 4.2.1. The ant build uses an Eclipse compiler (ecj-3.27.0).

The way to declare a Java compiler in Bazel is java_toolchain.

So I had a look at the output of bazel query @bazel_tools//tools/jdk:all and tried to use the vanilla toolchain as an inspiration (bazelisk query --output=build @bazel_tools//tools/jdk:toolchain_vanilla).

java_toolchain(
  # modified settings
  name = "my-ecj-toolchain", 
  javabuilder = ["@ecj//:ecj.jar"], # my Eclipse compiler jar
  target_version = "8",
  # prevent ecj.jar's error message 'unknown option --persistent_workers' 
  javac_supports_workers = False,
  # prevent ecj.jar's error message 'unknown option --persistent_workers' 
  javac_supports_multiplex_workers = False, 

  # keeping most vanilla-toolchain settings
  bootclasspath = ["@bazel_tools//tools/jdk:platformclasspath"],
  misc = ["-XDskipDuplicateBridges=true", "-XDcompilePolicy=simple", "-g", "-parameters"],
  jvm_opts = [],
  tools = ["@bazel_tools//tools/jdk:javac_jar", "@bazel_tools//tools/jdk:java_compiler_jar", "@bazel_tools//tools/jdk:jdk_compiler_jar"],
  singlejar = ["@bazel_tools//tools/jdk:singlejar"],
  forcibly_disable_header_compilation = True,
  genclass = ["@bazel_tools//tools/jdk:genclass"],
  ijar = ["@bazel_tools//tools/jdk:ijar"],
  header_compiler = ["@bazel_tools//tools/jdk:turbine_direct"],
  header_compiler_direct = ["@bazel_tools//tools/jdk:turbine_direct"],
  jacocorunner = "@bazel_tools//tools/jdk:JacocoCoverageFilegroup",
)

However, it still does not work. ecj.jar complains about the unknown option --output.

bazel aquery MYTARGET displays the whole compiler command line (plus some more build steps):

 Command Line: (exec external/remotejdk11_linux/bin/java \
    -jar \
    external/ecj/ecj.jar \
    --output \
    bazel-out/k8-opt/bin/[...].jar \
    --native_header_output \
    bazel-out/k8-opt/bin/[...]-native-header.jar \
    --output_manifest_proto \
    bazel-out/k8-opt/bin/[...].jar_manifest_proto \
    --compress_jar \
    --output_deps_proto \
    bazel-out/k8-opt/bin/[...].jdeps \
    --bootclasspath \
    bazel-out/k8-opt/bin/external/bazel_tools/tools/jdk/platformclasspath.jar \
    --sources \
    bazel-out/k8-opt/bin/[...].java \
    --javacopts \
    -target \
    8 \
    '-XDskipDuplicateBridges=true' \
    '-XDcompilePolicy=simple' \
    -g \
    -parameters \
    -g \
    -- \
    --target_label \
    bazel-out/k8-opt/bin/[...]:[...] \
    --strict_java_deps \
    ERROR \
    --direct_dependencies \
[...]

I don't know any Java compiler that accepts --output. Do I have to pass ecj.jar in a different way?


Solution

  • The Eclipse Java Compiler is available as toolchain for Bazel.

    https://github.com/salesforce/bazel-jdt-java-toolchain

    It wraps ECJ into a builder for Bazel. There are a few limitations. For example it does not support Error Prone yet. However, annotation processing works.

    We noticed that ECJ has quite some advantage in our large code base in terms of performance and resource consumption.