[Gradle] Fallback to the highest supported Kotlin JVM target
If used toolchain JavaVersion is not yet supported by the current Kotlin compiler, we are now fallback to the highest supported JVM target version instead of failing the build. ^KT-58987 Fixed
This commit is contained in:
committed by
Space Team
parent
844ab4ee74
commit
0c0507c25f
+46
-14
@@ -10,6 +10,8 @@ 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.logging.Logger
|
||||
import org.gradle.api.logging.Logging
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.provider.Property
|
||||
@@ -33,6 +35,8 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
|
||||
jvmCompilerOptions: () -> KotlinJvmCompilerOptions?
|
||||
) : KotlinJavaToolchain {
|
||||
|
||||
private val logger = Logging.getLogger("KotlinJavaToolchain")
|
||||
|
||||
@get:Internal
|
||||
internal val gradleJvm: Provider<Jvm> = objects
|
||||
.property(Jvm.current())
|
||||
@@ -117,18 +121,21 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
|
||||
final override val jdk: KotlinJavaToolchain.JdkSetter = DefaultJdkSetter(
|
||||
providedJvm,
|
||||
objects,
|
||||
logger,
|
||||
jvmCompilerOptions
|
||||
)
|
||||
|
||||
final override val toolchain: KotlinJavaToolchain.JavaToolchainSetter =
|
||||
DefaultJavaToolchainSetter(
|
||||
providedJvm,
|
||||
logger,
|
||||
jvmCompilerOptions
|
||||
)
|
||||
|
||||
private class DefaultJdkSetter(
|
||||
private val providedJvm: Property<Jvm>,
|
||||
private val objects: ObjectFactory,
|
||||
private val logger: Logger,
|
||||
private val jvmCompilerOptions: () -> KotlinJvmCompilerOptions?
|
||||
) : KotlinJavaToolchain.JdkSetter {
|
||||
|
||||
@@ -150,13 +157,14 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
|
||||
)
|
||||
|
||||
jvmCompilerOptions()?.let {
|
||||
wireJvmTargetToJvm(it, providedJvm)
|
||||
wireJvmTargetToJvm(it, providedJvm, logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class DefaultJavaToolchainSetter(
|
||||
private val providedJvm: Property<Jvm>,
|
||||
private val logger: Logger,
|
||||
private val jvmCompilerOptions: () -> KotlinJvmCompilerOptions?
|
||||
) : KotlinJavaToolchain.JavaToolchainSetter {
|
||||
|
||||
@@ -172,7 +180,7 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
|
||||
providedJvm.set(javaLauncher.map(::mapToJvm))
|
||||
|
||||
jvmCompilerOptions()?.let {
|
||||
wireJvmTargetToJvm(it, providedJvm)
|
||||
wireJvmTargetToJvm(it, providedJvm, logger)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -181,28 +189,52 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
|
||||
|
||||
internal fun wireJvmTargetToJvm(
|
||||
jvmCompilerOptions: KotlinJvmCompilerOptions,
|
||||
toolchainJvm: Provider<Jvm>
|
||||
toolchainJvm: Provider<Jvm>,
|
||||
logger: Logger
|
||||
) {
|
||||
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)
|
||||
convertJavaVersionToJvmTarget(requireNotNull(jvm.javaVersion), logger)
|
||||
}.orElse(JvmTarget.DEFAULT)
|
||||
)
|
||||
}
|
||||
|
||||
private fun convertJavaVersionToJvmTarget(
|
||||
javaVersion: JavaVersion,
|
||||
logger: Logger
|
||||
): JvmTarget {
|
||||
// For Java 9 and Java 10 JavaVersion returns "1.9" or "1.10" accordingly
|
||||
// that is not accepted by the Kotlin compiler
|
||||
val normalizedVersion = when (javaVersion) {
|
||||
JavaVersion.VERSION_1_9 -> "9"
|
||||
JavaVersion.VERSION_1_10 -> "10"
|
||||
else -> javaVersion.toString()
|
||||
}
|
||||
|
||||
// Update to the latest JDK LTS once it is released and Kotlin has JVM target with this version
|
||||
return if (javaVersion > JavaVersion.VERSION_17) {
|
||||
try {
|
||||
JvmTarget.fromTarget(normalizedVersion)
|
||||
} catch (_: IllegalArgumentException) {
|
||||
val fallbackTarget = JvmTarget.values().last()
|
||||
logger.warn(
|
||||
"Kotlin does not yet support $normalizedVersion JDK target, falling back to Kotlin $fallbackTarget JVM target"
|
||||
)
|
||||
fallbackTarget
|
||||
}
|
||||
} else {
|
||||
JvmTarget.fromTarget(normalizedVersion)
|
||||
}
|
||||
}
|
||||
|
||||
private fun wireJvmTargetToToolchain(
|
||||
jvmCompilerOptions: KotlinJvmCompilerOptions,
|
||||
javaLauncher: Provider<JavaLauncher>
|
||||
javaLauncher: Provider<JavaLauncher>,
|
||||
logger: Logger
|
||||
): Unit = wireJvmTargetToJvm(
|
||||
jvmCompilerOptions,
|
||||
javaLauncher.map(::mapToJvm)
|
||||
javaLauncher.map(::mapToJvm),
|
||||
logger
|
||||
)
|
||||
|
||||
internal fun wireJvmTargetToToolchain(
|
||||
@@ -216,7 +248,7 @@ internal abstract class DefaultKotlinJavaToolchain @Inject constructor(
|
||||
.getByType(JavaPluginExtension::class.java)
|
||||
.toolchain
|
||||
val javaLauncher = toolchainService.launcherFor(toolchainSpec)
|
||||
wireJvmTargetToToolchain(compilerOptions, javaLauncher)
|
||||
wireJvmTargetToToolchain(compilerOptions, javaLauncher, project.logger)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+79
@@ -0,0 +1,79 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import org.gradle.api.JavaVersion
|
||||
import org.gradle.api.internal.provider.AbstractProperty.PropertyQueryException
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.ProviderFactory
|
||||
import org.gradle.internal.jvm.Jvm
|
||||
import org.gradle.testfixtures.ProjectBuilder
|
||||
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsDefault
|
||||
import org.jetbrains.kotlin.gradle.utils.newInstance
|
||||
import org.jetbrains.kotlin.testhelpers.StubLogger
|
||||
import org.junit.Before
|
||||
import org.junit.jupiter.api.assertThrows
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertTrue
|
||||
import kotlin.test.fail
|
||||
|
||||
class KotlinJavaToolchainJavaVersionConvertTest {
|
||||
private lateinit var objects: ObjectFactory
|
||||
private lateinit var providers: ProviderFactory
|
||||
private val logger = StubLogger("JavaToolchain")
|
||||
private val jvmCompilerOptions by lazy {
|
||||
objects.newInstance<KotlinJvmCompilerOptionsDefault>()
|
||||
}
|
||||
|
||||
@Before
|
||||
fun setUp() {
|
||||
val project = ProjectBuilder.builder().build()
|
||||
objects = project.objects
|
||||
providers = project.providers
|
||||
}
|
||||
|
||||
@Test
|
||||
fun wiresExpectedTarget() {
|
||||
val jvm = jvm(JavaVersion.VERSION_19)
|
||||
|
||||
DefaultKotlinJavaToolchain.wireJvmTargetToJvm(jvmCompilerOptions, providers.provider { jvm }, logger)
|
||||
|
||||
assertEquals(JvmTarget.JVM_19, jvmCompilerOptions.jvmTarget.orNull)
|
||||
assertTrue(logger.loggedWarnings.isEmpty())
|
||||
}
|
||||
|
||||
@Test
|
||||
fun throwsExceptionOnUnsupportedLowerTarget() {
|
||||
val jvm = jvm(JavaVersion.VERSION_1_7)
|
||||
|
||||
DefaultKotlinJavaToolchain.wireJvmTargetToJvm(jvmCompilerOptions, providers.provider { jvm }, logger)
|
||||
|
||||
val exception = assertThrows<PropertyQueryException> {
|
||||
jvmCompilerOptions.jvmTarget.orNull
|
||||
}
|
||||
assertTrue(exception.cause is IllegalArgumentException)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun fallbacksToHighestSupportedVersionWithLogMessage() {
|
||||
val jvm = jvm(JavaVersion.VERSION_24)
|
||||
|
||||
DefaultKotlinJavaToolchain.wireJvmTargetToJvm(jvmCompilerOptions, providers.provider { jvm }, logger)
|
||||
|
||||
val expectedKotlinTarget = JvmTarget.values().last()
|
||||
assertEquals(expectedKotlinTarget, jvmCompilerOptions.jvmTarget.orNull)
|
||||
assertTrue(logger.loggedWarnings.isNotEmpty())
|
||||
assertEquals(
|
||||
"Kotlin does not yet support ${jvm.javaVersion} JDK target, falling back to Kotlin $expectedKotlinTarget JVM target",
|
||||
logger.loggedWarnings.single()
|
||||
)
|
||||
}
|
||||
|
||||
private fun jvm(javaVersion: JavaVersion) = Jvm.discovered(File("/tmp"), "any", javaVersion)
|
||||
}
|
||||
+302
@@ -0,0 +1,302 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.testhelpers
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.api.logging.Logger
|
||||
import org.slf4j.Marker
|
||||
|
||||
class StubLogger(
|
||||
private val name: String
|
||||
) : Logger {
|
||||
override fun getName(): String = name
|
||||
|
||||
override fun isTraceEnabled(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isTraceEnabled(marker: Marker?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(format: String?, vararg arguments: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(marker: Marker?, msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(marker: Marker?, format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(marker: Marker?, format: String?, vararg argArray: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun trace(marker: Marker?, msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isDebugEnabled(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isDebugEnabled(marker: Marker?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(message: String?, vararg objects: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(marker: Marker?, msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(marker: Marker?, format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(marker: Marker?, format: String?, vararg arguments: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun debug(marker: Marker?, msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isInfoEnabled(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isInfoEnabled(marker: Marker?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(message: String?, vararg objects: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(marker: Marker?, msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(marker: Marker?, format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(marker: Marker?, format: String?, vararg arguments: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun info(marker: Marker?, msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
var isWarnEnabledFlag = true
|
||||
override fun isWarnEnabled(): Boolean = isWarnEnabledFlag
|
||||
override fun isWarnEnabled(marker: Marker?): Boolean = isWarnEnabledFlag
|
||||
|
||||
val loggedWarnings = mutableListOf<String>()
|
||||
|
||||
override fun warn(msg: String) {
|
||||
loggedWarnings.add(msg)
|
||||
}
|
||||
|
||||
override fun warn(format: String, arg: Any) {
|
||||
loggedWarnings.add(format.format(arg))
|
||||
}
|
||||
|
||||
override fun warn(format: String, vararg arguments: Any) {
|
||||
loggedWarnings.add(format.format(arguments))
|
||||
}
|
||||
|
||||
override fun warn(format: String, arg1: Any, arg2: Any) {
|
||||
loggedWarnings.add(format.format(arg1, arg2))
|
||||
}
|
||||
|
||||
override fun warn(msg: String, t: Throwable) {
|
||||
loggedWarnings.add(msg)
|
||||
}
|
||||
|
||||
override fun warn(marker: Marker, msg: String) {
|
||||
loggedWarnings.add(msg)
|
||||
}
|
||||
|
||||
override fun warn(marker: Marker, format: String, arg: Any) {
|
||||
loggedWarnings.add(format.format(arg))
|
||||
}
|
||||
|
||||
override fun warn(marker: Marker, format: String, arg1: Any, arg2: Any) {
|
||||
loggedWarnings.add(format.format(arg1, arg2))
|
||||
}
|
||||
|
||||
override fun warn(marker: Marker, format: String, vararg arguments: Any) {
|
||||
loggedWarnings.add(format.format(arguments))
|
||||
}
|
||||
|
||||
override fun warn(marker: Marker, msg: String, t: Throwable) {
|
||||
loggedWarnings.add(msg)
|
||||
}
|
||||
|
||||
override fun isErrorEnabled(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isErrorEnabled(marker: Marker?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(format: String?, vararg arguments: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(marker: Marker?, msg: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(marker: Marker?, format: String?, arg: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(marker: Marker?, format: String?, arg1: Any?, arg2: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(marker: Marker?, format: String?, vararg arguments: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun error(marker: Marker?, msg: String?, t: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isLifecycleEnabled(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun lifecycle(message: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun lifecycle(message: String?, vararg objects: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun lifecycle(message: String?, throwable: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isQuietEnabled(): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun quiet(message: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun quiet(message: String?, vararg objects: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun quiet(message: String?, throwable: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun isEnabled(level: LogLevel?): Boolean {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun log(level: LogLevel?, message: String?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun log(level: LogLevel?, message: String?, vararg objects: Any?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
|
||||
override fun log(level: LogLevel?, message: String?, throwable: Throwable?) {
|
||||
TODO("Not yet implemented")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user