evaluationDependsOn annoyance

I have a project with three subprojects as follows (settings.gradle)

rootProject.name = 'alarm'
include 'jar'
include 'pp'
include 'cdb'
project(':jar').buildFileName = 'build-jar.gradle'
project(':pp').buildFileName = 'build-pp.gradle'
project(':cdb').buildFileName = 'build-cdb.gradle'

jar builds a jar.
pp and cdb each build an rpm that include that jar. the only differences are the name of the rpm and the directory into which the jar is put when the rpm is installed.

Both buildscripts have the following configuration block

        into (libdir) {
            from(project(':jar').jar.outputs) {
                fileMode defaultFileMode
            }
        }

where libdir is defined differently in each script,

Sounds simple enough, but this project cannot even be evaluated as written.

It is necessary to add the line

evaluationDependsOn(':jar')

to build-cdb-gradle, to have a subproject that can be evaluated. It is not necessary to add it to build-pp-gradle. I think this is because of alphabetical order ‘jar’ comes after ‘cdb’ but before ‘pp’ and since the projects are siblings, the subprojects are evaluated in alphabetical order.

This is staggeringly non-intuitive and I wasted two hours trying to figure it out.

It would be much better if gradle evaluated sibling subprojects in the order they were defined in settings.gradle.

While you can reference tasks from other projects, it really should be a last resort. Using evaluationDependsOn is a bit of a smell. Dependencies, configurations, and artifacts are a better model than directly accessing outputs of a task from another project.

There’s a decent blog post about this topic that’s actually pretty similar to your situation, but with Docker and TARs instead of RPMs and JARs: http://mrhaki.blogspot.com/2016/02/gradle-goodness-inter-project-artifact.html

1 Like

thanks for this, James. this comes up fairly frequently in my situation, which involves packaging work as much if not more than it involves java work. I’m actually surprised that the alphabetical thing didn’t bite me before. I think it’s because I may not have made the jar-building project a sibling before.

Maybe you might think about deprecating the task.outputs and evaluationDependsOn at some point. You’re definitely right that it smells bad. I only learned to do it by frantically scanning your documentation looking for anything that would work one harried day in the past. Your way is better and it should be made known in something more official than a blog post.

The basic Java functionality is built around these concepts, so I think “comes up” is probably the key sentiment here. Since the Java plugin sets up many of the configurations and defaults, it’s easy to overlook that you can use these constructs to model everything you must implement in the same way.

I think you had trouble finding the information you were expecting to find because much of the manual is written in the context of the default usage in the Java plugins. For example, I think the most useful information on this topic is in the publishing artifacts section, which you might not even look at if you’re not publishing to a repository.

I do think additional documentation around inter-project dependencies for generic artifacts would be good, but I can also see it being close to the threshold of what’s actually provided vs. what you can do with it. I think the blog post is really just pointing out that you can do exactly what is already done for Java. There’s nothing special about it.

I’m just a community member here with no affiliation to Gradle, Inc. If you have a strong opinion about what you’d like to see changed, you should probably open a GitHub Issue with a specific request (or two), but I’d expect the documentation request to be the most likely actionable item.

Sorry, but in this case and I think a couple of others, you’ve been so helpful I figured you must be one of the Gradle guys.
:smile: