Transitive libraries not included through project dependency


(Ari Maniatis) #1

I know many questions are asked about gradle handling dependencies, but I just can’t find the answer to this one. I have a multi-module project where module A has build.gradle like this

dependencies {
 testCompile project(':common:common-test')
}

In turn, the common-test project has test dependencies on a whole bunch of jars. When running:

gradle dependencies

on common-test, the ‘testCompile’ configuration has all the correct dependencies. But when I run that on module A, none of the transitive dependencies appear. To try and force the issue I tried this:

dependencies {
 testCompile (project(':common:common-test')) {
  transitive = true
 }
}

but that didn’t help.

I also found this old topic from 2008 which suggests that this behaviour is correct: http://gradle.1045684.n5.nabble.com/project-dependencies-and-transitivity-td1432998.html but I can’t see a way around the problem, the section in the manual that forum refers to doesn’t exist in any version of the manual I could find.

I found this quote at http://gradle.org/docs/current/userguide/userguide_single.html#multi_project_builds

A lib dependency is a special form of an execution dependency. It causes the other project to be built first and adds the jar with the classes of the other project to the classpath. It also adds the dependencies of the other project to the classpath.

However, I see no clue about how to create such a lib dependency which pulls in dependencies.

Thanks for any assistance.

Ari


(Peter Niederwieser) #2

‘project(’:common:common-test’)’ is a shorthand for ‘project(path: ‘:common:common-test’, configuration: ‘default’)’. The ‘default’ configuration (as configured by the Java plugin) includes ‘runtime’, but not ‘testCompile’ or ‘testRuntime’.

The easiest way to solve the problem is to use ‘compile’ instead of ‘testCompile’ for the dependency declarations in project ‘common-test’. Also, the sources of ‘common-test’ will have to be under ‘src/main/java’ rather than ‘src/test/java’. Otherwise, the ‘common-test’ Jar will be empty.


(Ari Maniatis) #3

Thanks for this reply, that explanation helps a lot. Does that mean the documentation here http://gradle.org/docs/current/dsl/org.gradle.api.artifacts.dsl.DependencyHandler.html is wrong?

Note that it says ‘By default, when you declare dependency to projectA, you actually declare dependency to the ‘default’ configuration of the projectA.’ That’s not the same thing as the ‘archives’ configuration you suggest.

Since I really want to keep ‘src/test/’ separate from ‘src/main/’ is it possible to write something like

testCompile project(path: ‘:common:common-test’, configuration: ‘testCompile’)

I just tried it and it seems to work the way I expect. Is this a bug or limitation in gradle that the configuration scope doesn’t automatically match in this way? I’d expect that this should be the default behaviour for POLA. Or am I missing something about the way this is expected to work?


(Peter Niederwieser) #4

The docs are right; its ‘default’, not ‘archives’. I’ve corrected my post accordingly.

It’s good to keep ‘src/main’ and ‘src/test’ separate. However, I would argue that ‘common-test’ is a library containing common test utilities, rather than a bunch of tests. As such, ‘src/main’ seems more fitting than ‘src/test’. Typically, ‘src/test’ is the part of a project that’s not exported.

If you want to keep the sources in ‘src/test’, you’ll have to add another Jar task, or reconfigure the one for the ‘main’ source set. In the former case, you’ll also have to add an ‘artifacts {}’ block to export the Jar via a configuration.

The fact that ‘project(’:foo’)’ always refers to the ‘default’ configuration is a limitation that a future version of Gradle will (massively) improve upon. However, it’s not quite as straightforward as simply “matching” the scopes.