Gradle: Can I compile code that depends on its own output?

This is a strange question, but it is not theoretical ...

  • I would like to create a Gradle project that uses buildSrc with a java project inside. This Java project defines some of the classes used in the build process.

  • A nasty trick: the Gradle project creates a bunch of outputs, including modified classes that belong to the buildSrc Java project itself.

Is there a way to express this with Gradle?

The only solution that I have in mind right now is to run the entire build script twice in a row. Is there any way to avoid this? For example, by creating modified code for buildSrc , recompiling buildSrc and then creating additional outputs from the main Gradle project?

+4
source share
2 answers

Well, relying on a wonderful example of Michael Easter, I can call the GradleBuild main level GradleBuild on one of my own tasks:

 task generateNewCode() << { println("tracer top build") // BuildTool is a Java class defined in `buildSrc` // ... and it has a cyclic dependency on its own // output (eek -- but that what I'm dealing with!) BuildTool.generateNewCode(); } task generateDocs(type: GradleBuild) { buildFile='build.gradle' tasks = ['generateDocs_Real'] } task generateDocs_Real << { BuildTool.outputDocumentation(); } generateDocs.dependsOn generateNewCode 

Then I can call gradle generateDocs :

  • Codegen (creating new java classes in buildSrc
  • Recompile buildSrc
  • Create documentation using helpers from recompiled buidSrc
+2
source

I believe the 59.4 Gradle doc section may help you.

Using Gradle 1.8, I tried "running another Gradle construct from an assembly", where another Gradle assembly is buildSrc.

This does not apply to codegen, but may be enough to help.

For replication, I have a simple Java project in buildSrc, with build.gradle, which looks like this:

 apply plugin: 'java' build << { println "TRACER: hello from buildSrc java build" } task compile2() << { println "TRACER: hello from buildSrc compile2" } 

The build task is called automatically through the buildSrc mechanism. The goal is to call 'compile2' from the root. In the root, build.gradle looks like this:

 task build1() << { println "TRACER: top-level build1" } task build2(type: GradleBuild) { buildFile = 'buildSrc/build.gradle' tasks = ['compile2'] } build2.dependsOn build1 

At the root level, the output is as follows:

 $ gradle build2 :buildSrc:compileJava etc etc TRACER: hello from buildSrc java build TRACER: top-level build1 TRACER: hello from buildSrc compile2 

This shows that:

  • compiled Java project in buildSrc
  • the root 'build1' is called (compile your main project here)
  • buildSrc 'compile2' is called

The pathpath and codegen classes are nasty, but can be straightforward.

+1
source

All Articles