How can I compile generated sources?

I need to do source code generation and found http://gradle.1045684.n5.nabble.com/GenerateSources-functionality-for-SourceSets-td4600652.html. The example given for SourceSetOutput using buildBy doesn’t exist for SourceSet (as noted in the other post).

Can you point me to an example of how to have a task generate Java source to be built by the Java plugin?

Hi Mark,

Dealing with generated source is currently not as nice as we’d like it to be, but here’s a general template you could use:

apply plugin: "java"
  task generateSources {
  outputDir = file("$buildDir/generated-src")
  outputs.dir outputDir
    doFirst {
    outputDir.exists() || outputDir.mkdirs()
    new File(outputDir, "Generated.java").write("public class Generated {}")
  }
}
  compileJava.source generateSources.outputs.files, sourceSets.main.java

The key parts are:

outputs.dir outputDir

And then:

compileJava.source generateSources.outputs.files, sourceSets.main.java

This configures the necessary task dependencies as well as the locations of the extra source.

Please let me know if you’d like me to expand on any of that.

We’ll definitely make this simpler in a future version.

1 Like

Thanks. Here’s how I did it after reading the Antlr plugin code:

apply plugin: 'java'
  task generateSource(type: Copy) {
 from 'src/main/mpfw'
 into 'build/generated-src/main/java'
}
  compileJava.dependsOn generateSource
  sourceSets {
 main {
  java {
   srcDir 'build/generated-src/java'
  }
 }
}

It seems our solutions are similar. I didn’t know you could construct the compileJava.source the way you did. There are so many clever things like this in Gradle I don’t understand yet.

I’ve almost got the equivalent written in a custom plugin by copying the antlr plugin.

It does seem a generic solution is in order. Would it make sense to have a generic “codeGeneration” plugin that had a DSL accepting the name of the task to do the code generation, the dependencies for that task, etc? I work on a large code baseline with several different kinds of code generation over many modules. It doesn’t make sense to replicate this logic in lots of places.

@mark, a generic solution would be very useful. Code generation is such a common concept that it should be baked into Gradle’s model.

Mark,

There’s a key difference between our two approaches in that you’ve had to duplicate the location of the generated source. In you’re example they are also actually different, which makes a good case for removing the duplication :slight_smile:

Implicit task dependencies are very powerful, yet I like Mark’s solution tiny bit better. I’m fine with a bit more redundancy/explicitness if it makes the build script clearer for a non-pro gradle user. The duplication could be removed by a variable or dynamic property on a task.

Also, Mark’s solution will work out of the box with IDE integration (our eclipse and idea plugins, and 3rd party tools like STS, JetBrains plugin).

Obviously, down the road we should have a generic solution, possibly an explicit dsl for code generation stuff.

A quick request for improved documentation on this.

The current documentation for source sets and SourceSetOutput at:

DSL Documentation for SourceSetOutput

and

Java docs for SourceSetOutput

gives an example of how to compile generated sources. The example code does not work in M6 and M7 as written. It’s good that the forums had an answer, but we would probably want to update the docs as well.

Hey, the examples show only how to put generated ‘resources’ on path, e.g. not how to generate/compile sources.

Why do you think they are not working?

I stand corrected sir. Yes, they do indeed only talk about generated ‘resources’ as opposed to generated ‘sources’ and compiling them. What threw me off were comments like:

...
//it is now a part of the 'main' classpath and will be a part of the jar
...
//Java plugin task 'classes' and 'testClasses' will automatically depend on relevant tasks registered with 'builtBy'
...

which for a casual (or careless as in my case) reader might indicate compilation.

This does however not necessarily mean we don’t need an improvement of the docs. Is there a section in the docs explaining how to deal with ‘generated sources’ and the compilation of them? I failed to find it, but I’ll refrain from being wrong twice in the same thread and leave the question open : )

No worries :slight_smile:

Please suggest improvements to the docs (pull request maybe?). I don’t think we have an idiomatic example for generated compile sources in the user guide (which should be fixed!) but I thought there’s something on that matter in forums.

Does anyone know how to disable warnings when compiling generated classes?

I would like to see compile warnings for my source code only. I do not wish to see compile warnings for generated classes.

Here is my code:

File generatedDir = new File(buildDir.toString() + ‘/generated’)

//Include generated classes in the sourceSets for compilation

sourceSets.main.java

{

srcDir generatedDir

}

Any help would be greatly appreciated. Thanks!

Yes, this thread answers the question and it obviously lives in the forums so we do have an answer in the forums : )

I think Luke’s first answer in this thread is an excellent idiomatic example. Had I found that answer in the docs it would have solved my issue.

oh man, I forgot that it’s exactly this thread :smiley:

The information here is two years old, and there is a comment that this should be done more generically. Has a better way been built into gradle now?

Not for java sources. But we’ve added some nicer support for generated sources to the new C++ support, and we plan to roll that into the new java plugins in Gradle 2.0.

Did a generic solution for Java ended up in 2.x? I want to do use apt.

I’m also wanting to use the Java solution. Did it make it in 2.x?