This is derived from a bug I just filed on IntJ: https://youtrack.jetbrains.com/issue/IDEA-302732/Gradle-wrapper-builds-jar-from-custom-source-set-without-error-but-intelliJ-fails-import
I don't think it is a real problem in the sense that all this works with gradle, but it produces spurious errors in IntJ and, until the bug (if it be) is fixed, I'm looking for a way around. It could be derived from some unconventional practice of mine, so if you see anything that makes you think "there's a more conventional method here", let me know.
I'm using a custom sourceset to build an executable jar in a library project; it's for a tool that uses the lib but isn't included in it. I know other people use a similar method for demos and integration tests.
I put together a minimal example for the bug report, here's the meat of build.gradle.kts
(the whole thing is posted in the report if you want/need):
sourceSets["main"].java.srcDir("src")
sourceSets.create("eg") {
java.srcDirs("src", "eg")
compileClasspath = sourceSets["main"].compileClasspath
}
tasks.register<Jar>("foobar") {
archiveFileName.set("foobar.jar")
manifest { attributes["Main-Class"] = "FoobarKt" }
// Not sure why this is necessary here, it isn't in the original project.
duplicatesStrategy = org.gradle.api.file.DuplicatesStrategy.EXCLUDE
dependsOn(configurations.runtimeClasspath)
from(sourceSets["eg"].output)
from({
configurations.runtimeClasspath.get().filter {
it.name.endsWith("jar") }.map { zipTree(it) }
})
}
src/main/kotlin/Example/Example.kt:
package Example
class Example {
fun hello () {
println("hello world")
}
}
And in eg/Foobar.kt, the entry point for the executable jar:
import Example.Example
fun main () {
val eg = Example()
eg.hello()
}
If I run ./gradlew foobar
from the project directory, it builds without error and runs via java -jar
as expected.
However, in the IntJ editor, Foobar.kt has "unresolved reference" errors for Example
on lines 1 and 4. It suggests I "Add dependency on module Problem.main", which is clickable but does nothing.1
I admit to not being much of a gradle fan -- for whatever reason the supposedly (?) intuitive DSL is persistently counter-intuitive with me, I'd much rather just use a more normal API (if the build system is going to be Turing complete, why dress it down inscrutably?) -- and I just don't get what is meant by that.
- There's a slew of other reports going back for years about this "add dependency on module..." suggestion doing nothing in various contexts.
CodePudding user response:
Thanks to Andrey for posting a solution in the bug report. Whether it remains a bug to be fixed or an inconsistency to be noted is up to others, but what works is to add the output
of the main sourceset to the compileClasspath
in the definition of the custom one:
sourceSets.create("eg") {
java.srcDirs("src", "eg")
compileClasspath = sourceSets["main"].compileClasspath
// You can use ' ' as well to combine these in one line.
compileClasspath = sourceSets["main"].output
}
You actually only need the output
to resolve the problem in the example from the question here, but if the custom sourceset code includes imports of project dependencies declared with implementation
or api
, you need
the main compileClasspath
as well.