Fix toolchain does not configure project level jvm target convention

Now JDK toolchain configures project level compiler options jvm target
convention and does not override convention for task.

For use case when toolchain is configured via task DSL jvm target
convention overrides project level convention.

^KT-57393 Fixed
This commit is contained in:
Yahor Berdnikau
2023-05-08 23:23:23 +02:00
committed by Space Team
parent aa5261395e
commit ac2d00916c
6 changed files with 150 additions and 30 deletions
@@ -12,6 +12,7 @@ import org.gradle.internal.jvm.Jvm
import org.gradle.testkit.runner.BuildResult
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.test.TestMetadata
import org.junit.jupiter.api.DisplayName
import java.io.File
import kotlin.io.path.appendText
@@ -702,6 +703,61 @@ class KotlinJavaToolchainTest : KGPBaseTest() {
}
}
@DisplayName("Toolchain should not override Jvm target configured in project level DSL")
@TestMetadata("kotlin-java-toolchain/simple")
@GradleTest
fun toolchainNotOverrideProjectJvmTarget(gradleVersion: GradleVersion) {
project(
projectName = "simple".fullProjectName,
gradleVersion = gradleVersion,
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
) {
buildGradle.appendText(
//language=groovy
"""
|
|kotlin.compilerOptions.jvmTarget.set(org.jetbrains.kotlin.gradle.dsl.JvmTarget.JVM_11)
|
""".trimMargin()
)
build(":compileKotlin") {
assertTasksExecuted(":compileKotlin")
assertCompilerArgument(":compileKotlin", "-jvm-target 11")
}
}
}
@AndroidGradlePluginTests
@DisplayName("Toolchain should not override Jvm taget configured via kotlinOptions in android project")
@AndroidTestVersions(minVersion = TestVersions.AGP.AGP_42)
@GradleAndroidTest
internal fun kotlinOptionsAndroidAndToolchainNotOverrideJvmTarget(
gradleVersion: GradleVersion,
agpVersion: String,
providedJdk: JdkVersions.ProvidedJdk
) {
project(
"android".fullProjectName,
gradleVersion,
buildOptions = defaultBuildOptions.copy(androidVersion = agpVersion, logLevel = LogLevel.DEBUG),
buildJdk = providedJdk.location
) {
buildGradle.appendText(
//language=groovy
"""
|
|android.kotlinOptions.jvmTarget = "11"
""".trimMargin()
)
build(":compileDebugKotlin") {
assertTasksExecuted(":compileDebugKotlin")
assertCompilerArgument(":compileDebugKotlin", "-jvm-target 11")
}
}
}
private fun BuildResult.assertJdkHomeIsUsingJdk(
javaexecPath: String
) = assertOutputContains("[KOTLIN] Kotlin compilation 'jdkHome' argument: $javaexecPath")
@@ -75,7 +75,7 @@ abstract class KotlinTopLevelExtension(internal val project: Project) : KotlinTo
override lateinit var coreLibrariesVersion: String
private val toolchainSupport = ToolchainSupport.createToolchain(project)
private val toolchainSupport = ToolchainSupport.createToolchain(project, this)
/**
* Configures [Java toolchain](https://docs.gradle.org/current/userguide/toolchains.html) both for Kotlin JVM and Java tasks.
@@ -14,6 +14,7 @@ import org.gradle.api.tasks.TaskContainer
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.jvm.toolchain.JavaToolchainSpec
import org.jetbrains.kotlin.gradle.tasks.DefaultKotlinJavaToolchain
import org.jetbrains.kotlin.gradle.tasks.KotlinJvmCompile
import org.jetbrains.kotlin.gradle.tasks.UsesKotlinJavaToolchain
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.newInstance
@@ -24,12 +25,14 @@ internal interface ToolchainSupport {
companion object {
internal fun createToolchain(
project: Project
project: Project,
kotlinExtension: KotlinTopLevelExtensionConfig
): ToolchainSupport {
return project.objects.newInstance<DefaultToolchainSupport>(
project.extensions,
project.tasks,
project.plugins
project.plugins,
kotlinExtension
)
}
}
@@ -38,7 +41,8 @@ internal interface ToolchainSupport {
internal abstract class DefaultToolchainSupport @Inject constructor(
private val extensions: ExtensionContainer,
private val tasks: TaskContainer,
private val plugins: PluginContainer
private val plugins: PluginContainer,
private val kotlinExtension: KotlinTopLevelExtensionConfig
) : ToolchainSupport {
private val toolchainSpec: JavaToolchainSpec
get() = extensions
@@ -60,12 +64,28 @@ internal abstract class DefaultToolchainSupport @Inject constructor(
val toolchainService = extensions.findByType(JavaToolchainService::class.java)
?: error("Gradle JavaToolchainService is not available!")
val javaLauncher = toolchainService.launcherFor(toolchainSpec)
tasks
.withType<UsesKotlinJavaToolchain>()
.configureEach {
(it.kotlinJavaToolchain.toolchain as DefaultKotlinJavaToolchain.DefaultJavaToolchainSetter)
.useAsConvention(javaLauncher)
}
if (kotlinExtension !is KotlinJvmProjectExtension &&
kotlinExtension !is KotlinAndroidProjectExtension
) {
tasks
.withType<UsesKotlinJavaToolchain>()
.configureEach { task ->
if (task is KotlinJvmCompile) {
DefaultKotlinJavaToolchain.wireJvmTargetToJvm(
task.compilerOptions,
(task.kotlinJavaToolchain as DefaultKotlinJavaToolchain).providedJvm
)
}
}
}
}
}
}
@@ -33,6 +33,10 @@ internal open class KotlinJvmPlugin(
) {
extensionCompilerOptions.verbose.convention(logger.isDebugEnabled)
extensionCompilerOptions.moduleName.convention(baseModuleName())
DefaultKotlinJavaToolchain.wireJvmTargetToToolchain(
extensionCompilerOptions,
project
)
compilationsContainer.configureEach {
val jvmCompilerOptions = it.compilerOptions.options as KotlinJvmCompilerOptions
KotlinJvmCompilerOptionsHelper.syncOptionsAsConvention(
@@ -7,15 +7,18 @@ package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.GradleException
import org.gradle.api.JavaVersion
import org.gradle.api.Project
import org.gradle.api.file.ProjectLayout
import org.gradle.api.file.RegularFileProperty
import org.gradle.api.model.ObjectFactory
import org.gradle.api.plugins.JavaPluginExtension
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.*
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.chainedFinalizeValueOnRead
import org.jetbrains.kotlin.gradle.utils.property
@@ -27,7 +30,7 @@ import javax.inject.Inject
internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
private val objects: ObjectFactory,
projectLayout: ProjectLayout,
private val kotlinCompileTaskProvider: () -> KotlinCompile?
jvmCompilerOptions: () -> KotlinJvmCompilerOptions?
) : KotlinJavaToolchain {
@get:Internal
@@ -60,27 +63,6 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
)
.chainedFinalizeValueOnRead()
init {
wireJvmTargetToToolchain()
}
private fun wireJvmTargetToToolchain() {
kotlinCompileTaskProvider()?.let { task ->
task.compilerOptions.jvmTarget.convention(
providedJvm.map { jvm ->
// For Java 9 and Java 10 JavaVersion returns "1.9" or "1.10" accordingly
// that is not accepted by Kotlin compiler
val normalizedVersion = when (jvm.javaVersion) {
JavaVersion.VERSION_1_9 -> "9"
JavaVersion.VERSION_1_10 -> "10"
else -> jvm.javaVersion.toString()
}
JvmTarget.fromTarget(normalizedVersion)
}.orElse(JvmTarget.DEFAULT)
)
}
}
@get:Internal
internal val javaExecutable: RegularFileProperty = objects
.fileProperty()
@@ -134,15 +116,20 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
final override val jdk: KotlinJavaToolchain.JdkSetter = DefaultJdkSetter(
providedJvm,
objects
objects,
jvmCompilerOptions
)
final override val toolchain: KotlinJavaToolchain.JavaToolchainSetter =
DefaultJavaToolchainSetter(providedJvm)
DefaultJavaToolchainSetter(
providedJvm,
jvmCompilerOptions
)
private class DefaultJdkSetter(
private val providedJvm: Property<Jvm>,
private val objects: ObjectFactory,
private val jvmCompilerOptions: () -> KotlinJvmCompilerOptions?
) : KotlinJavaToolchain.JdkSetter {
override fun use(
@@ -161,11 +148,16 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
Jvm.discovered(jdkHomeLocation, null, jdkVersion)
}
)
jvmCompilerOptions()?.let {
wireJvmTargetToJvm(it, providedJvm)
}
}
}
internal class DefaultJavaToolchainSetter(
private val providedJvm: Property<Jvm>
private val providedJvm: Property<Jvm>,
private val jvmCompilerOptions: () -> KotlinJvmCompilerOptions?
) : KotlinJavaToolchain.JavaToolchainSetter {
internal fun useAsConvention(
@@ -178,6 +170,54 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
javaLauncher: Provider<JavaLauncher>
) {
providedJvm.set(javaLauncher.map(::mapToJvm))
jvmCompilerOptions()?.let {
wireJvmTargetToJvm(it, providedJvm)
}
}
}
companion object {
internal fun wireJvmTargetToJvm(
jvmCompilerOptions: KotlinJvmCompilerOptions,
toolchainJvm: Provider<Jvm>
) {
jvmCompilerOptions.jvmTarget.convention(
toolchainJvm.map { jvm ->
// For Java 9 and Java 10 JavaVersion returns "1.9" or "1.10" accordingly
// that is not accepted by Kotlin compiler
val normalizedVersion = when (jvm.javaVersion) {
JavaVersion.VERSION_1_9 -> "9"
JavaVersion.VERSION_1_10 -> "10"
else -> jvm.javaVersion.toString()
}
JvmTarget.fromTarget(normalizedVersion)
}.orElse(JvmTarget.DEFAULT)
)
}
private fun wireJvmTargetToToolchain(
jvmCompilerOptions: KotlinJvmCompilerOptions,
javaLauncher: Provider<JavaLauncher>
): Unit = wireJvmTargetToJvm(
jvmCompilerOptions,
javaLauncher.map(::mapToJvm)
)
internal fun wireJvmTargetToToolchain(
compilerOptions: KotlinJvmCompilerOptions,
project: Project,
) {
project.plugins.withId("org.gradle.java-base") {
val toolchainService = project.extensions.findByType(JavaToolchainService::class.java)
?: error("Gradle JavaToolchainService is not available!")
val toolchainSpec = project.extensions
.getByType(JavaPluginExtension::class.java)
.toolchain
val javaLauncher = toolchainService.launcherFor(toolchainSpec)
wireJvmTargetToToolchain(compilerOptions, javaLauncher)
}
}
private fun mapToJvm(javaLauncher: JavaLauncher): Jvm {
@@ -144,7 +144,7 @@ abstract class KotlinCompile @Inject constructor(
@get:Internal
final override val defaultKotlinJavaToolchain: Provider<DefaultKotlinJavaToolchain> = objectFactory
.propertyWithNewInstance({ this })
.propertyWithNewInstance({ compilerOptions })
final override val kotlinJavaToolchainProvider: Provider<KotlinJavaToolchain> = defaultKotlinJavaToolchain.cast()