Hi all! I am trying to move a module as a child o...
# community-support
r
Hi all! I am trying to move a module as a child of another module, but I am having problems resolving references to it from other modules. This is in the scope of an Android application (not sure if this would be some constraint in AGP), but sharing it here as looks like a general problem so far. I've already looked into Structuring Projects with Gradle and Multi-Project Build Basics, but I couldn't find any examples specifically about putting modules inside other modules (neither recommendations against this practice). Is there any limitation for it? ๐Ÿค” Sharing full in a thread to not pollute this channel with a long message. ๐Ÿงต๐Ÿ‘‡
I have the following gradle subprojects structure:
Copy code
project-1
โ””โ”€โ”€ build.gradle 
project-1-api
โ””โ”€โ”€ build.gradle 
project-2
โ””โ”€โ”€ build.gradle
I would like to refactor it to the following structure:
Copy code
project-1
โ””โ”€โ”€ build.gradle 
โ””โ”€โ”€ api
โ”‚   โ””โ”€โ”€ build.gradle 
project-2
โ””โ”€โ”€ build.gradle
So I simply want to move the api module inside the
project-1
module. The project-2 depends on project-1 api. This works in the original structure but as soon as I move
project-1-api
inside
project-1
I am unable to compile project-2, as it cannot resolve any references. Interestingly, project-1 also depends
project-1:api
, and it compiles fine after this refactor. ๐Ÿค” This really puzzles me. I would expect this won't work either. I've updated the both project-1 and project-2 build.gradle files, and also the root settings.gradle file accordingly replacing
project-1-api
by
project-1:api
. (as the identifier changes with this movement). I've verified that
project-1:api
builds transitively when project-2 attempts to compile, so it looks like the dependency is properly declared at Gradle level.
Also, I managed to make it work successfully with a different alternative structure, but this is not exactly what I was looking for:
Copy code
project-1
โ””โ”€โ”€ impl
โ”‚   โ””โ”€โ”€ build.gradle 
โ””โ”€โ”€ api
โ”‚   โ””โ”€โ”€ build.gradle 
project-2
โ””โ”€โ”€ build.gradle
In this case both project-1 modules coexist in a folder that is not an actual module (so no build.gradle, or sourcesets inside). Which brings me to question if declaring modules inside other modules is what is causing the issues. Anyone can clarify if is there any actual limitation for this practice? ๐Ÿ‘€
t
that should work. would just ref via project 1impl or project 1api. I like doing the impl/api sub projects like you have there so my convention plugin can look at the path to build the group. effectively becomes "{rootProject.name}.{parent.name}" so when published out you get "xyz.project-1:impl" and "xyz.project-1:api"
v
Your original try should work fine. If it does not, please provide an MCVE of what you tried, then we can probably point at the problem. Keep in mind, that with this setup you will end up with
api-1.2.3.jar
which might be "suboptimal". So you might want the project name to be
project1-api
but set the project directory to be
project1/api
if you don't want to have
project1/project1-api
.
r
Yeah, I was actually renaming it as simply
api
when moving inside the other module for exactly the naming situation. Ok, if this should work in theory, then I will keep trying to figure out what is wrong. I wanted to validate that this is not an antipattern or an incorrect configuration. I will provide an example if I cannot unblock. Thanks for the quick insights!
v
You intentionally name it in a way that the end result is as unhelpful as possible and as clash producing as possible? Well, I don't have to understand that, whatever works for you. :-D
g
Note that having multiple (sub)projects named the same way will probably cause artifact transforms caching issues for you.
๐Ÿ‘€ 1
v
How will there be artifact transform problems? There you always have the hash in the path, don't you? If both end up in the same configuration and have the same version you have a duplicate file problem of course though in the end. One of the problems I mentioned, besides that it is totally unclear from the name what the jar contains.
r
Ok, I tried to replicate this in a simple new Gradle project... and it works perfectly โœ… There might be something specific to my own configuration ๐Ÿซ  . Actually I noticed that a few modules compile fine now, and this problem is just present in a few others. So it might be some mess up that I introduced with my changes, or some specific configuration on these modules. I will continue digging. Thanks for the support confirming that this is correct! ๐Ÿ’ช
๐Ÿ‘Œ 1
Regarding the naming or what the jar contains... we are not publishing any of these modules. This is part of an Android app and these are just internal modules, so no one would be confused. The only way to consume these will be doing
implementation(project(":project-1:api"))
, which contains all the relevant information to differentiate them. Doing
implementation(project(":project-1:project-1-api"))
would be quite redundant to me, and I would like to avoid forcing to rename each module (we have many and is an extra requirement when creating more). This is why I would like to name each one simply as
api
and let them inherit their parent ๐Ÿ™‚
I am curious now about the cacheability issues mentioned by @Gasper Kojek . Could you please elaborate on it?
Aaah!! Actually that is the problem!!! In my project I refactored a couple of modules and I had some requiring both, which are exactly the ones that failed (but the ones requiring only one, worked fine). I was not able to reproduce it in an simple project because I only created a unique
project-1:api
. In the moment I add a second submodule in a different path named also
api
, such as
project-2:api
, any other module requiring both fails to compile! ๐Ÿคฏ Is this expected/known? I can report this as GH issue with a code example to make it more clear.
v
Again, this is exactly the problem and expected, at least latest at runtime. You will produce two jars, both named
api-1.2.3.jar
. So even if compiling would work, when you then put mutliple of those to a classpath, how should that work? ๐Ÿ˜‰ You might be able to mitigate it in your situation by just configuring the
Jar
tasks to produce different names by setting the
archiveName
or
archiveBaseName
or
archiveClassifier
so that your resulting jar names are unique.
๐Ÿ‘ 1
r
I see. I assumed your were pointing just to a human problem ๐Ÿ˜…. I was expecting that even the produced jar name is the same, they would be identified as different ones by the different path. But it's clearly not the case ๐Ÿ‘ Yeah, besides overriding the archiveName directly, I solved this by renaming the module in the settings.kts file
project(":project-1-api").projectDir = file("project-1/api")
, which I guess effectively changes also that the archive name indirectly. Not sure if is there any preference for any these two approaches?
v
they would be identified as different ones by the different path
They should, yes, unless in the end you try to put them to the same directory for example as is typical for a normal application. No idea about Android builds though, Android is always a bit special. ๐Ÿ˜„
I solved this by renaming the module in the settings.kts file
Which is exactly what I suggested above. ๐Ÿ™‚
thank you 1
t
exactly correct. its fine if you are only consuming via android builds but will probably cause problems if you are building a ktor micro service with jib or similar. archive base name is probably the best quick workaround
took 2 years of consuming our libraries before I finally got broke by the name overlaps