From 46d5df49911df897ea5783b0906412f335d53d24 Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Tue, 15 Jun 2021 12:04:57 +0200 Subject: [PATCH] Consider toolchain only as input for 'jdkHome' compilation option. This change will limit toolchain scope only to the JVM compilations, as Kotlin compiler itself does not care about JDK version it is running on and should always produce same output for non-JVM backends. For JVM backend there is one condition - 'jdkHome' should always point to the same JDK version. Few additional changes: - allow to set specific JDK location even on Gradle versions 6.7+ - Fix typo in deprecation message ^KT-45611 In Progress ^KT-43095 In Progress --- .../kotlin/gradle/KotlinJavaToolchainTest.kt | 56 ++-- .../GradleCompilerRunnerWithWorkers.kt | 3 +- .../GradleKotlinCompilerRunner.kt | 13 +- .../GradleKotlinCompilerWork.kt | 7 +- .../internal/CompilerArgumentsContributor.kt | 2 +- .../internal/kapt/KaptWithKotlincTask.kt | 7 +- .../internal/kapt/KaptWithoutKotlincTask.kt | 10 +- .../js/ir/KotlinJsIrLinkWithWorkers.kt | 26 +- .../tasks/KotlinJavaToolchainProvider.kt | 251 +++++++----------- .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 129 ++++----- .../kotlin/gradle/utils/providerApiUtils.kt | 4 + 11 files changed, 223 insertions(+), 285 deletions(-) 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) =