This message was deleted.
# community-support
s
This message was deleted.
a
It would be good to understand how this changed class is referenced in the recompiled classes. You can get list of recompiled classed with
--debug
logs. And from that create a reproducer. For example we had a fix in 7.6 that if class was referenced as type parameter in methods/fields/class declarations, e.g.:
Copy code
class A implements Super<SomeClass>
and you deleted
SomeClass
, then there was no error (at least in 7.5). So if you class is referenced as type parameter 7.5 wont’ do anything, while 7.6 will recompile A.
d
Changed Kotlin class is not used in any Java class. In debug logs I can see only this:
Copy code
Input property 'classpath' file /modulebuild/tmp/kotlin-classes/debug/com/example/SomeKtClass.class has changed.
and then I see invocation to compiler. After that - the list of recompiled classes and seems like just the whole module was recompiled. Also I see this line before compiling java classes:
Copy code
2023-02-02T20:54:20.967+0800 [INFO] [org.gradle.api.internal.tasks.compile.incremental.recomp.CurrentCompilationAccess] Created classpath snapshot for incremental compilation in 0.088 secs.
2023-02-02T20:54:20.997+0800 [DEBUG] [org.gradle.internal.file.impl.DefaultDeleter] Deleting /Users/user/project/module/build/tmp/compileDebugJavaWithJavac/compileTransaction/stash-dir
Does it mean something or I should ignore it?
a
Since you have mixed Java and Kotlin sources in one module, is this compilation done by compileJava task or is there any Kotlin task starting that?
It would be interesting to see, if the problem is also with Gradle 8.1, but I guess it’s harder to try 8.1, due to breaking changes
d
Yes, by compileJavaWithJavac task.
I'll try to check 7.6-milestone-1 and 8.* versions, maybe I'll get lucky 🙂
Is it possible to build Gradle locally by myself and use it for building the project? So that I can try to find commit where the issue started reproducing.
a
Yes, you can build it locally with:
Copy code
./gradlew install -Pgradle_installPath=<path where to install>
and then you can run it with:
Copy code
<path where to install>/bin/gradle
If you’ll try some 8.* version, please try some latest 8.1 version (you can get all nightlies here), since there was some change how compilation after failure is done.
d
Well, I'm still getting the issue on the last snapshot gradle-8.1-20230202231649+0000. Disabling
incrementalAfterFailure
is also not helping me.
a
Then improvements to incremental compilation after failure are probably not the issue, that is in some way also good. These issues are very difficult to debug without a reproducer and we didn’t get any such report for 7.6. It might be also a AGP bug (I am not sure if AGP just runs Java compile or does something more here) or some Kotlin -> Java problem. So if you find some way to share the reproducer that would be great.
d
Ok, I got it. For now I have one interesting intermidiate output: We use our own dependency injection framework that is very similar to https://github.com/google/dagger/. There is a chain:
TestClass.kt
(the file that I'm changing) ->
TestClassFactory.kt
(creates
TestClass
) ->
ApplicationComponent.java
- big interface that have references to huge amount of classes across the project. This cycle: https://github.com/gradle/gradle/blob/master/subprojects/language-java/src/main/java/org/gradle/api/internal/tasks/compile/incremental/deps/ClassSetAnalysis.java#L119 collects not only those three classes, but also all the classes that exists in ApplicationComponent and so one. The final amount of classes is 2192, just like in logs. To confirm that I removed reference on
TestClassFactory
from
ApplicationComponent
and then java compilation does nothing, as with 7.5 version. And seems like it was introduced by this change: https://github.com/gradle/gradle/commit/aa3807e513490867e6f2859ad2423a415513b74f. Now I'm going to check how does it work on 7.5 version.
a
This change basically recompiles all classes in a source. So if you have: A.java and inside you will have: class A1 {} and class A2 This makes sure we delete A1.class and A2.class before compilation (they will be anyway recompiled again). But we also recompile all annotation process dependencies of A1.class and A2.class. So, are these 2192 classes annotation processor dependencies of ApplicationComponent?
Good research btw, we are getting closer 🙂
@Denis Buzmakov Did you find anything else here? Asking since I want to understand if we have really a regression or recompiling other classes in this case is needed for the correctness sake
d
I'm stuck for now because it requires debugging on two different laptops and takes too much time. What I have for now: • seems like my previous assumption was wrong and the cause somewhere else. • in
ClassSetAnalysisData.getChangedClassesSince
in this line: https://github.com/gradle/gradle/blob/master/subprojects/language-java/src/main/ja[…]ternal/tasks/compile/incremental/deps/ClassSetAnalysisData.java in
other.classHashes
in Gradle 7.5 changes class is not present and then it decided that nothing has changed and that's all. But in Gradle 7.6 changed class is present and then, as I said before, gradle recompiles a lot of classes. I'm still don't know well how does it work and why, so I will try to dig deeper and I will definitely write here if I will find out something new.
@Anze Sodja Hi! Sorry for so late response. I finally found one of the causes of increasing build time in our project after upgrading from 7.5 to 7.6. The reason is that Gradle in 7.5 does not take into account classes that were declared in generics (sorry for my English if I was wrong here). Let's see an example: https://github.com/bacecek/sample-checking-assistant-role/blob/gradle_76_java_compilation/app/src/main/java/dev/bacecek/defaultassistant/ApplicationComponent.java#L13 On Gradle 7.5 if I would change the class TestJavaClass3InComponent (add new method), compiler told has this:
Copy code
Incremental compilation of 1 classes completed
But on 7.6 version I got this:
Copy code
Incremental compilation of 11 classes completed
As I can understand, it's correct behavior. I have removed all
Optional
usings in Component class, but for now I still have the diff of recompiled classes with the same change: 347 vs ~2200. I will also try to find any other cause, but it will be harder 😞. But maybe it doesn't make sense anymore because other classes have also recompiled in the same way and it's correct behavior for now.
a
Hi Denis, Yes that should be correct behaviour. Because of the added method to TestJavaClass3InComponent, ApplicationComponent has to be recompiled (public class change of TestJavaClass3InComponent). And since TestJavaClass3InComponent is a return type of ApplicationComponent, all classes that use ApplicationComponent has to be recompiled (public class change of ApplicationComponent). Maybe Gradle could optimize some cases for generics, but that needs some rethinking and can be tricky in general case. You have some options to help Gradle here: you could split the ApplicationComponent class in multiple classes. Or alternatively you could have just one method if your framework allows that:
Copy code
ApplicationComponent {
    Optional<T> getComponent(Class<T> clazz)
}
Hmm, ok probably second suggestion won’t help you, if you have all classes in one project.
d
Thank you a lot for your help!
Is it possible to add some logs in debug mode about the reason why every class has been recompiled?
a
It’s possible, but if we would want to have exact reason for recompilation, it would require some work, since there are a lot of cases to cover. And in general users should not need to care about that. You can always open a feature request though. It would be interesting to have some analysis though, how well inc. compilation works and what we could optimize further.