I have a monolith Gradle project that contains multiple subprojects, each with its own subprojects, like so:
project
|
|-- subprojectA
| |-- models
|
|-- subprojectB
| |-- models
This compiles fine but the issue is when I try to add a dependency on :subprojectB:models to :subprojectA:models, Gradle thinks :subprojectA:models is trying to add a dependency on itself and complains of a circular dependency, even though I specify the fully qualified path like so (in subprojectA's build.gradle):
compile project(':subprojectB:models')
How can I avoid this? Can subprojects not have the same name even if their paths are unique?
Project identity for dependency resolution is based on the group:name:version or GAV coordinates, as explained in the linked Gradle issue.
So you need to make sure your different models project have different GAVs.
One way to make this happen is to make the subprojectA (or B) part of the group.
Another way is to assign names that are not based on the containing folder.
That's currently a known Gradle issue as Gradle by default uses the parent directory name as the project name. You can work around the issue as described here by assigning unique subproject names in the root project's settings.gradle like so:
include ':subprojectA:models', ':subprojectB:models'
project(':subprojectA:models-a').projectDir = file('subprojectA/models')
project(':subprojectB:models-b').projectDir = file('subprojectA/models')
Related
I want to use a project in my project as a git submodule, ideally without changing the upstream project (or if it makes sense, changing it in a way that will get merged there).
The problem is that the project consists of modules, 2 of which I want to directly use, with the one also depending on the other.
myProject
├ submodule
| ├ first
| | ├ build.gradle: implementation project(":second") <---- this fails if I don't change it to :submodule:second
| ├ second
| ├ settings.gradle: include ':first', ':second'
├ app
| ├ build.gradle: implementation project(":submodule:first"), implementation project(":submodule:second")
| ├ settings.gradle: include ':submodule:first', ':submodule:second', ':app'
As my project's settings.gradle replaces the submodule's settings.gradle, the submodule's absolute paths suddenly change. Can I somehow `include ':submodule:second as :second'?
I know I can use implementation project(somePrefix + ":second") and define this somePrefix accordingly but that would involve touching the submodule.
Gradle project paths (e.g. ':submodule:second')
actually represent project hierarchies. This means that using include ':submodule:second' in your settings.gradle will implicitly create a project called submodule, even if not relevant for the build at all.
do not need to match the directory structure (this is just a convention). You may set the project directory independent from the project path (and the project name).
Check out the following example from the documentation:
// include two projects, 'foo' and 'foo:bar'
// directories are inferred by replacing ':' with '/'
include 'foo:bar'
// include one project whose project dir does not match the logical project path
include 'baz'
project(':baz').projectDir = file('foo/baz')
However, I would recommend to not use include at all. Instead use includeBuild and setup a composite build. Composite builds differ from classical multi-project builds in their coupling. Since your Git submodule indicates a build that may be used as a standalone project (with its own settings.gradle), the strong coupling of a multi-project builds seems inappropriate. Multiple settings.gradle files may also cause problems in a multi-project build, but are fine for composite builds.
I have created a simple maven project with a parent pom and a module pom. When i execute a mvn clean install i notice that the parent and the module are in the same level.
Structure of the project in the local repo:
-parent folder
-module folder
While I expected something like that:
-parent folder
+—-module folder
Is this normal ?
What happened if two modules have the same name in this case ?
Assuming you are talking about the local repo usually located at ~/.m2/repository, yes, that is normal. You have to distinguish between the folder layout within the repository and the folder layout for your development.
As mentioned in this question, the artifacts are always in a folder structure according to their coordinates (groupId, artifactId and version).
groupIdSplitAtDots/artifactId/version
Whether some artifacts are modules of another is completely irrelevant for the directory-layout of the local repository.
If you have e.g. the artifacts com.organisation.topic:artifact-parent:1.2, com.organisation.topic:artifact-module1:1.2 and com.organisation.topic:artifact-module2:1.2, the folder structure will be:
com
|-- organisation
|-- topic
|-- artifact-parent
|-- 1.2
|-- artifact-module1
|-- 1.2
|-- artifact-module2
|-- 1.2
Note, that for development it is usually a good idea to have the parent module in a parent folder, resulting in a layout like this:
artifact-parent
|-- artifact-module1
|-- artifact-module2
As per your second question, identical module names (artifactIds) are not allowed. Regarding the artifactId the docs state:
The identifier for this artifact that is unique within the group given by the group ID.
Typically, a multi project Gradle build would be setup something like this:
root
subproject1
subproject2
And in root's settings.gradle file, I'd have something like:
rootProject.name = 'root'
include 'subproject1'
include 'subproject2'
This kind of multi-project setup is straightforward. However, what if subproject1 or subproject2 aren't contained within root? For example, I might have an existing subproject on my machine that is stored somewhere far away from root. How do I configure the setting.gradle file to account for this "non-standard" structure? Is it just a matter of providing an absolute path to the subproject folder in the settings.gradle file?
This post covers it: https://discuss.gradle.org/t/how-to-include-sub-projects-in-settings-gradle-file/5096
Basically, you have to overwrite the project.projectDir attribute of your subproject so that it points to the location of the subproject on your machine.
I realize there are a lot of posts online regarding Gradle setup. That being said, I have researched heavily and not found exactly what I'm looking for, or I'm using incorrect terms to do so. I'm using Gradle version 3.3.
So I've got multiple Gradle projects, each of which is maintained separately. There is no master Gradle project. Each projects has its own modules, build, and settings file. The structure of this is as so:
Projects
A
a1
build.gradle
a2
build.gradle
build.gradle
settings.gradle
B
b1
build.gradle
b2
build.gradle
build.gradle
settings.gradle
What I'm attempting to do is make B dependent on A's modules. Let's assume one of the modules in B is dependent on a1. In B's settings, I've done the following:
rootProject.name = 'B'
rootProject.setProjectDir(new File(".")
include 'a1'
project(':a1').setProjectDir(new File(settingsDir.getParentFile(), "/A/a1"))
The way I'm storing version numbers is through each project's build.gradle file in the ext closure. I then access them through the project. Here's how B's build file looks:
ext {
freemarkerVersion = '2.3.19'
}
dependencies {
compile project(':a1')
compile group: 'org.freemarker', name: 'freemarker', version: rootProject.properties.get('freemarkerVersion')
}
What I'm seeing is B is able to resolve its dependencies and is attempting to compile project a1, but it is using B's version numbers instead of A's. I verified this by putting a common dependency in both projects with different version numbers. The dependency showed up using B's version. I also changed the version number in B and further confirmed this. So if I could get any help for using project-appropriate versions in each of their own build.gradle files, that would be great!
EDIT: Updated post, figured out previous problem was from relative path not resolving.
Not to toot my own horn or anything, but I'm posting the solution I came up with, as I had no other answers knocking down my door.
The first thing I did was moved all of my version properties to an external gradle.properties file, instead of in an ext closure in the project's build.gradle file. Doing this, the project will load the properties file by default when compiled from its own context. It will of course be overridden from the user.home gradle.properties file, so keep this in mind. Example gradle.properties:
a_freemarkerVersion = 2.3.19
When using one project's modules from another project, you'll need a way to separately link the two so Gradle can resolve the dependency's properties. I achieved this by defining a method to load in the desired project's properties file. This method looks like so:
def addConfig(String parent, String filename) {
Properties props = new Properties()
props.load(new FileInputStream(new File(project.projectDir.getParent(), "/${parent}/${filename}")))
props.each { prop ->
project.ext.set(prop.key, prop.value)
}
}
addConfig("A", "gradle.properties")
All this method does is goes up one directory, goes into the project specified, and retrieves its gradle.properties file and loads these variables into the current project's properties. With that being said, there's one thing to note here: if you define the same variable in both, one of them will be overridden. To avoid this, I just prefixed all variables with the project name and then an underscore. This will guarantee they'll never conflict with one another.
I accessed the variables in all projects with this syntax:
dependencies {
compile group: 'org.freemarker', name: 'freemarker', version: "${a_freemarkerVersion}"
}
The rest of the setup is the same as I defined in my initial post. Just make sure to include the dependent module, specify its project directory, and compile that project from within the project's dependencies.
I don't know if I totally got the concept wrong, but I want to create several projects with dependencies to other projects which are not part of the directory structure of a parent project. I know that the normal way of doing this would be to use an external dependency which fetches from some external repository. But in this case, where let's say in project called 'F' a framework is developed, which is used in project 'P'., then P uses F, but F should IMO not necessarily be a sub-project of P as P is only used to test-drive the development of F (but it's not only a unit test). Later in the process, when F is stable, F is separated and can be consumed by other projects via a repository. But during development of F with P as it's test case, it would be nice if that round-trip through the repository could be omitted.
To make matters worse, for the initial development there is more than one test-driving consumer project, which all need to have a dependency to F, but not via an external repository.
My idea is to develop F in some place on the disk with it's own git reposity. The other P like projects reside somewhere else on the disk and have a local file system based dependency to F. Would such a construct be possible in Gradle? If so, where do I start? I scanned the Java examples but couldn't find an appropriate example.
Any ideas?
The Gradle project hierarchy is fully virtual. It just has the default that the physical location corresponds to the virtual hierarchy. But you have complete control over this. See: http://gradle.org/0.9-rc-1/docs/userguide/build_lifecycle.html#sec:settings_file
Regarding your other ideas have a look at the following Jira: http://jira.codehaus.org/browse/GRADLE-1014
You could consider a folder hierarchy like this one:
Main folder
|- F folder
| |- .git
| |- sources
| |- build.gradle (with parts specific to F)
|- P folder
| |- sources
| |- build.gradle (with part specific to P)
|- build.gradle (with common parts)
|- settings.gradle
So you can always decide to run gradle on either the F project, the P project or the two alltoegether. It will also allows you to promote you F project alone without the P or any other side projects.
For more up-to-date information, check the Multi Project Builds chapter of the Gradle documentation.