Project compile dependency without triggering a jar build

Hi,

I have a multi-project build with mostly Java and some Groovy stuff (Gradle 2.1). When building a dependent project, some of the parent projects are always rebuilt, even though nothing changed. When running gradle --debug I found that this is caused by a dynamically created manifest:

project(":A") {
 Closure manifestClosure = {
  attributes("CompanyName": solutionProperties['solution.company'] ?: rootProject.productCompany,
   // more attributes ...
  )
        }
    jar {
         manifest manifestClosure
  archiveName = "${baseName}.${extension}"
 }
}
  project(":B") {
 dependencies {
  compile project(":A")
 }
}

This now always triggers a build of :a:compileJava and :a:jar as well:

./gradlew :B:compileJava

I understand that the manifest is not based on an input file so Gradle has no way of knowing whether the manifest and hence the jar has changed.

My question is now why the compile dependency to project A needs the jar (and hence the manifest) and not just the compiled output of project A?

I tried to change the dependencies of project B like this:

project(":B") {
 dependencies {
  compile project(':A').sourceSets.main.output
  compile project(path: ':A', configuration:'compile')
 }
}

The first line provides the compiled classes, the second the (transient) dependencies. This solved the issue for me but is a bit cumbersome, especially as I have more than one such project dependency. Is there a better way to configure this build dependency without triggering a recompile caused by the dynamically created manifest?

Regards,

Wolfgang

Does the manifest need to be evaluated at execution time? If not, you could remove the need for the closure and then leverage Gradle’s incremental task support. Alternatively, you could short-circuit the project A ‘jar’ task if the contents of the jar would not have changed, effectively ignoring the dynamic manifest.

project(’:A’) {

jar {

onlyIf {

compileJava.didWork || processResources.didWork

}

}

}

Yes, the manifest needs to be evaluated at execution (or rather configuration?) time, as it integrates information from the build server, such as version, build number, etc.

As I do have a work around, I’m rather wondering why the project dependency depends on the upstream jar instead of the upstream project’s build output (and its transitive dependencies).

Well, arguably the project’s jar is it’s build output as it could conceivably contain resources not defined in a source set, or omit items from it’s source outputs. For example, in your use case, the JAR manifest isn’t really used but that is not always the case.

Like you said, you have a workaround. You might consider another option be to simply disable the dynamic manifest in your development builds.

You are right about the build output, but for building dependent projects, usually only transient dependencies and compiled (test) classes are relevant.

But what I would like to achieve is surely no standard use-case, so I will either live with my work-around or maybe abandon that for better readability.

Anyway, thanks for your time and help!

Cheers, Wolfgang