wholerabbit
wholerabbit

Reputation: 11567

Include dependency for custom sourceSet

I have a build.gradle.kts for a small, pure kotlin project (I am aware I am using slightly non-standard source paths):

plugins {
    kotlin("jvm") version "1.3.72"
}

repositories { mavenCentral() }

dependencies {
    implementation(kotlin("stdlib-jdk8"))
    testImplementation("org.jetbrains.kotlin:kotlin-test")
    testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}

sourceSets["main"].java.srcDir("src")
sourceSets["test"].java.srcDirs("test")
sourceSets {
    create("demo")?.let {
        it.java.srcDir("demo")
        // Also tried:  it.java.srcDirs("src", "demo")
        it.compileClasspath += main.get().output
        it.runtimeClasspath += main.get().output
    }
}

tasks {
    compileKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
    compileTestKotlin {
        kotlinOptions.jvmTarget = "1.8"
    }
}

listOf("InteractiveClient", "LockingBufferDemo").forEach {
    tasks.register<Jar>(it) {
        manifest { attributes["Main-Class"] = "${it}Kt" }
        from(sourceSets.main.get().output)
        from(sourceSets["demo"].output) {
            include("**/${it}Kt.class")
        }
        dependsOn(configurations.runtimeClasspath)
        from({
            configurations.runtimeClasspath.get().filter {
                it.name.endsWith("jar") }.map { zipTree(it) }
        })
    }

}

When I try to run one of the "demo" sourceSet based jar tasks ("InteractiveClient" and "LockingBufferDemo"),1 I get a the long list of "Cannot access built-in..." errors indicating the kotlin stdlib is not properly in play.

The actual failing task is compileDemoKotlin, so I tried adding mimetically to the tasks block:

withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
    this.kotlinOptions.jvmTarget = "1.8"
}

Which makes no difference.

What's strange to me is that the demo stuff was originally in the test sourceSet, and changing the above back to that (by removing the definition, changing from(sourceSets["demo"]... to from(sourceSets.test... in the jar task(s), and moving the source file) makes the problem disappear. It works.

I don't want this stuff in with automated tests. I imagine I could put them in branches of the main or test set and then use a from() { exclude(... pattern in building the jars, but that seems awkward and unnecessary.

How do I get a custom source set to compile against the default project dependencies?


  1. See this other recent question of mine about the from(... include( in the jar tasks.

Upvotes: 3

Views: 2867

Answers (2)

Bj&#248;rn Vester
Bj&#248;rn Vester

Reputation: 7598

It looks to me like you are missing the configurations that will make the demo source sets use the same dependencies as the main set. Something like this:

configurations["demoImplementation"].extendsFrom(configurations.implementation.get())
configurations["demoRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get())

There is an example in the user guide here that seems to have a very similar use case as yours.

Also, from the issue you created in the Gradle repository, you mentioned it failed with:

Unresolved reference: printlin

I am pretty sure this is a typo of println.

Upvotes: 3

Nicolas
Nicolas

Reputation: 7121

I'm not entirely sure what you're trying to do with your jar files, but I spotted a few problems in your build script:

  • You have set your source sets like this:

    sourceSets["main"].java.srcDir("src")
    sourceSets["test"].java.srcDirs("src", "test")
    sourceSets {
        create("demo")?.let {
            it.java.srcDir("demo")
        }
    }
    

    This means you're supposed the following directory structure:

    - <module root>
      - src     <-- Belongs to both 'main' and a 'test' source sets!
      - test    <-- Belongs to the 'test' source set
      - demo    <-- Belongs to the 'demo' source set
    

    As you can see, there's a directory that belongs to two source sets. I'm not sure how this turns out in practice, probably one or the other is discarded. Here's a more standard directory structure:

    - <module root>
      - src
        - main
        - test
        - demo
    

    You configure it like this:

    sourceSets {
        main {
            java.srcDir("src/main")
        }
        test {
            java.srcDir("src/test")
        }
        create("demo") {
            java.srcDir("src/demo")
        }
    }
    
  • The task compileDemoKotlin actually exists, but you can't access it just like that. If you look at the compileKotlin and compileTestKotlin extension functions source, they look like this:

    val TaskContainer.`compileKotlin`: TaskProvider<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
        get() = named<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>("compileKotlin")
    

    So the trick is to use named to get the task instead:

    named<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>("compileDemoKotlin") {
        kotlinOptions.jvmTarget = "1.8"
    }
    

I don't know if that answers your question. If I missed anything please let me know.

Upvotes: 1

Related Questions