Incremental Compile with gradle 3.4.2-rc-2 not working?


(Woden Cafe) #1

Hi all,

I have switched to gradle 3.4-rc-2 with the wrapper, I have added the options to the build.gradle, and I am trying to run the build with the incremental compiler for performance improvements.

However, here is the message I get when gradle compiles the project:

Project:compileJava - is not incremental. Annotation processors are required. 

Are Annotation Processors required for incremental compile? I didn’t see anything about that being a requirement in the release notes. Is this a bug, or am I doing something wrong?

Here is the relevant section in my build.gradle:

compileJava {
//enable compilation in a separate daemon process
options.fork = true

//enable incremental compilation
options.incremental = true
}


(Mark Vieira) #2

This message is actually saying the opposite. Incremental compilation is not possible when annotation processors have been found on the classpath. You must have a dependency which is registering an annotation processor on the classpath.


(Woden Cafe) #3

Oh I see. That error message is a bit confusing then.

mark, do you have any idea how we can identify which dependencies have these annotation processors?


(Mark Vieira) #4

Adding something like the following should give you some indication of which JARs include annotation processors.

tasks.withType(JavaCompile) {
  doFirst {
    println "Task ${path} annotation processors: ${effectiveAnnotationProcessorPath.asPath}"
  }
}

(Woden Cafe) #5

Oh you’re right! We have a lot of dependencies that are using annotation processors, it seems.

But these are already compiled jar files, they are not getting rebuilt as a part of our build process,

why would that affect incremental compilation of our code?


(Mark Vieira) #6

Quite simply, our incremental compiler implementation is not capable of considering what annotation processors might do. For example, adding a source retention only annotation to a class would normally result in us not recompiling (as it would not affect bytecode) but this annotation might result in an annotation processor creating a class, etc. For that reason, to ensure correctness, we simply disable incremental compilation. This is a known limitation.


(Mark Vieira) #7

So the snippet I gave you before is somewhat misleading. All that means is that one of those jars has an annotation processor. Not that they all contain an annotation processor.


(Mark Vieira) #8

Ok, try this for size :slight_smile:

tasks.withType(JavaCompile) {
    doFirst {
        effectiveAnnotationProcessorPath.each { maybeJar ->
            if (maybeJar.file) {
                zipTree(maybeJar).each {
                    if (it.name == 'javax.annotation.processing.Processor') {
                        println "Annotation processor found in $maybeJar.name"
                    }
                }
            }
        }
    }
}

(Woden Cafe) #9

Hi again mark, this is very helpful, thank you again!

It only found one:
Annotation processor found in log4j-core-2.2.jar

I’m a bit puzzled though, this jar is precompiled, so the annotation processors should not be activated as this jar isn’t getting built.

Is that how it’s supposed to work?


(Mark Vieira) #10

Not exactly. Annotation processors act on your code. Basically, they are like extentions to the Java compiler which can do things like generate code, modify existing classes, etc. They do this by looking for certain annotation in your code, if they find them, they perform some work at compilation time. In this case, log4j2 uses an annotation processor to search for plugin classes annotated with @Plugin. If your code doesn’t contain any log4j plugins you can safely disable this. You can turn off annotation processing completely via a compiler argument. This will also inform Gradle that you do no wish to use annotation processing and should enable incremental compilation.

tasks.withType(JavaCompile) {
  options.compilerArgs = ['-proc:none']
}

(Woden Cafe) #11

Hi again mark, thanks for the great info, that makes sense!

Unfortunately things are even stranger now, after I added your tasks.withType argument, I’m getting compile errors like “error: cannot find symbol sun.security.pkcs10.PKCS10”

Without the argument, things compile correctly.

Do you have any idea why the “-proc:none” argument would cause problems for using sun security classes?


(Mark Vieira) #12

Perhaps we are overriding some other important compiler arguments. Try this.

options.compilerArgs.add '-proc:none'

(Woden Cafe) #13

It worked! Thank you again mark, this has been super helpful!


(Stefan Oehme) #14

3.4 provides a strongly typed way to define which processors to use:

compileTask.options.annotationProcessorPath =...

In your case an empty file collection will do. See the Java plugin documentation for 3.4 for more information.

If you don’t specify that we fall back to using whatever processors are on your compile classpath. That disables both incremental compile and compile avoidance, so it’s really important to declare processors (or the fact you don’t want any) explicitly. We also handle the jvm arguments, like proc:none, but I think the explicit DSL is simpler to use.


(Woden Cafe) #15

Thanks for the additional info :smile:


(Mike Snare) #16

@st_oehme this doesn’t seem to be working for me.

I have configured the annotationProcessorPath for my compile task, and I am using some other code provided in this thread by @mark_vieira to inspect the effectiveAnnotationProcessorPath to make sure that only the jars I have added to the annotationProcessorPath are being included. That’s working correctly. When I run the compile, the code provided by Mark correctly shows the jar file that has the annotation processor and no other jars.

However, gradle is also telling me that the compile is not incremental because annotation processors are found:

`:ComBase:Common:compileJava - is not incremental. Annotation processors are present.`

I’m using 3.4-rc-3. My reading of the docs suggests that I’m doing this correctly.

I don’t know if this information is relevant, but in case it is:

  1. The processor jar is the same jar that contains the annotation to be processed. This necessarily places a compile-time dependency on that jar so that we can actually apply the annotation. I have created a separate jar that contains ONLY the annotation, and that jar is on the compile path. The processor jar still has the annotation class. This means the annotation itself will be found twice.
  2. Also, the main code has a compile time dependency on a library that the processor needs at runtime. That library is therefore duplicated in the apt config as well as the compile config.

Any help would be appreciated,
Thanks


(Stefan Oehme) #17

@mikesnare you are actually using annotation processors, so we can’t do incremental compile.

The original poster did not want to use them (they were just included accidentally through a transitive dependency) and was asking how to get rid of them.


(Mike Snare) #18

Ugh… it’s only compile avoidance that was made annotation processor aware?


(Stefan Oehme) #19

Our incremental compile depends on the class dependencies that are part of the normal Java language specification. Annotation processors can introduce completely new and unexpected relationships, so to be safe we need to disable incremental compile.

We will explore options to improve this in the future. Potentially we can inspect what the processors are doing or maybe we can provide an API for annotation processor authors to tell us what they are doing.


(Mike Snare) #20

Bummer, but understood. I can still use incremental and compile avoidance in downstream projects, so it’s still better than it was before.

Thanks for the response.