diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinJavaToolchainTest.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinJavaToolchainTest.kt index 62ee2dd1a77..7a70692e597 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinJavaToolchainTest.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinJavaToolchainTest.kt @@ -21,14 +21,15 @@ class KotlinJavaToolchainTest : KGPBaseTest() { @GradleTestVersions(additionalVersions = ["6.7.1"]) @GradleTest - @DisplayName("Should use by default same jvm as Gradle daemon") + @DisplayName("Should use by default same jvm as Gradle daemon for jdkHome") internal fun byDefaultShouldUseGradleJDK(gradleVersion: GradleVersion) { project( projectName = "simple".fullProjectName, - gradleVersion = gradleVersion, + gradleVersion = gradleVersion ) { - build("assemble") { - assertDaemonIsUsingJdk(getUserJdk().javaExecutableRealPath) + build("assemble", enableGradleDebug = true) { + assertOutputDoesNotContain("'kotlinOptions.jdkHome' is deprecated and will be ignored in Kotlin 1.7!") + assertJdkHomeIsUsingJdk(getUserJdk().javaHomeRealPath) } } } @@ -41,7 +42,7 @@ class KotlinJavaToolchainTest : KGPBaseTest() { projectName = "simple".fullProjectName, gradleVersion = gradleVersion ) { - //lang=Groovy + //language=Groovy rootBuildGradle.append( """ @@ -65,23 +66,11 @@ class KotlinJavaToolchainTest : KGPBaseTest() { useJdk9ToCompile() build("assemble") { - assertDaemonIsUsingJdk(getJdk9().javaExecutableRealPath) + assertJdkHomeIsUsingJdk(getJdk9().javaHomeRealPath) } } } - @Test - @DisplayName("Should fail the build on setting custom JDK when toolchain is available") - internal fun errorOnSettingJdkWhenToolchainIsAvailable() { - project( - projectName = "simple".fullProjectName, - gradleVersion = GradleVersion.version("6.7.1"), - ) { - useJdk9ToCompile() - buildAndFail("assemble") - } - } - @GradleTest @DisplayName("KotlinCompile task should use build cache when using provided JDK") internal fun customJdkBuildCache(gradleVersion: GradleVersion) { @@ -174,11 +163,11 @@ class KotlinJavaToolchainTest : KGPBaseTest() { ) build("assemble") { - assertDaemonIsUsingJdk( + assertJdkHomeIsUsingJdk( if (shouldUseToolchain(gradleVersion)) { getToolchainExecPathFromLogs() } else { - getJdk9().javaExecutableRealPath + getJdk9().javaHomeRealPath } ) @@ -281,7 +270,7 @@ class KotlinJavaToolchainTest : KGPBaseTest() { } } - @DisplayName("jdkHome Kotlin option should produce deprecation warning on Gradle builds") + @DisplayName("User provided jdkHome Kotlin option should produce deprecation warning on Gradle builds") @GradleTest internal fun jdkHomeIsDeprecated(gradleVersion: GradleVersion) { project( @@ -302,9 +291,8 @@ class KotlinJavaToolchainTest : KGPBaseTest() { """.trimIndent() ) build("assemble") { - assertDaemonIsUsingJdk(getUserJdk().javaExecutableRealPath) - assertOutputContains("'kotlinOptions.jdkHome' is deprecated and will ignored in Kotlin 1.6!") - assertOutputContains("-jdk-home ${getJdk9().javaHome.absolutePath}") + assertJdkHomeIsUsingJdk(getJdk9().javaHomeRealPath) + assertOutputContains("'kotlinOptions.jdkHome' is deprecated and will be ignored in Kotlin 1.7!") } } } @@ -320,7 +308,7 @@ class KotlinJavaToolchainTest : KGPBaseTest() { ) { useToolchainToCompile(11) build("assemble") { - assertDaemonIsUsingJdk(getToolchainExecPathFromLogs()) + assertJdkHomeIsUsingJdk(getToolchainExecPathFromLogs()) } } } @@ -336,21 +324,21 @@ class KotlinJavaToolchainTest : KGPBaseTest() { ) { useToolchainExtension(11) build("assemble") { - assertDaemonIsUsingJdk(getToolchainExecPathFromLogs()) + assertJdkHomeIsUsingJdk(getToolchainExecPathFromLogs()) } } } - private fun BuildResult.assertDaemonIsUsingJdk( + private fun BuildResult.assertJdkHomeIsUsingJdk( javaexecPath: String - ) = assertOutputContains("i: connected to the daemon. Daemon is using following 'java' executable to run itself: $javaexecPath") + ) = assertOutputContains("[KOTLIN] Kotlin compilation 'jdkHome' argument: $javaexecPath") private fun getUserJdk(): JavaInfo = Jvm.forHome(File(System.getenv("JAVA_HOME"))) private fun getJdk9(): JavaInfo = Jvm.forHome(File(System.getenv("JDK_9"))) // replace required for windows paths so Groovy will not complain about unexpected char '\' private fun getJdk9Path(): String = getJdk9().javaHome.absolutePath.replace("\\", "\\\\") - private val JavaInfo.javaExecutableRealPath - get() = javaExecutable + private val JavaInfo.javaHomeRealPath + get() = javaHome .toPath() .toRealPath() .toAbsolutePath() @@ -399,7 +387,7 @@ class KotlinJavaToolchainTest : KGPBaseTest() { } afterEvaluate { - logger.info("Toolchain exec path: ${'$'}{defaultLauncher.get().executablePath.asFile.absolutePath}") + logger.info("Toolchain jdk path: ${'$'}{defaultLauncher.get().metadata.installationPath.asFile.absolutePath}") } """.trimIndent() ) @@ -425,7 +413,7 @@ class KotlinJavaToolchainTest : KGPBaseTest() { def toolchain = project.extensions.getByType(JavaPluginExtension.class).toolchain def service = project.extensions.getByType(JavaToolchainService.class) def defaultLauncher = service.launcherFor(toolchain) - logger.info("Toolchain exec path: ${'$'}{defaultLauncher.get().executablePath.asFile.absolutePath}") + logger.info("Toolchain jdk path: ${'$'}{defaultLauncher.get().metadata.installationPath.asFile.absolutePath}") } """.trimIndent() ) @@ -435,6 +423,6 @@ class KotlinJavaToolchainTest : KGPBaseTest() { private fun BuildResult.getToolchainExecPathFromLogs() = output .lineSequence() - .first { it.startsWith("Toolchain exec path:") } - .substringAfter("Toolchain exec path: ") + .first { it.startsWith("Toolchain jdk path:") } + .substringAfter("Toolchain jdk path: ") } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerRunnerWithWorkers.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerRunnerWithWorkers.kt index 705a5312a74..25c1a7a3467 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerRunnerWithWorkers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerRunnerWithWorkers.kt @@ -18,10 +18,9 @@ import java.io.File */ internal class GradleCompilerRunnerWithWorkers( taskProvider: GradleCompileTaskProvider, - javaExecutable: File, jdkToolsJar: File?, private val workerExecutor: WorkerExecutor -) : GradleCompilerRunner(taskProvider, javaExecutable, jdkToolsJar) { +) : GradleCompilerRunner(taskProvider, jdkToolsJar) { override fun runCompilerAsync(workArgs: GradleKotlinCompilerWorkArguments) { loggerProvider.kotlinDebug { "Starting Kotlin compiler work from task '${pathProvider}'" } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index 2390b53d7d6..b16e3cbdd24 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.daemon.common.CompilerId import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.logging.kotlinDebug +import org.jetbrains.kotlin.gradle.logging.kotlinInfo import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService @@ -55,7 +56,6 @@ is not assignable to 'org.gradle.api.tasks.TaskProvider'" exception */ internal open class GradleCompilerRunner( protected val taskProvider: GradleCompileTaskProvider, - protected val javaExecutable: File, protected val jdkToolsJar: File? ) { @@ -78,12 +78,15 @@ internal open class GradleCompilerRunner( javaSourceRoots: Iterable, javaPackagePrefix: String?, args: K2JVMCompilerArguments, - environment: GradleCompilerEnvironment + environment: GradleCompilerEnvironment, + jdkHome: File ) { args.freeArgs += sourcesToCompile.map { it.absolutePath } args.commonSources = commonSources.map { it.absolutePath }.toTypedArray() args.javaSourceRoots = javaSourceRoots.map { it.absolutePath }.toTypedArray() args.javaPackagePrefix = javaPackagePrefix + if (args.jdkHome == null) args.jdkHome = jdkHome.absolutePath + loggerProvider.kotlinInfo("Kotlin compilation 'jdkHome' argument: ${args.jdkHome}") runCompilerAsync(KotlinCompilerClass.JVM, args, environment) } @@ -165,8 +168,7 @@ internal open class GradleCompilerRunner( taskPath = pathProvider, reportingSettings = environment.reportingSettings, kotlinScriptExtensions = environment.kotlinScriptExtensions, - allWarningsAsErrors = compilerArgs.allWarningsAsErrors, - javaExecutable = javaExecutable + allWarningsAsErrors = compilerArgs.allWarningsAsErrors ) TaskLoggers.put(pathProvider, loggerProvider) runCompilerAsync(workArgs) @@ -183,11 +185,10 @@ internal open class GradleCompilerRunner( clientIsAliveFlagFile: File, sessionIsAliveFlagFile: File, compilerFullClasspath: List, - javaExecutable: File, messageCollector: MessageCollector, isDebugEnabled: Boolean ): CompileServiceSession? { - val compilerId = CompilerId.makeCompilerId(compilerFullClasspath, javaExecutable) + val compilerId = CompilerId.makeCompilerId(compilerFullClasspath) val additionalJvmParams = arrayListOf() return KotlinCompilerRunnerUtils.newDaemonConnection( compilerId, clientIsAliveFlagFile, sessionIsAliveFlagFile, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt index 34d247a543d..cf4938ca1c4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerWork.kt @@ -5,9 +5,7 @@ package org.jetbrains.kotlin.compilerRunner -import org.gradle.api.Project import org.gradle.api.logging.Logger -import org.jetbrains.kotlin.build.ExecutionStrategy import org.jetbrains.kotlin.build.report.metrics.* import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.messages.MessageCollector @@ -64,8 +62,7 @@ internal class GradleKotlinCompilerWorkArguments( val taskPath: String, val reportingSettings: ReportingSettings, val kotlinScriptExtensions: Array, - val allWarningsAsErrors: Boolean, - val javaExecutable: File + val allWarningsAsErrors: Boolean ) : Serializable { companion object { const val serialVersionUID: Long = 0 @@ -108,7 +105,6 @@ internal class GradleKotlinCompilerWork @Inject constructor( private val buildDir = config.projectFiles.buildDir private val metrics = if (reportingSettings.reportMetrics) BuildMetricsReporterImpl() else DoNothingBuildMetricsReporter private var icLogLines: List = emptyList() - private val javaExecutable = config.javaExecutable private val log: KotlinLogger = TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } } @@ -178,7 +174,6 @@ internal class GradleKotlinCompilerWork @Inject constructor( clientIsAliveFlagFile, sessionFlagFile, compilerFullClasspath, - javaExecutable, daemonMessageCollector, isDebugEnabled = isDebugEnabled ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt index d233ddf35d0..f0e63f9f8fa 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt @@ -114,7 +114,7 @@ internal open class KotlinJvmCompilerArgumentsContributor( ?.run { logger.warn( """ - 'kotlinOptions.jdkHome' is deprecated and will ignored in Kotlin 1.6! + 'kotlinOptions.jdkHome' is deprecated and will be ignored in Kotlin 1.7! Consider using JavaToolchain on Gradle 6.7+: kotlin { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt index f508ff5e240..25a5ebf0696 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt @@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Property -import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments @@ -113,8 +112,7 @@ abstract class KaptWithKotlincTask @Inject constructor( val compilerRunner = GradleCompilerRunner( taskProvider, - kotlinJavaToolchainProvider.get().jdkProvider.javaExecutable.get().asFile, - kotlinJavaToolchainProvider.get().jdkProvider.jdkToolsJar.orNull + kotlinJavaToolchainProvider.get().currentJvmJdkToolsJar.orNull ) compilerRunner.runJvmCompilerAsync( sourcesToCompile = emptyList(), @@ -122,7 +120,8 @@ abstract class KaptWithKotlincTask @Inject constructor( javaSourceRoots = source.files, javaPackagePrefix = javaPackagePrefix.orNull, args = args, - environment = environment + environment = environment, + jdkHome = kotlinJavaToolchainProvider.get().providedJvm.get().javaHome ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt index e4728560cc8..e4c4de6385e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt @@ -158,7 +158,6 @@ abstract class KaptWithoutKotlincTask @Inject constructor( val isolationMode = getWorkerIsolationMode() logger.info("Using workers $isolationMode isolation mode to run kapt") val toolsJarURLSpec = kotlinJavaToolchainProvider.get() - .jdkProvider .jdkToolsJar.orNull?.toURI()?.toURL()?.toString().orEmpty() submitWork( @@ -170,12 +169,12 @@ abstract class KaptWithoutKotlincTask @Inject constructor( } private fun getWorkerIsolationMode(): IsolationMode { - val jdkProvider = kotlinJavaToolchainProvider.get().jdkProvider - val gradleJvm = jdkProvider.currentJvm.get() + val toolchainProvider = kotlinJavaToolchainProvider.get() + val gradleJvm = toolchainProvider.currentJvm.get() // 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 - val isRunningOnGradleJvm = gradleJvm.javaVersion == jdkProvider.javaVersion.get() && - gradleJvm.javaExecutable.absolutePath == jdkProvider.javaExecutable.get().asFile.absolutePath + val isRunningOnGradleJvm = gradleJvm.javaVersion == toolchainProvider.javaVersion.get() && + gradleJvm.javaExecutable.absolutePath == toolchainProvider.javaExecutable.get().asFile.absolutePath val isolationModeStr = getValue("kapt.workers.isolation")?.toLowerCase() return when { (isolationModeStr == null || isolationModeStr == "none") && isRunningOnGradleJvm -> IsolationMode.NONE @@ -201,7 +200,6 @@ abstract class KaptWithoutKotlincTask @Inject constructor( it.forkOptions.jvmArgs("-verbose:class") } it.forkOptions.executable = kotlinJavaToolchainProvider.get() - .jdkProvider .javaExecutable .asFile.get() .absolutePath diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLinkWithWorkers.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLinkWithWorkers.kt index c7b8066c72e..9c825dc0ed8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLinkWithWorkers.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLinkWithWorkers.kt @@ -6,11 +6,12 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Provider import org.gradle.api.tasks.CacheableTask import org.gradle.workers.WorkerExecutor +import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers -import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider -import java.io.File +import org.jetbrains.kotlin.gradle.utils.propertyWithConvention import javax.inject.Inject @CacheableTask @@ -18,15 +19,16 @@ internal abstract class KotlinJsIrLinkWithWorkers @Inject constructor( objectFactory: ObjectFactory, - private val workerExecutor: WorkerExecutor + workerExecutor: WorkerExecutor ) : KotlinJsIrLink(objectFactory) { - override fun compilerRunner( - javaExecutable: File, - jdkToolsJar: File? - ) = GradleCompilerRunnerWithWorkers( - gradleCompileTaskProvider, - javaExecutable, - jdkToolsJar, - workerExecutor - ) + override val compilerRunner: Provider = + objects.propertyWithConvention( + gradleCompileTaskProvider.map { + GradleCompilerRunnerWithWorkers( + it, + null, + workerExecutor + ) as GradleCompilerRunner + } + ) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJavaToolchainProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJavaToolchainProvider.kt index dbe8599cda7..8ae1a10ec3a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJavaToolchainProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJavaToolchainProvider.kt @@ -23,190 +23,141 @@ import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.propertyWithConvention import java.io.File import javax.inject.Inject +import kotlin.reflect.full.functions abstract class KotlinJavaToolchainProvider @Inject constructor( - objects: ObjectFactory, + private val objects: ObjectFactory, projectLayout: ProjectLayout, gradle: Gradle ) : KotlinJavaToolchain { - private val defaultJdkSetter by lazy(LazyThreadSafetyMode.NONE) { - DefaultJdkSetter( - objects, - projectLayout, - GradleVersion.version(gradle.gradleVersion) + private val currentGradleVersion = GradleVersion.version(gradle.gradleVersion) + + @get:Internal + internal val currentJvm: Provider = objects + .property(Jvm.current()) + .chainedFinalizeValueOnRead() + + @get:Internal + internal val providedJvm: Property = objects + .propertyWithConvention(currentJvm) + .chainedFinalizeValueOnRead() + + final override val javaVersion: Provider = objects + .property( + providedJvm.map { jvm -> + jvm.javaVersion + ?: throw GradleException( + "Kotlin could not get java version for the JDK installation: " + + jvm.javaHome?.let { "'$it' " }.orEmpty() + ) + } ) + .chainedFinalizeValueOnRead() + + @get:Internal + internal val javaExecutable: RegularFileProperty = objects + .fileProperty() + .value( + providedJvm.flatMap { jvm -> + projectLayout.file( + objects.property( + jvm.javaExecutable + ?: throw GradleException( + "Kotlin could not find 'java' executable in the JDK installation: " + + jvm.javaHome?.let { "'$it' " }.orEmpty() + ) + ) + ) + } + ) + .chainedFinalizeValueOnRead() + + private fun getToolsJarFromJvm(jvmProvider: Provider): Provider { + return objects + .propertyWithConvention( + jvmProvider.flatMap { jvm -> + objects.propertyWithConvention(jvm.toolsJar) + } + ) + .orElse(javaVersion.flatMap { + if (it < JavaVersion.VERSION_1_9) { + throw GradleException( + "Kotlin could not find the required JDK tools in the Java installation. " + + "Make sure Kotlin compilation is running on a JDK, not JRE." + ) + } else { + objects.propertyWithConvention(null) + } + }) } + @get:Internal + internal val jdkToolsJar: Provider = getToolsJarFromJvm(providedJvm) + + @get:Internal + internal val currentJvmJdkToolsJar: Provider = getToolsJarFromJvm(currentJvm) + + final override val jdk: KotlinJavaToolchain.JdkSetter = DefaultJdkSetter(providedJvm, currentGradleVersion) + private val defaultJavaToolchainSetter by lazy(LazyThreadSafetyMode.NONE) { - if (GradleVersion.version(gradle.gradleVersion) >= TOOLCHAIN_SUPPORTED_VERSION) { - DefaultJavaToolchainSetter(objects) + if (currentGradleVersion >= TOOLCHAIN_SUPPORTED_VERSION) { + DefaultJavaToolchainSetter(providedJvm) } else { null } } - @get:Internal - internal val jdkProvider: JdkProvider = - if (GradleVersion.version(gradle.gradleVersion) < TOOLCHAIN_SUPPORTED_VERSION) { - defaultJdkSetter - } else { - defaultJavaToolchainSetter!! - } - - final override val javaVersion: Provider - get() = jdkProvider.javaVersion - - final override val jdk: KotlinJavaToolchain.JdkSetter get() = defaultJdkSetter - final override val toolchain: KotlinJavaToolchain.JavaToolchainSetter get() = defaultJavaToolchainSetter ?: throw GradleException("Toolchain support is available from $TOOLCHAIN_SUPPORTED_VERSION") - internal interface JdkProvider { - val currentJvm: Property - val javaExecutable: RegularFileProperty - val javaVersion: Property - val jdkToolsJar: Provider - - companion object { - fun jdkToolsProperty( - objectsFactory: ObjectFactory, - currentJvm: Provider - ): Property = objectsFactory - .propertyWithConvention( - currentJvm.flatMap { jvm -> - objectsFactory.propertyWithConvention(jvm.toolsJar) - } - ) - - fun defaultJdkToolsJarProvider( - objectsFactory: ObjectFactory, - javaVersion: Property, - jdkTools: Property - ): Provider = jdkTools - .orElse(javaVersion.flatMap { - if (it < JavaVersion.VERSION_1_9) { - throw GradleException( - "Kotlin could not find the required JDK tools in the Java installation. " + - "Make sure Kotlin compilation is running on a JDK, not JRE." - ) - } else { - objectsFactory.propertyWithConvention(null) - } - }) - } - } - private class DefaultJdkSetter( - private val objectsFactory: ObjectFactory, - projectLayout: ProjectLayout, + private val providedJvm: Property, private val currentGradleVersion: GradleVersion - ) : KotlinJavaToolchain.JdkSetter, - JdkProvider { - - override val currentJvm: Property = objectsFactory - .property(Jvm.current()) - .chainedFinalizeValueOnRead() - - override val javaExecutable: RegularFileProperty = objectsFactory - .fileProperty() - .convention( - currentJvm.flatMap { jvm -> - projectLayout.file( - objectsFactory.property( - jvm.javaExecutable - ?: throw GradleException( - "Kotlin could not find 'java' executable in the JDK installation: " + - jvm.javaHome?.let { "'$it' " }.orEmpty() - ) - ) - ) - } - ) - .chainedFinalizeValueOnRead() - - override val javaVersion: Property = objectsFactory - .propertyWithConvention( - currentJvm.map { jvm -> - jvm.javaVersion - ?: throw GradleException( - "Kotlin could not get java version for the JDK installation: " + - jvm.javaHome?.let { "'$it' " }.orEmpty() - ) - } - ) - - private val _jdkToolsJar: Property = JdkProvider.jdkToolsProperty( - objectsFactory, - currentJvm - ) - override val jdkToolsJar: Provider = JdkProvider.defaultJdkToolsJarProvider( - objectsFactory, - javaVersion, - _jdkToolsJar - ) + ) : KotlinJavaToolchain.JdkSetter { override fun use( jdkHomeLocation: File, jdkVersion: JavaVersion ) { - if (currentGradleVersion >= TOOLCHAIN_SUPPORTED_VERSION) { - throw GradleException( - "Please use Java toolchains instead" - ) + require(jdkHomeLocation.isDirectory) { + "Supplied jdkHomeLocation must be a valid directory. You supplied: $jdkHomeLocation" + } + require(jdkHomeLocation.exists()) { + "Supplied jdkHomeLocation does not exists. You supplied: $jdkHomeLocation" } - val jvm = Jvm.forHome(jdkHomeLocation) as Jvm - - javaExecutable.set(jvm.javaExecutable) - _jdkToolsJar.set(jvm.toolsJar) - javaVersion.set(jdkVersion) + if (currentGradleVersion < GradleVersion.version("6.2.0")) { + // Before Gradle 6.2.0 'Jvm.discovered' does not have 'implementationJavaVersion' parameter + val jvm = Jvm::class.functions + .first { it.name == "discovered" } + .call(jdkHomeLocation, jdkVersion) as Jvm + providedJvm.set(jvm) + } else { + providedJvm.set( + Jvm.discovered(jdkHomeLocation, null, jdkVersion) + ) + } } } - private class DefaultJavaToolchainSetter( - objectsFactory: ObjectFactory - ) : KotlinJavaToolchain.JavaToolchainSetter, - JdkProvider { - - private val javaLauncher: Property = objectsFactory.property() - - override val currentJvm: Property = objectsFactory - .propertyWithConvention( - javaLauncher.map { - Jvm.forHome(it.metadata.installationPath.asFile) as Jvm - } - ) - - override val javaExecutable: RegularFileProperty = objectsFactory - .fileProperty() - .apply { - set(javaLauncher.map { it.executablePath }) - } - - override val javaVersion: Property = objectsFactory - .property( - javaLauncher.map { - JavaVersion.toVersion(it.metadata.languageVersion.asInt()) - } - ) - - private val _jdkToolsJar = JdkProvider.jdkToolsProperty( - objectsFactory, - currentJvm - ) - - override val jdkToolsJar: Provider = JdkProvider.defaultJdkToolsJarProvider( - objectsFactory, - javaVersion, - _jdkToolsJar - ) - + private inner class DefaultJavaToolchainSetter( + private val providedJvm: Property + ) : KotlinJavaToolchain.JavaToolchainSetter { override fun use( javaLauncher: Provider ) { - this.javaLauncher.set(javaLauncher) + providedJvm.set( + javaLauncher.map { + val metadata = javaLauncher.get().metadata + Jvm.discovered( + metadata.installationPath.asFile, + null, + JavaVersion.toVersion(metadata.languageVersion.asInt()) + ) + } + ) } } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index dc37cf1bd15..c206aa5231e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -138,7 +138,7 @@ class GradleCompileTaskProvider(task: Task) { } } -abstract class AbstractKotlinCompile : AbstractKotlinCompileTool(), UsesKotlinJavaToolchain { +abstract class AbstractKotlinCompile : AbstractKotlinCompileTool() { open class Configurator>(protected val compilation: KotlinCompilationData<*>) : TaskConfigurator { override fun configure(task: T) { @@ -256,40 +256,18 @@ abstract class AbstractKotlinCompile : AbstractKotl private val kotlinLogger by lazy { GradleKotlinLogger(logger) } - final override val kotlinJavaToolchainProvider: Provider = objects - .propertyWithNewInstance( - project.gradle - ) + @get:Internal + protected val gradleCompileTaskProvider: Provider = objects + .providerWithLazyConvention { GradleCompileTaskProvider(this) } @get:Internal - internal val compilerRunner: Provider = + internal open val compilerRunner: Provider = objects.propertyWithConvention( - kotlinJavaToolchainProvider.map { - compilerRunner( - it.jdkProvider.javaExecutable.get().asFile, - it.jdkProvider.jdkToolsJar.orNull - ) + gradleCompileTaskProvider.map { + GradleCompilerRunner(it, null) } ) - // Moved creation here to not violate Gradle configuration cache as [compilerRunner] method is called - // at execution time - // by lazy is added so properties of task extending this one are captured - required for incremental - // compilation - @get:Internal - protected val gradleCompileTaskProvider by lazy { - GradleCompileTaskProvider(this) - } - - internal open fun compilerRunner( - javaExecutable: File, - jdkToolsJar: File? - ): GradleCompilerRunner = GradleCompilerRunner( - gradleCompileTaskProvider, - javaExecutable, - jdkToolsJar - ) - private val systemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project.gradle) @TaskAction @@ -403,7 +381,9 @@ internal inline val T.thisTaskProvider: TaskProvider @CacheableTask abstract class KotlinCompile @Inject constructor( override val kotlinOptions: KotlinJvmOptions -) : AbstractKotlinCompile(), KotlinJvmCompile { +) : AbstractKotlinCompile(), + KotlinJvmCompile, + UsesKotlinJavaToolchain { class Configurator(kotlinCompilation: KotlinCompilationData<*>) : AbstractKotlinCompile.Configurator(kotlinCompilation) { } @@ -438,6 +418,24 @@ abstract class KotlinCompile @Inject constructor( @get:Input abstract val useClasspathSnapshot: Property + final override val kotlinJavaToolchainProvider: Provider = objects + .propertyWithNewInstance( + project.gradle + ) + + @get:Internal + override val compilerRunner: Provider = objects.propertyWithConvention( + // From Gradle 6.6 better to replace flatMap with provider.zip() + kotlinJavaToolchainProvider.flatMap { toolchain -> + objects.property(gradleCompileTaskProvider.map { + GradleCompilerRunner( + it, + toolchain.currentJvmJdkToolsJar.orNull + ) + }) + } + ) + init { incremental = true } @@ -495,7 +493,8 @@ abstract class KotlinCompile @Inject constructor( sourceRoots.javaSourceRoots, javaPackagePrefix, args, - environment + environment, + kotlinJavaToolchainProvider.get().providedJvm.get().javaHome ) } @@ -543,52 +542,53 @@ abstract class KotlinCompile @Inject constructor( @CacheableTask internal abstract class KotlinCompileWithWorkers @Inject constructor( kotlinOptions: KotlinJvmOptions, - private val workerExecutor: WorkerExecutor + workerExecutor: WorkerExecutor ) : KotlinCompile(kotlinOptions) { - - override fun compilerRunner( - javaExecutable: File, - jdkToolsJar: File? - ) = GradleCompilerRunnerWithWorkers( - gradleCompileTaskProvider, - javaExecutable, - jdkToolsJar, - workerExecutor - ) + override val compilerRunner: Provider = + objects.propertyWithConvention( + gradleCompileTaskProvider.map { + GradleCompilerRunnerWithWorkers( + it, + null, + workerExecutor + ) as GradleCompilerRunner + } + ) } @CacheableTask internal abstract class Kotlin2JsCompileWithWorkers @Inject constructor( kotlinOptions: KotlinJsOptions, objectFactory: ObjectFactory, - private val workerExecutor: WorkerExecutor + workerExecutor: WorkerExecutor ) : Kotlin2JsCompile(kotlinOptions, objectFactory) { - - override fun compilerRunner( - javaExecutable: File, - jdkToolsJar: File? - ) = GradleCompilerRunnerWithWorkers( - gradleCompileTaskProvider, - javaExecutable, - jdkToolsJar, - workerExecutor - ) + override val compilerRunner: Provider = + objects.propertyWithConvention( + gradleCompileTaskProvider.map { + GradleCompilerRunnerWithWorkers( + it, + null, + workerExecutor + ) as GradleCompilerRunner + } + ) } @CacheableTask internal abstract class KotlinCompileCommonWithWorkers @Inject constructor( kotlinOptions: KotlinMultiplatformCommonOptions, - private val workerExecutor: WorkerExecutor + workerExecutor: WorkerExecutor ) : KotlinCompileCommon(kotlinOptions) { - override fun compilerRunner( - javaExecutable: File, - jdkToolsJar: File? - ) = GradleCompilerRunnerWithWorkers( - gradleCompileTaskProvider, - javaExecutable, - jdkToolsJar, - workerExecutor - ) + override val compilerRunner: Provider = + objects.propertyWithConvention( + gradleCompileTaskProvider.map { + GradleCompilerRunnerWithWorkers( + it, + null, + workerExecutor + ) as GradleCompilerRunner + } + ) } @CacheableTask @@ -601,7 +601,8 @@ abstract class Kotlin2JsCompile @Inject constructor( incremental = true } - open class Configurator(compilation: KotlinCompilationData<*>) : AbstractKotlinCompile.Configurator(compilation) { + open class Configurator(compilation: KotlinCompilationData<*>) : + AbstractKotlinCompile.Configurator(compilation) { override fun configure(task: T) { super.configure(task) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt index 2c9030050bb..2c33284852b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt @@ -52,6 +52,10 @@ internal inline fun ObjectFactory.propertyWithConvention( conventionValue: T ) = property().convention(conventionValue) +internal inline fun ObjectFactory.providerWithLazyConvention( + noinline lazyConventionValue: () -> T +) = property(lazyConventionValue).map { it.invoke() } + internal inline fun ObjectFactory.newInstance() = newInstance(T::class.java) internal inline fun ObjectFactory.newInstance(vararg parameters: Any) =