Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Android multi modules annotation processing

In a multi modules Android project annotation processing is still executed as a first task before any compilation is done and then a complete compilation is triggered. Of course this is done per module before getting into the app module.

Imagine a case where some child modules depend on others, the compilation will fail as the dependant cannot yet find definition for generated classes in the module that it depends on simply because they were not generated yet.

I am wondering if there's a way either using gradle or anything else to force execute all child modules annotation processing first and then compile the whole project in an automatic fashion. This means if I have 3 modules let's name them app, services and executors where services depends on executors.

What I am seeking is that the build tree would go in this order:

  1. annotation processing is executed for all modules without compilation
  2. a full project compilation is then invoked

I found so far some promising lead using the java compiler's option -proc:{none;only} where the value only should invoke the annotation processing without any further compilation. I have tried passing this option to my compiler but still the compilation goes sequentially child module per child module.

Any ideas?

like image 207
AouledIssa Avatar asked May 28 '20 07:05

AouledIssa


1 Answers

After a deep investigation on this subjects, long hours of reading and many tee and coffee cups, I have across the fact that my project setup was not quite correct also I have figured out that Kotlin android plugin has its own sad and shady fact which I hope I can clarify in this very answer so grab a cup of tee/coffee and enjoy reading.

  1. Is there a way to trigger a kotlin compilation twice? Short answer for that is NO!, this is simply due to the fact that gradle it self has an Acyclic dependency graph which means there should be no way to have a circular dependency hence a task will only run once per gradle invocation.
  2. How to can we solve this limitation? There are two options, either we add a new Source set (for android that will be through adding a new buildType) or simply break the wonders of the chicken/egg dilemma and use artifacts.

I have experimented a lot with every possible solution but still, something was smelling fishy. First thing first, here is a thread where I asked gradle users about my problem. Even though, It didn't solve my problem, it still shed some light on the roots of the issue itself,The chicken/egg dilemma.

Trying to clarify further my problem, I went ahead with my investigations and asked kotlin developers about how to do this using kotlin gradle plugin. Please find the answers here

Short story: There is no way to extend the kotlinCompile gradle task directly simply cuz there is a "code around" that initiate the compilation. I mean sure but why it was very poorly designed this way? Why such a beautiful language as kotlin had to rush the production of that specific supposedly powerful plugin, and mostly why its sources was never updated/reviewed ever since?

The way around this is to use their handle KotlinCompilation entry point. I personally don't like this solution as it limits the level of flexibility and also still abstract the compilation task even further.

Another promising way using gradle was artifacts where a module builds it self and produces an artifact (usually a jar in our case) which will be consumed by other projects. This sounds cool right? Well unfortunately there is no way to add this library to the classpath of consumers and the compilation will simply fail.

These were my findings, please feel free to update my knowledge or correct me if I am mistakingly understanding something.

Happy coding!

like image 148
AouledIssa Avatar answered Sep 27 '22 19:09

AouledIssa