New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Support for java based compilers like Eclipse Compiler for Java (ecj) in Java toolchains #15942
Comments
I would also be interested in using ECJ for compiling with Gradle >= 7, as that allows makes hot-swapping much easier when building projects with Gradle on Java 17, but debugging them using Eclipse (and performing modifications while debugging). |
Add |
With some work done on the toolchain provisioning in Gradle 7.6, I had a fresh look at this topic. This is roughly what I think would be needed to make it work:
|
The T.J. Watson Libraries for Analysis, also known as WALA, builds using both the standard Java compiler and Eclipse's compiler. Our approach may be useful as an example of how to get this working within current Gradle limits. This Groovy code implements a
So to @jjohannes I'd say: yes, this is indeed a workable strategy. @jjohannes also wrote:
For WALA's |
Gradle 8.0 includes Kotlin 1.8.0, and Kotlin 1.8.0 deprecates `String.toLowerCase()`. So in the `NullAway` script plugin, instead of using `name.toLowerCase().contains("test")`, we now use `name.contains("test", true)`. The `true` argument requests case-insensitive `String` comparison, which perfectly corresponds to what the earlier code was doing anyway. Gradle 8.0 adds an annoying extra check for `JavaCompile` tasks. If such a task is configured to fork a subprocess, Gradle 8.0 now requires that the configured subprocess executable match the configured toolchain compiler executable. That's a problem for our ECJ Java compile tasks: they want to fork a `java` subprocess, which does not match `javac` as the toolchain compiler executable. Working around this requires that we adapt our `JavaCompileUsingEcj` task implementation *yet again*, as we seemingly have to do with every new Gradle release, with gradle/gradle#15942 still not implemented. This time around, we avoid relying on the standard `JavaCompile.compile()` task action method, since calling that leads to the new executable equality check. Instead, we provide our own `compile()` task action method that directly runs the ECJ subprocess with a suitable command line. Along with that change, we also slightly change how we define and resolve the ECJ jar. Previously we used a detached `Configuration` for this purpose, but that turns out to be a bit tricky to manage with the Gradle configuration cache. Now we use a normal, named `Configuration` that is defined and configured in the shared `java.gradle.kts` script plugin. We also move the `skipJavaUsingEcjTasks` property check out of the `JavaCompileUsingEcj` task constructor, because having it there produced an IntelliJ IDEA warning about calling a non-`final` method in a constructor. Instead, we configure this check in an existing bit of `java.gradle.kts` logic that was already being used to configure all `JavaCompileUsingEcj` tasks.
Gradle 8.0 includes Kotlin 1.8.0, and Kotlin 1.8.0 deprecates `String.toLowerCase()`. So in the `NullAway` script plugin, instead of using `name.toLowerCase().contains("test")`, we now use `name.contains("test", true)`. The `true` argument requests case-insensitive `String` comparison, which perfectly corresponds to what the earlier code was doing anyway. Gradle 8.0 adds an annoying extra check for `JavaCompile` tasks. If such a task is configured to fork a subprocess, Gradle 8.0 now requires that the configured subprocess executable match the configured toolchain compiler executable. That's a problem for our ECJ Java compile tasks: they want to fork a `java` subprocess, which does not match `javac` as the toolchain compiler executable. Working around this requires that we adapt our `JavaCompileUsingEcj` task implementation *yet again*, as we seemingly have to do with every new Gradle release, with gradle/gradle#15942 still not implemented. This time around, we avoid relying on the standard `JavaCompile.compile()` task action method, since calling that leads to the new executable equality check. Instead, we provide our own `compile()` task action method that directly runs the ECJ subprocess with a suitable command line. Along with that change, we also slightly change how we define and resolve the ECJ jar. Previously we used a detached `Configuration` for this purpose, but that turns out to be a bit tricky to manage with the Gradle configuration cache. Now we use a normal, named `Configuration` that is defined and configured in the shared `java.gradle.kts` script plugin. We also move the `skipJavaUsingEcjTasks` property check out of the `JavaCompileUsingEcj` task constructor, because having it there produced an IntelliJ IDEA warning about calling a non-`final` method in a constructor. Instead, we configure this check in an existing bit of `java.gradle.kts` logic that was already being used to configure all `JavaCompileUsingEcj` tasks.
Gradle 8.0 includes Kotlin 1.8.0, and Kotlin 1.8.0 deprecates `String.toLowerCase()`. So in the `NullAway` script plugin, instead of using `name.toLowerCase().contains("test")`, we now use `name.contains("test", true)`. The `true` argument requests case-insensitive `String` comparison, which perfectly corresponds to what the earlier code was doing anyway. Gradle 8.0 adds an annoying extra check for `JavaCompile` tasks. If such a task is configured to fork a subprocess, Gradle 8.0 now requires that the configured subprocess executable match the configured toolchain compiler executable. That's a problem for our ECJ Java compile tasks: they want to fork a `java` subprocess, which does not match `javac` as the toolchain compiler executable. Working around this requires that we adapt our `JavaCompileUsingEcj` task implementation *yet again*, as we seemingly have to do with every new Gradle release, with gradle/gradle#15942 still not implemented. This time around, we avoid relying on the standard `JavaCompile.compile()` task action method, since calling that leads to the new executable equality check. Instead, we provide our own `compile()` task action method that directly runs the ECJ subprocess with a suitable command line. Along with that change, we also slightly change how we define and resolve the ECJ jar. Previously we used a detached `Configuration` for this purpose, but that turns out to be a bit tricky to manage with the Gradle configuration cache. Now we use a normal, named `Configuration` that is defined and configured in the shared `java.gradle.kts` script plugin. We also move the `skipJavaUsingEcjTasks` property check out of the `JavaCompileUsingEcj` task constructor, because having it there produced an IntelliJ IDEA warning about calling a non-`final` method in a constructor. Instead, we configure this check in an existing bit of `java.gradle.kts` logic that was already being used to configure all `JavaCompileUsingEcj` tasks.
This issue has become more apparent with Gradle 8 effectively dropping support for using custom compilers (via On a more general note, I'm somewhat annoyed by Gradle at this point as there seems to be a trend to remove old APIs before a (stable) replacement is available. Other example of this is the removal of the |
There was a discussion about this in the Gradle Community Slack some time ago, where I also warned about being careful to not break this use case before there is a replacement: My understanding was that setting the executable is still possible (more or less) as before. But I haven't tried myslef. Maybe @alllex can share here how this works now? |
The WALA project compiles all code twice: once using standard That being said, it would be lovely if Gradle could just stop breaking this for us with each new release. If Gradle would support ECJ compilation directly, then that would be even better. |
Instead of making the Jar with the compiler part of the toolchain (which I considered in this comment #15942 (comment)), we could also think of as an add-on for the toolchain in the Turned out this wouldn't need too much adjustments: #24649 |
See this PR: |
What's the status here? I'm quite confused. There are a lot of linked PRs around this topics, some seem to be merged, some have been closed, some are still open without progress since months. What are the plans to move forward here? |
Patched Gradle https://github.com/jjohannes/gradle/tree/release-8.7-ecj-patch/gradle-bin |
Provide support for Java based compilers like ecj in Java toolchains feature.
Expected Behavior
Should be able to configure a non distribution based compiler (non-executable) when provisioning a different compiler in Java toolchains feature.
Current Behavior
Only jdk executables (javac, etc.) distributions seem to be supported.
Context
Ecj allows compilation to proceed when there are minor and possible unrelated compile time errors from the code path one would like to execute. In a large multi-project build it is sometimes quite handy at development time to ignore such errors while somebody else is looking at them, for example. Javac does not allow compilation to proceed in case of any errors.
The text was updated successfully, but these errors were encountered: