Lets say I have 3 dependencies A, B and C. A depends on C V1.0 while B depends on C V2.0. If A uses C V2.0 then it throws an error and if B uses C V1.0 it will also thrown an error. These are both obviously unwanted behaviors. So I want a dependency tree that looks like this.
A
+--- C:1.0
B
+--- C:2.0
However, when I try to implement this with gradle I get this
A
+--- C:1.0 -> 2.0
B
+--- C:2.0
which means C:1.0 is not being used anywhere despite A requesting that version. How can I get gradle to not override the 1.0 version of C that A needs to work?
Related
I use below config to force using old version of library_common in project my_library
my_library
dependencies{
compile("library_A")
compile("library_B")
compile("library_common:old_version"){
force = true
}
}
Library_common is resolved to old_version, which match our expectation
dependency tree
+---library_A
| +---library_common: new_version -> old_version
+---library_B
| +---library_common: old_version
+---library_common: old_version
Another Project my_application then have dependencies on my_library and a non_related_lib
my_application
dependencies{
compile("my_library")
compile("non_related_lib"){transitive = false}
}
Library_common is somehow resolved to new_version which causes the conflicts in my_library.
dependency tree
+---my_library
| +---library_A
| | +---library_common: new_version
| \---library_B
| | +---library_common: old_version -> new_version
| \---library_common: old_version -> new_version
+---non_related_lib
I know I can force library_common version again in my_application, but it seems not right, as my_library should handle this conflict by itself.
It seems to me Gradle ignores force=true constraint declared in a direct dependency. Could somebody help explain if this is the way Gradle works?
Also, another thought is to exclude library_common in library_A and library_B. Will need to test it. But this way may become complicated when library_common is included as a transitive dependency of library_A/B, and nested level is deep.
Could someone provide any suggestions on the best practice to downgrade a dependency in a library project?
Thank you!!
If you want to force an older version of a transitive dependency, you should use dependency constraints. If your libraries are all published using Gradle, the constraints are also packaged within the Gradle module metadata, which means they will be preserved whenever you add your libraries as dependencies to some other project.
This all means, your buildscript has to change to something like this:
// my_library
dependencies{
compile("library_A") // do not specify a version of library_A here
constraints {
compile("library_A:version") // specify a version of library_A here
compile("library_common") { // do not specify a version of library_common here
version {
strictly(old_version) // specify a version of library_common here
}
}
}
compile("library_B")
}
extremely close to this SO post, and asked in comments, but left unclear there.
$ git clone https://github.com/k9mail/k-9.git
$ cd k-9/mail/protocols/smtp
$ ../../../gradlew dependencies | grep "4.7.1 (\*)\|4.7.1 (c)\|4.7.1 (n)" | sort -u
+--- com.jakewharton.timber:timber:4.7.1 (*)
+--- com.jakewharton.timber:timber:4.7.1 (n)
+--- com.jakewharton.timber:timber:{strictly 4.7.1} -> 4.7.1 (c)
What do (c) and (n) suffixes mean?
Sadly, the Gradle docs do not cover this topic so it is a bit confusing.
Issuing gradlew dependencies | tail shows a legend explaining the meaning of the printed suffixes.
(c) - dependency constraint
(*) - dependencies omitted (listed previously)
(n) - Not resolved (configuration is not meant to be resolved)
Constraints are not pulled in unless some other dependency pulls them in.
Transitive dependencies are listed only once and then omitted.
Declared just for holding/listing the dependency not resolving it to a graph. This is the case for configurations like implementation or api.
Our project worked until I tried to upgrade to Gradle 5. There the first thing it complained was that / isn't a good character for multi-projects, e.g. bla/blub isn't valid, so we changed this to bla:blub (even though the error message said : also isn't valid). But now we apparently have a circular dependency which didn't exist before with Gradle 4:
Circular dependency between the following tasks:
:lap:server:classes
\--- :lap:server:compileJava
+--- :lap:server:compileKotlin
| \--- :lap:server:jar
| +--- :lap:server:classes (*)
| +--- :lap:server:compileKotlin (*)
| \--- :lap:server:inspectClassesForKotlinIC
| \--- :lap:server:classes (*)
\--- :lap:server:jar (*)
Why could this be?
The problem was indeed with the : notation in our settings.gradle. Now that I've changed all the nested projects to - the problem is resolved.
More concretely, before we had something like:
include 'common/server',
'someproject/server',
'someproject/common',
'someproject/search',
...
which worked with gradle 4.
Then in Gradle 5 I've changed it to
include 'common:server',
'someproject:server',
'someproject:common',
'someproject:search',
...
which caused the issue, presumably because someproject:common depended on common:server or something of the likes.
Now that I've changed it to
include 'common-server'
project(':common-server').projectDir = file('common/server')
include 'someproject-server'
project(':someproject-server').projectDir = file('someproject/server')
include 'someproject-common'
project(':someproject-common').projectDir = file('someproject/common')
everything works like a charm. By the way, the error with the circular dependency is also reproducible in Gradle 4, it's just that there we still had the / notation.
For those of you who stumble on this question.
see : https://github.com/gradle/gradle/issues/847
in a multi project setup, a duplicate "shortname" will throw in a monkey wrench:
from the url above:
myApp
- client
- common
- server
- common
Even though it should be 2 distinct entries, the duplicate (shortname) of "common" is the issue/bug.
I ended up doing this: (my code is different names of course) (but the idea is)
myApp
- client
- clientcommon
- server
- servercommon
to disambiguate.
The url has some other ideas.
What I saw in my code was, the built jars looked something like this:
common-1.0-SNAPSHOT.jar
So that was what clued me in to "ahhh, maybe I have ambiguous issue with the shortname". And finally found that github-gradle link.
I'm converting an existing java multimodule project to gradle. The dependencies are a bit complicated - in short, I have something along these lines:
Root project MainProject
+--- Project ':P1'
| \--- Project ':P1:P2'
\--- Project ':utilProject'
So, my mainProject depends on P1, which in turn depends on P2, and a utilProject.
The thing is, both P1 and P2 also depend on the utilProject.
In the build.gradle for each of these projects was just compiling the ':utilProject' (the project is always in the root, and the projects for the main one look as I wrote above):
dependencies {
compile project(':utilProject')
// compile some other dependencies
}
P1 and P2 are fine (compiling without errors), however the main project won't compile. I've tried changing the code in utilProject around, and found that while the utilProject itself does compile the latest changes, the the main project is blind to them.
Any ideas would be greatly appreciated.
/// Update - July 20th 2014
Forgot to mention the MainProject is an eclipse plugin, and so we use the wuff plugin to compile (though I'm not sure it's relevant).
Seems like there is no need for P2 - P1 won't compile either (previously it just didn't use that bit of updated code. My bad).
Also, while I wasn't able to reproduce, I was able to find a workaround - adding the latest utilProject.jar to the dependency list seems to do the trick. I'm not sure why it's necessary... any ideas? Note that I did have to add the P1.jar to the MainProject and so on to make things work, which seems to indicate something's wrong with the dependency list, but all the projects on that list compile just fine.
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.