only single gradle sub-project among multiple sub-projects can resolve symbols from a shared sourceset folder in intellj - gradle

I am working on a gradle project which has multiple sub-projects. To simplify the problem description, I am using a simple project here.
The project structure looks like
/client-v1
/src
/main
/java
/v1
Client.java
build.gradle
/client-v2/
/src
/main
/java
/v2
Client.java
build.gradle
/common
/src
/main
/java
/common
Util.java
settings.gradle
client-v1 and client-v2 are sub-projects and /common is a sourceSet folder. The settings.gradle is
rootProject.name = 'client'
include('client-v1', 'client-v2')
The build.gradle in client-v1 and client-v2 has the sourceSet definition as below.
sourceSets {
main {
java {
srcDir '../common/src/main/java'
}
}
}
gradle build works fine in project root, client-v1 folder and client-v2 folder. Also my vscode resolves all the symbols in client-v1, client-v2, and common.
Here is the problem. However, in Intellij-idea(IntelliJ Community 2021.1), client-v2 doesn't recognize the Common symbol whereas client-v2 does.
For example,
package client.v1;
import common.Util; // Okay
...
package client.v2;
import common.Util; // Cannot resolve symbol 'Util'
...
So, I updated the settings.gradle to remove the client-v1 as below:
rootProject.name = 'client'
include('client-v2')
Then the Cannot resolve symbol 'Util' error messages in client-v2's Client.java disappears in intellj.
So it seems like that the intellij enables only single gradle project to resolve symbols from a sourceSet. Is it true? Is there any way to address the problem?

It is a limitation of the IDE: IDEA-214527 Two modules in a project cannot share the same content root.

Related

Path relative to multi-project build file

I have a project structure like this:
config/
foo/
build.gradle
settings.gradle
bar/
build.gradle
baz/
build.gradle
I want to add the config directory to the classpath in foo/build.gradle so that the subprojects bar and baz can access it. I've tried doing this in foo/build.gradle:
subprojects {
apply plugin: 'java'
dependencies {
runtime files('../config')
}
}
But that results in the following entry in the classpath:
/home/me/project/foo/config
When what I actually want is:
/home/me/project/config
I believe it's because runtime files('../config') is being evaluated in foo/bar/build.gradle instead of foo/build.gradle. So, how can I get the path to foo/? I could just use runtime files('../../config'), but it doesn't feel quite right.
Or maybe I'm going about this the wrong way and there's a better place to put the config files?
One way to get to your current config folder location irrespective of which project/folder level you're at is:
"$rootDir/../config"

Gradle multi-project custom build.gradle file name

I have a multi-project Gradle build, which is currently configured through a single build.gradle file.
There are over 70 modules in this project, and the single (gigantic) build.gradle file has become cumbersome to use, so I'd like to split it into small per-module buildscript files.
Now, I don't want to have 70 small build.gradle files (one in each module), as that would make navigating to a specific build.gradle a pain in the IDE (the only difference between the files is their path).
What I want is my per-module buildscript files to be named after the module name.
Instead of this:
root
|--foo\
|--| build.gradle
|--bar\
|--| build.gradle
I want this:
root
|--foo\
|--| foo.gradle
|--bar\
|--| bar.gradle
Since this doesn't seem to be officially supported, I tried hacking around the root build.gradle a bit, but it seems that applying a .gradle file happens before the projects are configured, so this gives an error for projects that depend on other projects:
in root build.gradle:
subprojects { subProject ->
rootProject.apply from: "${subProject.name}/${subProject.name}.gradle"
}
foo.gradle, which is not a standard build.gradle file:
project('foo') {
dependencies {
compile project(':bar')
}
}
Is there any way of making it work like this?
A web search for "gradle rename build.gradle" rendered the below example settings.gradle file:
rootProject.buildFileName = 'epub-organizer.gradle'
rootProject.children.each { project ->
String fileBaseName = project.name.replaceAll("\p{Upper}") { "-${it.toLowerCase()}" }
project.buildFileName = "${fileBaseName}.gradle"
}
Note that the author is here also renaming the root project's build script, which you may or may not want.
One of the authors of Gradle, Hans Dockter, has said somewhere (I believe it was in his "Rocking the Gradle" demo from 2012), that he felt one of their biggest mistakes was using build.gradle as the default file name.
You can customize name of your build scripts in settings.gradle file. Check recent presentation from Ben Muschko about multi-project builds or look at Gradle sources where similar customization is done.
rootProject.children.each {
it.buildFileName = it.name + '.gradle'
}
You can find this content in Gradle in action, manning

Referencing an external project from a sub project in gradle

I have a project setup like so where my projects are all in sibling folders relative to one another:
+ mainApp
+ mylib
+ mylib2
mainApp references the mylib library project that is not in its root with the following in my settings.gradle:
include ':app', ':mylib'
project(':mylib').projectDir=new File('..\\mylib')
However, the issue is that the mylib project depends on another lib - mylib2. I can essentially do the same thing and reference mylib2 using settings.gradle and building mylib works fine.
The problem is when I try to build mainApp, it cannot find mylib2 because the settings.gradle of a sub-project is not ran, only the root settings.gradle is ran. So, when the build.gradle file of mylib references mylib2, it cannot find mylib2.
I do not want to add a reference to mylib2 from mainApp, I want mylib2 to be brought in by mylib.
Is there a way to bring in mylib2 from the build.gradle file of mylib ?
It seems like you have a wrong understanding of subprojects.
Every "Project Tree" has a rootProject. This rootProject is the only project that should have a settings.gradle wich includes all subprojects. So if all of your 3 Projects belog together, then they must all be included in the settings.gradle.
References to other foreign project should be added as dependencies. Note that you can only reference Artifacts this way.
You did not make it very clear, but it seems like you want to use the project "mylib" as a Library for the source code of "mainApp"
If those are java projects you can simply add the jar file produced by "mylib" to the compile configuration of "mainApp":
apply plugin: 'java'
dependencies {
compile fileTree(dir:'../myLib/build/libs', include : '**/*.jar')
}
For other languages you have to use the language specific support for that language.

How do I prevent Gradle from building a non-project directory?

In the Gradle samples (included with version 2.2.1) there is a java/multiproject project.
The settings.gradle file defines the following projects:
include "shared", "api", "services:webservice", "services:shared"
Note that services is not itself a project, merely a directory which contains the webservice and shared projects.
When I run the command gradle build from the root directory, I notice that after gradle successfully builds it creates inside the /services directory a /build directory containing /lib and a /tmp directories.
Inside of /services/build/lib is a jar: services-1.0.jar which contains very little; specifically just a META-INF/MANIFEST.MF file containing:
Manifest-Version: 1.0
provider: gradle
So what is causing Gradle to build a jar for this non-project? And how can I prevent this behavior in my similarly structured multiproject project?
/services isn't a project, I don't want to create anything inside /build folder at all. Yes I could just delete it, but I would like to avoid the unnecessary work of building this jar/running any tasks on this non-project in the first place.
To be honest I've no reasonable idea why gradle builds this folder. I guess that because it's a kind of a transient folder. However it can be excluded by adding the following piece of code to main build.gradle script:
project(':services').jar { onlyIf { false } }
Desired effect (services.jar elimination) can be also obtained with the following settings.gradle content:
include "shared", "api", "services/webservice", "services/shared"
File instead of project paths are included.
My guess would be that this is a combination of the next 2 gradle rules:
When you're including subprojects in the build.settings file using the include keyword according to Gradle Documentation here:
the inclusion of the path 'services:hotels:api' will result in
creating 3 projects: 'services', 'services:hotels' and
'services:hotels:api'.
In simple words, this means that the inclusion of services::webservice will also build the services project
The bulid.gradle file in your root that applies the 'java' plugin. According to Gradle Documentation here every configuration defined in the root.gradle takes effect for all sub projects. This means that it will also hold as the default configuration for the services project. As the 'java' plugin was applied a jar will be created, but as there is no src/main folder under the services directory nothing will be compiled and the jar will include only a META-INF/MANIFEST.MF file.

Gradle-built project structure

I see a lot of examples of Gradle-built Java/Groovy projects that have the following structure:
some-app/
src/
main/
test/
docs/
README.md
build.gradle
gradlew
gradlew.bat
settings.gradle
gradle.properties
gradle/
*.gradle
I understand that build.gradle is the main buildscript and that gradle.properties is its properties file. But settings.gradle really throws me. Inside it I see:
rootProject.name = "someApp"
But this seems like it belongs in gradle.properties. I'm also wondering where the gradlew and gradlew.bat files come from, they seem to be generated.
Finally, I'm wondering why there are so many *.gradle files under the gradle/ dir: are these plugins, or extension scripts of some sort. They are all pulled in from the main build.gradle like so:
apply "gradle/fizz.gradle"
apply "gradle/buzz.gradle"
etc.
So:
What properties are supposed to go in settings.gradle that are not supposed to go in gradle.properties?
How are the gradlew/gradlew.bat files generated?
Why would someone have so many disparate *.gradle files? Why not just 1 big build.gradle buildscript?
1) gradle.properties is normal properties file, while settings.gradle is also a build script. You can add there some code that will be executed during build. Typically this file is needed when You have a multi-module project.
2) When You type gradle tasks in project build directory (empty build.gradle is enough to see it) You'll see wrapper task. This task is used to generate scripts You're asking about. More info.
3) The reason is that all these files have different responsibilities that are cleanly separated.

Resources