I have the following project structure
-->Starnderd Location
-->Project1
-->settings.gradle
-->build.gradle
-->Subproject11
-->build.gradle
-->Subproject12
-->build.gradle
-->Project2
-->settings.gradle
-->build.gradle
-->Subproject21
-->build.gradle
-->Subproject22
-->build.gradle
-->build.gradle
-->settings.gradle
Idea of above project structure is that we have multiple projects which contains subprojects, each project can have dependencies to other projects. Also subprojects inside the project can have dependencies to other subprojects within the same project. Projects will be specified in the settings.gradle in the root. Also settings.gradle inside each project will say what are the subprojects of that particular project.
My settings.gradle in the root would looks like
include 'Project1',
'Project2'
and Project1 settings.gradle will looks like
include 'SubProject11'
'SubProject12'
other dependency orders are defined in the respective build.gradle files If I rand gradle clean build install inside the root location(Standar location) it doesn't seems to use configurations in the Project level settings.gradle file.
What I'm doing here wrong?
I was able to solve this problem in a relatively clean way. Improvements are certainly welcome!
Although Gradle does not support multiple settings.gradle
scripts out of the box, it is possible to create individual sub-projects each with their own settings.gradle
file. Let's say you have multi-project A that depends on multi-project B, each with their own sub-projects. Your directory structure might look like:
A
- settings.gradle
- foo
- faz
\ B
- settings.gradle
- bar
- bap
Out of the box, Gradle expects A/settings.gradle
to look something like this:
include ':foo', ':faz', 'B:bar', 'B:bap'
The problem with this is that every time B adds a new project, A/settings.gradle
must also change even if the new project is only used by B. To avoid this situation, you could try to apply
B/settings.gradle
in A/settings.gradle
instead of adding redundant declarations:
apply from: 'B/settings.gradle'
include ':foo', ':faz'
If you try this, you'll find that Gradle fails because it generates the wrong projectDir
for :bar
and :bap
. It mistakenly assumes that B's includes are relative to settingsDir
which happens to be A/
when Gradle is invoked from that project root. To fix this you can add another script such as B/settings-parent.gradle
(the exact name is not significant):
apply from: 'settings.gradle'
def updateProjectPaths(Set<ProjectDescriptor> projects) {
projects.each { ProjectDescriptor project ->
String relativeProjectPath = project.projectDir.path.replace(settingsDir.path, "")
project.projectDir = new File("B/$relativeProjectPath")
// Recursively update paths for all children
updateProjectPaths(project.children)
}
}
updateProjectPaths(rootProject.children)
This strips settingsDir.path
and prefixes the path with B/
. This can be extended to multiple layers of settings[-parent].gradle
files by having each layer add itself onto the path. Now you will apply this script to A/settings.gradle
:
apply from: 'B/settings-parent.gradle'
include ':foo', ':faz'
With this scheme, new B projects do not unnecessarily break A/settings.gradle
and all projects can be used without explicitly referencing the B sub-project. For example, if ':foo'
wanted to use 'B:bap'
, it may simply declare:
compile project(':bap')