Why does dependsOn work, and dependencies {} does not?


(Michael Irby II) #1

I have a multi-project build and trying to setup project dependencies. When I use dependsOn the dependencies are successful, but when I use dependencies {} they do not work. In both cases the dependencies show up when i run ‘gradle dependencies’, but they both do not provide the same valid dependencies.

This works:

project(':myProj2') {
    dependsOn ':myProj1'
                                                                                                                                                                                 }

This does not:

project(':myProj2') {
                                                                                                                                                                              dependencies {
        compile project(path: ':myProj1', configuration: 'compile')
    }
}

I would continue using ‘dependsOn’, but when building there is a warning stating that ‘dependsOn’ will be deprecated starting with Gradle 2.0.

I am just confused as to why dependencies {} does not work when building, but shows up correctly when running ‘gradle dependencies’.

Any help would be greatly appreciated.


(Peter Niederwieser) #2

These aren’t the same things. The former snippet makes tasks in ‘myProj2’ depend on equally named tasks in ‘myProj1’. The latter makes whichever task consumes ‘myProj2’'s ‘compile’ configuration (and declares it as an input) depend on whichever tasks build the artifacts in ‘myProj1’'s ‘compile’ configuration. Typically, the ‘compile’ configuration doesn’t contain any artifacts built by Gradle. (The ‘java’ plugin will add them to ‘runtime’.)


(Michael Irby II) #3

ahhh, now that makes more sense. is there an equivalent method for ‘dependsOn’ that is not going to be deprecated?


(Peter Niederwieser) #4

We no longer think that the automatic name-by-name mapping is a good approach, as it is unlikely to reflect the actual dependencies. Therefore, the answer is no.


(Michael Irby II) #5

i see, well using dependsOn was the only way I could get Gradle to support a kind of build order that I need. Is there any way to enforce build order in Gradle without using dependsOn?


(Peter Niederwieser) #6

Of course. First there is ‘Task#dependsOn’ and friends. Often Gradle can also infer task dependencies from higher-level dependencies, such as the dependencies between configurations. The latter is generally the preferred way to handle cross-project dependencies.


(Michael Irby II) #7

I tried using task dependencies…

task(':myProj2:task1').dependsOn(':myProj1:task1')

It seems to be valid, but again no luck. I also tried configuration dependencies and that also did not work.

Seems to me that everything other than project.dependsOn works completely different.


(Peter Niederwieser) #8

The above will certainly do what it’s expected to. As I said earlier, depending on configuration ‘compile’ will not typically result in any task dependencies. You’d have to depend on ‘runtime’ or a custom configuration that you add artifacts to using an ‘archives {}’ block. For details, see the Gradle User Guide.


(Michael Irby II) #9

yea, this is all based on a custom Gradle plugin compiling in a language that Gradle does not support. So there is no work being done by Java or any other plugin. Is there something that the plugin needs to do to support dependencies?


(Peter Niederwieser) #10

Support task dependencies? No. Support inferral of task dependencies (e.g. from configurations)? Yes, the tasks (or task classes) need to declare their inputs.


(Michael Irby II) #11

i guess I will just have to dig a bit deeper to get it working in my case. thanks for the help though. Gradle is an excellent tool, but i do find it odd that it cant just have something like project build order or turn off ordering of projects alphabetically.


(Peter Niederwieser) #12

There is no such concept as “project build order” in Gradle. Execution order is solely based on task dependencies.


(Michael Irby II) #13

yes, but Gradle orders the project builds using alphabetical ordering or project names. so if here are no task dependencies the execution order is in alphabetical order of project name. if Gradle simply allowed the order of projects to be the order they are defined in the settings.gradle file it would fix my issue. also the name-by-name mapping is exactly what i need because i simply need projects to build in a certain order. i know this can probably be done by some complex task/configuration scheme, but would be much easier if Gradle did not re-sort the project order from the settings.gradle file. that is kind of making an assumption that the user wants Gradle to sort them alphabetically.


(Peter Niederwieser) #14

There is no such assumption. The order is undefined, but stable for sequential builds. Since the implementation has to choose some stable order, it chooses lexicographical order. This only holds for sequential builds, and only as long as Gradle doesn’t apply any optimizations (which it will definitely do at some point). Hence relying on this order is a bad idea, and there is no way around telling Gradle about the actual dependencies.

If you truly need an automatic name-by-name mapping, it can be implemented in the build script (or a plugin).


(Michael Irby II) #15

i here you. well, how would i go about providing a name-by-name mapping. I tried doing name-by-name mapping of tasks across projects, but it did not work.


(Peter Niederwieser) #16

I can’t think of any pitfalls regarding defining cross-project task dependencies, and I can’t say what went wrong in your case. It’s unlikely that it is a problem with Gradle. To do a name-by-name mapping, you could add a method that iterates over the two project’s tasks and adds the necessary ‘dependsOn’ relationships. This needs to be done after both projects have been evaluated (so that all tasks have been declared already), e.g. inside ‘gradle.projectsEvaluated { … }’.


(Michael Irby II) #17

awesome…the "gradle.projectsEvaluated {…} is what i needed…

This is what I used:

gradle.projectsEvaluated {
    subprojects { proj ->
        proj.configurations.compile.dependencies.each { depend ->
            proj.tasks.each { task ->
                task.dependsOn ":${depend.name}:${task.name}"
            }
        }
       }
   }

That provided the behavior I needed.

Thats ALOT for all your help!!