Reputation: 47163
I would like to create a project whose build process includes some code generation. The generated code has a compile-time dependency on the main code (it extends a common base class), and on a module from JCenter. The main code effectively has a run-time dependency on the generated code; perhaps it's more correct to say that the application has a runtime dependency on both the main and generated code, plus the module dependencies of both.
EDIT: to make the dependencies clearer, here's a shoddy diagram, where arrows point from a configuration to something it depends on. As you can see, there are no cycles in the dependency graph.
main compile ← generated compile → generated module
↑ ↑
main runtime → generated runtime
I would really like to put the generated code in a separate source set to the main code. I would also really like to use the application plugin, to provide gradle run
and gradle installDist
.
I'm using Gradle 3.3, the latest available.
I've created a project to try this. In it, the source sets are:
sourceSets {
generated {
java {
srcDirs = ["$buildDir/src/generated/java"]
compileClasspath += sourceSets.main.output
}
}
main {
java {
runtimeClasspath += sourceSets.generated.output + sourceSets.generated.runtimeClasspath
}
}
}
And there is a task to generate the code:
task generateSource {
doLast {
// generate the code into sourceSets.generated.java.srcDirs[0] here
}
}
compileGeneratedJava.dependsOn generateSource
Generation and compilation of the generated code work fine. If i say gradle generatedClasses
, it compiles the main code, generates the source, and then compiles the generated code.
However, neither running nor distribution work correctly. If i say gradle run
, it doesn't attempt to generate or compile the generated code. If i say gradle generatedClasses run
, then the generated code is generated and compiled, but not added to the classpath of the executed Java process. If i say gradle installDist
, then it doesn't attempt to generator or compile the generated code, and, similarly, if i say gradle generatedClasses installDist
, the generated code is generated and compiled, but not included in the distribution.
The module dependencies of the generated source set are also not included in the classpath or the distribution.
The really weird thing is that if i define by own version of the run task:
task runProperly(type: JavaExec) {
classpath = sourceSets.main.runtimeClasspath
main = mainClassName
}
That works perfectly!
So, why are neither the compiled classes nor the module dependencies of the generated source set being included in the run or distribution classpaths?
Upvotes: 5
Views: 3301
Reputation: 1834
Because application
plugin has set the classpath before you change sourcesets. If you move apply plugin: 'application'
after sourcesets {}
the build will work as you expected.
But from my opinion a sourceset
is not a correct place for generated code. Your build should look like:
apply plugin: 'application'
repositories {
jcenter()
}
dependencies {
compile group: 'org.fusesource.jansi', name: 'jansi', version: '1.14'
compile group: 'org.slf4j', name: 'slf4j-api', version: '1.7.22'
runtime group: 'ch.qos.logback', name: 'logback-classic', version: '1.1.9'
}
mainClassName = 'Application'
task generateSources {
outputs.dir temporaryDir
doLast {
// Generate some code into temporaryDir
}
}
compileJava {
source generateSources
}
Upvotes: 3