Set 'jvmTarget' value on toolchain configuration.

Toolchain will set 'kotlinOptions.jvmTarget' value to the toolchain
jdk version, if 'jvmTarget' is not explicitly set by user.

If toolchain is not configured, 'jvmTarget' field uses default value,
which is now - "1.8".

^KT-45611 In Progress
^KT-43095 In Progress
This commit is contained in:
Yahor Berdnikau
2021-06-21 17:21:53 +02:00
committed by Space
parent 430306b23d
commit af2f716f4d
6 changed files with 198 additions and 32 deletions
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle package org.jetbrains.kotlin.gradle
import org.gradle.api.JavaVersion
import org.gradle.api.logging.LogLevel import org.gradle.api.logging.LogLevel
import org.gradle.internal.jvm.JavaInfo import org.gradle.internal.jvm.JavaInfo
import org.gradle.internal.jvm.Jvm import org.gradle.internal.jvm.Jvm
@@ -62,7 +63,10 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
projectName = "simple".fullProjectName, projectName = "simple".fullProjectName,
gradleVersion = gradleVersion, gradleVersion = gradleVersion,
) { ) {
useJdk9ToCompile() useJdkToCompile(
getJdk9Path(),
JavaVersion.VERSION_1_9
)
build("assemble") { build("assemble") {
assertJdkHomeIsUsingJdk(getJdk9().javaHomeRealPath) assertJdkHomeIsUsingJdk(getJdk9().javaHomeRealPath)
@@ -84,7 +88,10 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
if (shouldUseToolchain(gradleVersion)) { if (shouldUseToolchain(gradleVersion)) {
useToolchainExtension(11) useToolchainExtension(11)
} else { } else {
useJdk9ToCompile() useJdkToCompile(
getJdk9Path(),
JavaVersion.VERSION_1_9
)
} }
build("assemble") build("assemble")
@@ -100,7 +107,10 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
if (shouldUseToolchain(gradleVersion)) { if (shouldUseToolchain(gradleVersion)) {
useToolchainExtension(11) useToolchainExtension(11)
} else { } else {
useJdk9ToCompile() useJdkToCompile(
getJdk9Path(),
JavaVersion.VERSION_1_9
)
} }
build("assemble") { build("assemble") {
@@ -124,7 +134,10 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
if (shouldUseToolchain(gradleVersion)) { if (shouldUseToolchain(gradleVersion)) {
useToolchainExtension(11) useToolchainExtension(11)
} else { } else {
useJdk9ToCompile() useJdkToCompile(
getJdk9Path(),
JavaVersion.VERSION_1_9
)
} }
build("assemble") build("assemble")
} }
@@ -153,7 +166,10 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
if (shouldUseToolchain(gradleVersion)) { if (shouldUseToolchain(gradleVersion)) {
useToolchainExtension(11) useToolchainExtension(11)
} else { } else {
useJdk9ToCompile() useJdkToCompile(
getJdk9Path(),
JavaVersion.VERSION_1_9
)
} }
gradleProperties.append( gradleProperties.append(
"kapt.workers.isolation = none" "kapt.workers.isolation = none"
@@ -202,7 +218,10 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
if (shouldUseToolchain(gradleVersion)) { if (shouldUseToolchain(gradleVersion)) {
useToolchainExtension(11) useToolchainExtension(11)
} else { } else {
useJdk9ToCompile() useJdkToCompile(
getJdk9Path(),
JavaVersion.VERSION_1_9
)
} }
build("assemble") build("assemble")
@@ -218,7 +237,10 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
if (shouldUseToolchain(gradleVersion)) { if (shouldUseToolchain(gradleVersion)) {
useToolchainExtension(11) useToolchainExtension(11)
} else { } else {
useJdk9ToCompile() useJdkToCompile(
getJdk9Path(),
JavaVersion.VERSION_1_9
)
} }
build("assemble") { build("assemble") {
@@ -272,8 +294,7 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
internal fun jdkHomeIsDeprecated(gradleVersion: GradleVersion) { internal fun jdkHomeIsDeprecated(gradleVersion: GradleVersion) {
project( project(
projectName = "simple".fullProjectName, projectName = "simple".fullProjectName,
gradleVersion = gradleVersion, gradleVersion = gradleVersion
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) { ) {
//language=Groovy //language=Groovy
rootBuildGradle.append( rootBuildGradle.append(
@@ -340,14 +361,95 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
} }
} }
@DisplayName("Should set 'jvmTarget' option if user does not specify it explicitly via jdk setter")
@GradleTest
internal fun shouldSetJvmTargetNonSpecifiedByUserViaSetJdk(gradleVersion: GradleVersion) {
project(
projectName = "simple".fullProjectName,
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
useJdkToCompile(
getJdk11Path(),
JavaVersion.VERSION_11
)
build("build") {
assertOutputContains("-jvm-target 11")
assertOutputDoesNotContain("-jvm-target 1.8")
}
}
}
@DisplayName("Should not override user specified 'jvmTarget' option via jdk setter")
@GradleTest
internal fun shouldNotOverrideUserJvmTargetViaSetJDK(gradleVersion: GradleVersion) {
project(
projectName = "simple".fullProjectName,
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
setJvmTarget("1.8")
useJdkToCompile(
getJdk11Path(),
JavaVersion.VERSION_11
)
build("build") {
assertOutputContains("-jvm-target 1.8")
assertOutputDoesNotContain("-jvm-target 11")
}
}
}
@DisplayName("Should set 'jvmTarget' option if user does not specify it explicitly via toolchain setter")
@GradleTestVersions(minVersion = "6.7.1")
@GradleTest
internal fun shouldSetJvmTargetNonSpecifiedByUserViaToolchain(gradleVersion: GradleVersion) {
project(
projectName = "simple".fullProjectName,
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
useToolchainToCompile(11)
build("build") {
assertOutputContains("-jvm-target 11")
assertOutputDoesNotContain("-jvm-target 1.8")
}
}
}
@DisplayName("Should not override user specified 'jvmTarget' option via toolchain setter")
@GradleTestVersions(minVersion = "6.7.1")
@GradleTest
internal fun shouldNotOverrideUserSpecifiedJvmTargetViaToolchain(gradleVersion: GradleVersion) {
project(
projectName = "simple".fullProjectName,
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
setJvmTarget("1.8")
useToolchainToCompile(11)
build("build") {
assertOutputContains("-jvm-target 1.8")
assertOutputDoesNotContain("-jvm-target 11")
}
}
}
private fun BuildResult.assertJdkHomeIsUsingJdk( private fun BuildResult.assertJdkHomeIsUsingJdk(
javaexecPath: String javaexecPath: String
) = assertOutputContains("[KOTLIN] Kotlin compilation 'jdkHome' argument: $javaexecPath") ) = assertOutputContains("[KOTLIN] Kotlin compilation 'jdkHome' argument: $javaexecPath")
private fun getUserJdk(): JavaInfo = Jvm.forHome(File(System.getenv("JAVA_HOME"))) private fun getUserJdk(): JavaInfo = Jvm.forHome(File(System.getenv("JAVA_HOME")))
private fun getJdk9(): JavaInfo = Jvm.forHome(File(System.getenv("JDK_9"))) private fun getJdk9(): JavaInfo = Jvm.forHome(File(System.getenv("JDK_9")))
private fun getJdk11(): JavaInfo = Jvm.forHome(File(System.getenv("JDK_11")))
// replace required for windows paths so Groovy will not complain about unexpected char '\' // replace required for windows paths so Groovy will not complain about unexpected char '\'
private fun getJdk9Path(): String = getJdk9().javaHome.absolutePath.replace("\\", "\\\\") private fun getJdk9Path(): String = getJdk9().javaHome.absolutePath.replace("\\", "\\\\")
private fun getJdk11Path(): String = getJdk11().javaHome.absolutePath.replace("\\", "\\\\")
private val JavaInfo.javaHomeRealPath private val JavaInfo.javaHomeRealPath
get() = javaHome get() = javaHome
.toPath() .toPath()
@@ -357,7 +459,26 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
private val String.fullProjectName get() = "kotlin-java-toolchain/$this" private val String.fullProjectName get() = "kotlin-java-toolchain/$this"
private fun TestProject.useJdk9ToCompile() { private fun TestProject.setJvmTarget(
jvmTarget: String
) {
//language=Groovy
rootBuildGradle.append(
"""
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
kotlinOptions {
jvmTarget = "$jvmTarget"
}
}
""".trimIndent()
)
}
private fun TestProject.useJdkToCompile(
jdkPath: String,
jdkVersion: JavaVersion
) {
//language=Groovy //language=Groovy
rootBuildGradle.append( rootBuildGradle.append(
""" """
@@ -368,8 +489,8 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
.withType(UsesKotlinJavaToolchain.class) .withType(UsesKotlinJavaToolchain.class)
.configureEach { .configureEach {
it.kotlinJavaToolchain.jdk.use( it.kotlinJavaToolchain.jdk.use(
"${getJdk9Path()}", "$jdkPath",
JavaVersion.VERSION_1_9 JavaVersion.${jdkVersion.name}
) )
} }
""".trimIndent() """.trimIndent()
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable
import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.property
import org.jetbrains.kotlin.gradle.utils.propertyWithNewInstance import org.jetbrains.kotlin.gradle.utils.propertyWithNewInstance
import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File import java.io.File
import java.util.concurrent.Callable import java.util.concurrent.Callable
import java.util.jar.JarFile import java.util.jar.JarFile
@@ -124,11 +125,15 @@ abstract class KaptTask @Inject constructor(
@get:Internal @get:Internal
abstract val classpath: ConfigurableFileCollection abstract val classpath: ConfigurableFileCollection
final override val kotlinJavaToolchainProvider: Provider<KotlinJavaToolchainProvider> = objectFactory @get:Internal
internal val defaultKotlinJavaToolchain: Provider<KotlinJavaToolchainProvider> = objectFactory
.propertyWithNewInstance( .propertyWithNewInstance(
project.gradle project.gradle,
{ null }
) )
final override val kotlinJavaToolchainProvider: Provider<KotlinJavaToolchain> = defaultKotlinJavaToolchain.cast()
@Suppress("unused", "DeprecatedCallableAddReplaceWith") @Suppress("unused", "DeprecatedCallableAddReplaceWith")
@Deprecated( @Deprecated(
message = "Don't use directly. Used only for up-to-date checks", message = "Don't use directly. Used only for up-to-date checks",
@@ -117,7 +117,7 @@ abstract class KaptWithKotlincTask @Inject constructor(
val compilerRunner = GradleCompilerRunner( val compilerRunner = GradleCompilerRunner(
taskProvider.get(), taskProvider.get(),
kotlinJavaToolchainProvider.get().currentJvmJdkToolsJar.orNull defaultKotlinJavaToolchain.get().currentJvmJdkToolsJar.orNull
) )
compilerRunner.runJvmCompilerAsync( compilerRunner.runJvmCompilerAsync(
sourcesToCompile = emptyList(), sourcesToCompile = emptyList(),
@@ -126,7 +126,7 @@ abstract class KaptWithKotlincTask @Inject constructor(
javaPackagePrefix = javaPackagePrefix.orNull, javaPackagePrefix = javaPackagePrefix.orNull,
args = args, args = args,
environment = environment, environment = environment,
jdkHome = kotlinJavaToolchainProvider.get().providedJvm.get().javaHome jdkHome = defaultKotlinJavaToolchain.get().providedJvm.get().javaHome
) )
} }
} }
@@ -157,7 +157,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
val kaptClasspath = kaptJars.toList() + kotlinStdlibClasspath val kaptClasspath = kaptJars.toList() + kotlinStdlibClasspath
val isolationMode = getWorkerIsolationMode() val isolationMode = getWorkerIsolationMode()
logger.info("Using workers $isolationMode isolation mode to run kapt") logger.info("Using workers $isolationMode isolation mode to run kapt")
val toolsJarURLSpec = kotlinJavaToolchainProvider.get() val toolsJarURLSpec = defaultKotlinJavaToolchain.get()
.jdkToolsJar.orNull?.toURI()?.toURL()?.toString().orEmpty() .jdkToolsJar.orNull?.toURI()?.toURL()?.toString().orEmpty()
submitWork( submitWork(
@@ -169,7 +169,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
} }
private fun getWorkerIsolationMode(): IsolationMode { private fun getWorkerIsolationMode(): IsolationMode {
val toolchainProvider = kotlinJavaToolchainProvider.get() val toolchainProvider = defaultKotlinJavaToolchain.get()
val gradleJvm = toolchainProvider.currentJvm.get() val gradleJvm = toolchainProvider.currentJvm.get()
// Ensuring Gradle build JDK is set to kotlin toolchain by also comparing javaExecutable paths, // Ensuring Gradle build JDK is set to kotlin toolchain by also comparing javaExecutable paths,
// as user may set JDK with same major Java version, but from different vendor // as user may set JDK with same major Java version, but from different vendor
@@ -199,7 +199,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor(
// for tests // for tests
it.forkOptions.jvmArgs("-verbose:class") it.forkOptions.jvmArgs("-verbose:class")
} }
it.forkOptions.executable = kotlinJavaToolchainProvider.get() it.forkOptions.executable = defaultKotlinJavaToolchain.get()
.javaExecutable .javaExecutable
.asFile.get() .asFile.get()
.absolutePath .absolutePath
@@ -17,6 +17,8 @@ import org.gradle.api.tasks.Internal
import org.gradle.internal.jvm.Jvm import org.gradle.internal.jvm.Jvm
import org.gradle.jvm.toolchain.* import org.gradle.jvm.toolchain.*
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile as KotlinCompileTask
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsBase
import org.jetbrains.kotlin.gradle.tasks.KotlinJavaToolchain.Companion.TOOLCHAIN_SUPPORTED_VERSION import org.jetbrains.kotlin.gradle.tasks.KotlinJavaToolchain.Companion.TOOLCHAIN_SUPPORTED_VERSION
import org.jetbrains.kotlin.gradle.utils.chainedFinalizeValueOnRead import org.jetbrains.kotlin.gradle.utils.chainedFinalizeValueOnRead
import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.property
@@ -25,10 +27,11 @@ import java.io.File
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.full.functions import kotlin.reflect.full.functions
abstract class KotlinJavaToolchainProvider @Inject constructor( internal abstract class KotlinJavaToolchainProvider @Inject constructor(
private val objects: ObjectFactory, private val objects: ObjectFactory,
projectLayout: ProjectLayout, projectLayout: ProjectLayout,
gradle: Gradle gradle: Gradle,
kotlinCompileTaskProvider: () -> KotlinCompileTask<KotlinJvmOptionsBase>?
) : KotlinJavaToolchain { ) : KotlinJavaToolchain {
private val currentGradleVersion = GradleVersion.version(gradle.gradleVersion) private val currentGradleVersion = GradleVersion.version(gradle.gradleVersion)
@@ -98,11 +101,15 @@ abstract class KotlinJavaToolchainProvider @Inject constructor(
@get:Internal @get:Internal
internal val currentJvmJdkToolsJar: Provider<File?> = getToolsJarFromJvm(currentJvm) internal val currentJvmJdkToolsJar: Provider<File?> = getToolsJarFromJvm(currentJvm)
final override val jdk: KotlinJavaToolchain.JdkSetter = DefaultJdkSetter(providedJvm, currentGradleVersion) final override val jdk: KotlinJavaToolchain.JdkSetter = DefaultJdkSetter(
providedJvm,
currentGradleVersion,
kotlinCompileTaskProvider
)
private val defaultJavaToolchainSetter by lazy(LazyThreadSafetyMode.NONE) { private val defaultJavaToolchainSetter by lazy(LazyThreadSafetyMode.NONE) {
if (currentGradleVersion >= TOOLCHAIN_SUPPORTED_VERSION) { if (currentGradleVersion >= TOOLCHAIN_SUPPORTED_VERSION) {
DefaultJavaToolchainSetter(providedJvm) DefaultJavaToolchainSetter(providedJvm, kotlinCompileTaskProvider)
} else { } else {
null null
} }
@@ -112,10 +119,32 @@ abstract class KotlinJavaToolchainProvider @Inject constructor(
get() = defaultJavaToolchainSetter get() = defaultJavaToolchainSetter
?: throw GradleException("Toolchain support is available from $TOOLCHAIN_SUPPORTED_VERSION") ?: throw GradleException("Toolchain support is available from $TOOLCHAIN_SUPPORTED_VERSION")
private abstract class JvmTargetUpdater(
private val kotlinCompileTaskProvider: () -> KotlinCompileTask<KotlinJvmOptionsBase>?
) {
fun updateJvmTarget(
jdkVersion: JavaVersion
) {
kotlinCompileTaskProvider()?.kotlinOptions {
if (jvmTargetField == null) {
// For Java 9 JavaVersion returns "1.9" that is not accepted by Kotlin compiler
jvmTarget = if (jdkVersion == JavaVersion.VERSION_1_9) {
"9"
} else {
jdkVersion.toString()
}
}
}
}
}
private class DefaultJdkSetter( private class DefaultJdkSetter(
private val providedJvm: Property<Jvm>, private val providedJvm: Property<Jvm>,
private val currentGradleVersion: GradleVersion private val currentGradleVersion: GradleVersion,
) : KotlinJavaToolchain.JdkSetter { kotlinCompileTaskProvider: () -> KotlinCompileTask<KotlinJvmOptionsBase>?
) : JvmTargetUpdater(kotlinCompileTaskProvider),
KotlinJavaToolchain.JdkSetter {
override fun use( override fun use(
jdkHomeLocation: File, jdkHomeLocation: File,
@@ -139,22 +168,28 @@ abstract class KotlinJavaToolchainProvider @Inject constructor(
Jvm.discovered(jdkHomeLocation, null, jdkVersion) Jvm.discovered(jdkHomeLocation, null, jdkVersion)
) )
} }
updateJvmTarget(jdkVersion)
} }
} }
private inner class DefaultJavaToolchainSetter( private inner class DefaultJavaToolchainSetter(
private val providedJvm: Property<Jvm> private val providedJvm: Property<Jvm>,
) : KotlinJavaToolchain.JavaToolchainSetter { kotlinCompileTaskProvider: () -> KotlinCompileTask<KotlinJvmOptionsBase>?
) : JvmTargetUpdater(kotlinCompileTaskProvider),
KotlinJavaToolchain.JavaToolchainSetter {
override fun use( override fun use(
javaLauncher: Provider<JavaLauncher> javaLauncher: Provider<JavaLauncher>
) { ) {
providedJvm.set( providedJvm.set(
javaLauncher.map { javaLauncher.map {
val metadata = javaLauncher.get().metadata val metadata = javaLauncher.get().metadata
val javaVersion = JavaVersion.toVersion(metadata.languageVersion.asInt())
updateJvmTarget(javaVersion)
Jvm.discovered( Jvm.discovered(
metadata.installationPath.asFile, metadata.installationPath.asFile,
null, null,
JavaVersion.toVersion(metadata.languageVersion.asInt()) javaVersion
) )
} }
) )
@@ -57,6 +57,7 @@ import org.jetbrains.kotlin.incremental.ChangedFiles
import org.jetbrains.kotlin.incremental.IncrementalCompilerRunner import org.jetbrains.kotlin.incremental.IncrementalCompilerRunner
import org.jetbrains.kotlin.library.impl.isKotlinLibrary import org.jetbrains.kotlin.library.impl.isKotlinLibrary
import org.jetbrains.kotlin.utils.JsLibraryUtils import org.jetbrains.kotlin.utils.JsLibraryUtils
import org.jetbrains.kotlin.utils.addToStdlib.cast
import java.io.File import java.io.File
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
import javax.inject.Inject import javax.inject.Inject
@@ -459,15 +460,19 @@ abstract class KotlinCompile @Inject constructor(
@get:Input @get:Input
abstract val useClasspathSnapshot: Property<Boolean> abstract val useClasspathSnapshot: Property<Boolean>
final override val kotlinJavaToolchainProvider: Provider<KotlinJavaToolchainProvider> = objects @get:Internal
internal val defaultKotlinJavaToolchain: Provider<KotlinJavaToolchainProvider> = objects
.propertyWithNewInstance( .propertyWithNewInstance(
project.gradle project.gradle,
{ this }
) )
final override val kotlinJavaToolchainProvider: Provider<KotlinJavaToolchain> = defaultKotlinJavaToolchain.cast()
@get:Internal @get:Internal
override val compilerRunner: Provider<GradleCompilerRunner> = objects.propertyWithConvention( override val compilerRunner: Provider<GradleCompilerRunner> = objects.propertyWithConvention(
// From Gradle 6.6 better to replace flatMap with provider.zip() // From Gradle 6.6 better to replace flatMap with provider.zip()
kotlinJavaToolchainProvider.flatMap { toolchain -> defaultKotlinJavaToolchain.flatMap { toolchain ->
objects.property(gradleCompileTaskProvider.map { objects.property(gradleCompileTaskProvider.map {
GradleCompilerRunner( GradleCompilerRunner(
it, it,
@@ -535,7 +540,7 @@ abstract class KotlinCompile @Inject constructor(
javaPackagePrefix, javaPackagePrefix,
args, args,
environment, environment,
kotlinJavaToolchainProvider.get().providedJvm.get().javaHome defaultKotlinJavaToolchain.get().providedJvm.get().javaHome
) )
} }