rodion
rodion

Reputation: 15029

Gradle - can I include task's output in project dependencies

I have a task that generates java sources and a set of jars from these sources (say, project a). I would like to export these jars to dependent projects (say, project b). So here's roughly what I have right now:

//a.gradle

configurations{
  generatedJars
}

task generateJars(type: JavaExec) { 
  //generate jars ... 

  outputs.files += //append generated jars here
} 

dependencies{
  generatedJars generateJars.outputs.files
}


//b.gradle

dependencies{
  project(path: ':a', configuration: 'generatedJars')
}

It works OK, except that adding generateJars.outputs.files as a dependency does not tell gradle that it has to run generateJars task when there are no jars generated yet. I have tried adding the task itself as a dependency hoping that it would work in the same way as it does when you add a jar/zip task to an artifact configuration (e.g. artifacts{ myJarTask }), but it throws an error telling me that I cannot do that. Of course I can inject the generateJars task somewhere in the build process before :b starts evaluating, but that's clumsy and brittle, so I would like to avoid it.

I feel like I should be adding the generated jars to artifacts{ ... } of the project, but I am not sure how to make them then visible to dependent projects. Is there a better way of achieving this?

Dependent projects (project b) will need to do setup IntelliJ IDEA module classpath to point to project a's generated jars. Something rather like this (pseudo-code):

//b.gradle

idea{
  module{
    scopes.COMPILE.plus += project(path: ':a', configuration: 'generatedJars').files
  }
}

So far I have tried simply adding a project dependecy on :a's generatedJars in :b, but Idea plugin simply adds module :a as a module-dependency and assumes that it exports its generated jars (which is probably a correct assumption), therefore not adding the generated jars to :b's classpath.

Any help would be greatly appreciated!

Upvotes: 6

Views: 10226

Answers (2)

smac89
smac89

Reputation: 43128

For my use case, I had a C++ project which generated some native libraries which my java project needed to load in order to run.

In the project ':native' build.gradle:

task compile(type: Exec, group: 'build') {
    dependsOn ...

    outputs.files(fileTree('/some/build/directory') {
        include 'mylib/libmy.so'
    })

    ...
}

In project java application build.gradle:

configurations {
    nativeDep
}

// Add dependency on the task that produces the library
dependencies {
    nativeDep files(project(':native').tasks.findByPath('compile'))
}

// Unfortunately, we also have to do this because gradle will only
// run the ':native:compile' task if we needed the tasks inputs for another
// task
tasks.withType(JavaCompile) {
    dependsOn ':native:compile'
}

run {
    doFirst {
        // Use the configuration to add our library to java.library.path
        def libDirs = files(configurations.nativeDep.files.collect {it.parentFile})
        systemProperty "java.library.path", libDirs.asPath
    }
}

Upvotes: 1

Peter Niederwieser
Peter Niederwieser

Reputation: 123910

First, do you need a separate configuration? That is, do you have clients of a that should not see the generated Jars? If not, you can add the generated Jars to the archives configuration, which will simplify things.

Second, the correct way to add the generated Jars to the configuration is (instead of the dependencies block):

artifacts {
    generatedJars generateJars
}

This should make sure that the generateJars task gets run automatically when needed.

Third, I'd omit the += after outputs.files, although it might not make a difference. You should also add the necessary inputs.

Fourth, why do you need a JavaExec task to generate the Jars? Can you instead add the generated sources to some source set and let Gradle build them?

Fifth, IDEA doesn't have a concept corresponding to Gradle's project configuration dependencies. Either an IDEA module fully depends on another module, or not at all. You have two options: either use a module dependency and make the generated sources a source folder of the depended-on module (preferably both in the Gradle and the IDEA build), or pass the generated Jars as external dependencies to IDEA. In either case, you should probably add a task dependency from ideaModule to the appropriate generation task. If this still doesn't lead to a satisfactory IDEA setup, you could think about moving the generation of the Jars into a separate subproject.

Upvotes: 2

Related Questions