Allow to set non-default JDK for tasks via java toolchain.

Has to split jdk/toolchain setters, because, when toolchain setter is
in the 'UsesKotlinJavaToolchain', Groovy fails to create meta class
on <Gradle 6.7 with ClassNotFoundException.

^KT-43092 In Progress
This commit is contained in:
Yahor Berdnikau
2021-05-19 17:43:18 +02:00
committed by Space
parent de5dcfcbd8
commit 8e1c420c9f
3 changed files with 128 additions and 31 deletions
@@ -10,6 +10,7 @@ import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested
import org.gradle.jvm.toolchain.JavaLauncher
import java.io.File
interface UsesKotlinJavaToolchain {
@@ -25,27 +26,44 @@ interface KotlinJavaToolchain {
@get:Input
val javaVersion: Provider<JavaVersion>
/**
* Set JDK to use for Kotlin compilation.
*
* Major JDK version is considered as compile task input.
*
* @param jdkHomeLocation path to JDK.
* *Note*: project build will fail on providing here JRE instead of JDK!
* @param jdkVersion provided JDK version
*/
fun setJdkHome(
jdkHomeLocation: File,
jdkVersion: JavaVersion
)
@get:Internal
val jdk: JdkSetter
/**
* Set JDK to use for Kotlin compilation.
*
* @see [setJdkHome]
*/
fun setJdkHome(
jdkHomeLocation: String,
jdkVersion: JavaVersion
) = setJdkHome(File(jdkHomeLocation), jdkVersion)
@get:Internal
val toolchain: JavaToolchainSetter
interface JdkSetter {
/**
* Set JDK to use for Kotlin compilation.
*
* Major JDK version is considered as compile task input.
*
* @param jdkHomeLocation path to JDK.
* *Note*: project build will fail on providing here JRE instead of JDK!
* @param jdkVersion provided JDK version
*/
fun use(
jdkHomeLocation: File,
jdkVersion: JavaVersion
)
/**
* Set JDK to use for Kotlin compilation.
*
* @see [use]
*/
fun use(
jdkHomeLocation: String,
jdkVersion: JavaVersion
) = use(File(jdkHomeLocation), jdkVersion)
}
interface JavaToolchainSetter {
/**
* Set JDK obtained from [org.gradle.jvm.toolchain.JavaToolchainService] to use for Kotlin compilation.
*/
fun use(
javaLauncher: Provider<JavaLauncher>
)
}
}
@@ -243,6 +243,22 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
}
}
@DisplayName("Should allow to set JDK version for tasks via Java toolchain")
@GradleTestVersions(minVersion = "6.7")
@GradleTest
internal fun setJdkUsingJavaToolchain(gradleVersion: GradleVersion) {
project(
projectName = "simple".fullProjectName,
gradleVersion = gradleVersion,
forceOutput = true
) {
useToolchainToCompile(11)
build("assemble") {
assertDaemonIsUsingJdk(getToolchainExecPathFromLogs())
}
}
}
private fun BuildResult.assertDaemonIsUsingJdk(
javaexecPath: String
) = assertOutputContains("i: connected to the daemon. Daemon is using following 'java' executable to run itself: $javaexecPath")
@@ -270,7 +286,7 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
project.tasks
.withType(UsesKotlinJavaToolchain.class)
.configureEach {
it.kotlinJavaToolchain.setJdkHome(
it.kotlinJavaToolchain.jdk.use(
"${getJdk9Path()}",
JavaVersion.VERSION_1_9
)
@@ -278,4 +294,42 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
""".trimIndent()
)
}
private fun TestProject.useToolchainToCompile(
jdkVersion: Int
) {
//language=Groovy
rootBuildGradle.append(
"""
import org.jetbrains.kotlin.gradle.tasks.UsesKotlinJavaToolchain
java {
toolchain {
languageVersion.set(JavaLanguageVersion.of($jdkVersion))
}
}
def toolchain = project.extensions.getByType(JavaPluginExtension.class).toolchain
def service = project.extensions.getByType(JavaToolchainService.class)
def defaultLauncher = service.launcherFor(toolchain)
project.tasks
.withType(UsesKotlinJavaToolchain.class)
.configureEach {
it.kotlinJavaToolchain.toolchain.use(
defaultLauncher
)
}
afterEvaluate {
logger.info("Toolchain exec path: ${'$'}{defaultLauncher.get().executablePath.asFile.absolutePath}")
}
""".trimIndent()
)
}
private fun BuildResult.getToolchainExecPathFromLogs() = output
.lineSequence()
.first { it.startsWith("Toolchain exec path:") }
.substringAfter("Toolchain exec path: ")
}
@@ -14,6 +14,7 @@ import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Internal
import org.gradle.internal.jvm.Jvm
import org.gradle.jvm.toolchain.JavaLauncher
import org.jetbrains.kotlin.gradle.utils.chainedFinalizeValueOnRead
import org.jetbrains.kotlin.gradle.utils.property
import org.jetbrains.kotlin.gradle.utils.propertyWithConvention
@@ -82,14 +83,38 @@ abstract class KotlinJavaToolchainProvider @Inject constructor(
objects.propertyWithConvention<File?>(null)
})
override fun setJdkHome(
jdkHomeLocation: File,
jdkVersion: JavaVersion
) {
val jvm = Jvm.forHome(jdkHomeLocation) as Jvm
override val jdk: KotlinJavaToolchain.JdkSetter = DefaultJdkSetter()
javaExecutable.set(jvm.javaExecutable)
_jdkToolsJar.set(jvm.toolsJar)
_javaVersion.set(jdkVersion)
override val toolchain: KotlinJavaToolchain.JavaToolchainSetter = DefaultJavaToolchainSetter()
private inner class DefaultJdkSetter : KotlinJavaToolchain.JdkSetter {
override fun use(
jdkHomeLocation: File,
jdkVersion: JavaVersion
) {
val jvm = Jvm.forHome(jdkHomeLocation) as Jvm
javaExecutable.set(jvm.javaExecutable)
_jdkToolsJar.set(jvm.toolsJar)
_javaVersion.set(jdkVersion)
}
}
private inner class DefaultJavaToolchainSetter : KotlinJavaToolchain.JavaToolchainSetter {
override fun use(
javaLauncher: Provider<JavaLauncher>
) {
javaExecutable.set(javaLauncher.map { it.executablePath })
_javaVersion.set(
javaLauncher.map {
JavaVersion.toVersion(it.metadata.languageVersion)
}
)
_jdkToolsJar.set(
javaLauncher.map {
Jvm.forHome(it.metadata.installationPath.asFile).toolsJar
}
)
}
}
}