From 816e955c61b3e076888b61049ccd8f277f90339f Mon Sep 17 00:00:00 2001 From: Yahor Berdnikau Date: Mon, 26 Apr 2021 11:01:01 +0200 Subject: [PATCH] Introduce KotlinJavaToolchain compile tasks input. This task input provides a way to set different from current Gradle JDK and use it for Kotlin files compilation. By default it provides current Gradle JDK. Provided JDK major version is used as task input, so on providing different JDK user will see cache miss. All required interfaces are located inside api module. ^KT-45611 In Progress --- .../gradle/tasks/UsesKotlinJavaToolchain.kt | 51 +++++++ .../kotlin/gradle/KotlinJavaToolchainTest.kt | 144 ++++++++++++++++++ .../kotlin-java-toolchain/simple/build.gradle | 8 + .../simple/src/main/kotlin/main.kt | 3 + .../GradleCompilerEnvironment.kt | 7 +- .../GradleCompilerRunnerWithWorkers.kt | 5 +- .../GradleKotlinCompilerRunner.kt | 14 +- .../GradleKotlinCompilerWork.kt | 5 +- .../internal/kapt/KaptWithKotlincTask.kt | 35 +++-- .../js/ir/KotlinJsIrLinkWithWorkers.kt | 15 +- .../gradle/tasks/KotlinCompileCommon.kt | 2 +- .../tasks/KotlinJavaToolchainProvider.kt | 94 ++++++++++++ .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 78 ++++++---- 13 files changed, 401 insertions(+), 60 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/UsesKotlinJavaToolchain.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinJavaToolchainTest.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/build.gradle create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/src/main/kotlin/main.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinJavaToolchainProvider.kt diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/UsesKotlinJavaToolchain.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/UsesKotlinJavaToolchain.kt new file mode 100644 index 00000000000..d3e653f5c49 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/UsesKotlinJavaToolchain.kt @@ -0,0 +1,51 @@ +/* + * Copyright 2010-2021 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.provider.Provider +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import java.io.File + +interface UsesKotlinJavaToolchain { + @get:Nested + val kotlinJavaToolchainProvider: Provider + + @get:Internal + val kotlinJavaToolchain: KotlinJavaToolchain + get() = kotlinJavaToolchainProvider.get() +} + +interface KotlinJavaToolchain { + @get:Input + val javaVersion: Provider + + /** + * Set JDK to use for Kotlin compilation. + * + * Major JDK version is considered as compile task input. + * + * @param jdkHomeLocation path to JDK. + * *Note*: project build will fail on providing here JRE instead of JDK! + * @param jdkVersion provided JDK version + */ + fun setJdkHome( + jdkHomeLocation: File, + jdkVersion: JavaVersion + ) + + /** + * Set JDK to use for Kotlin compilation. + * + * @see [setJdkHome] + */ + fun setJdkHome( + jdkHomeLocation: String, + jdkVersion: JavaVersion + ) = setJdkHome(File(jdkHomeLocation), jdkVersion) +} 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 new file mode 100644 index 00000000000..4172a4764ef --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KotlinJavaToolchainTest.kt @@ -0,0 +1,144 @@ +/* + * Copyright 2010-2021 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 + +import org.gradle.internal.jvm.JavaInfo +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.junit.jupiter.api.DisplayName +import java.io.File + +class KotlinJavaToolchainTest : KGPBaseTest() { + + @GradleTest + @DisplayName("Should use by default same jvm as Gradle daemon") + internal fun byDefaultShouldUseGradleJDK(gradleVersion: GradleVersion) { + project( + projectName = "simple".fullProjectName, + gradleVersion = gradleVersion, + ) { + build("assemble") { + assertDaemonIsUsingJdk(getUserJdk().javaExecutableRealPath) + } + } + } + + @GradleTest + @DisplayName("Should use provided jdk location to compile Kotlin sources") + internal fun customJdkHomeLocation(gradleVersion: GradleVersion) { + project( + projectName = "simple".fullProjectName, + gradleVersion = gradleVersion, + ) { + useJdk9ToCompile() + + build("assemble") { + assertDaemonIsUsingJdk(getJdk9().javaExecutableRealPath) + } + } + } + + @GradleTest + @DisplayName("KotlinCompile task should use build cache when using provided JDK") + internal fun customJdkBuildCache(gradleVersion: GradleVersion) { + val buildCache = workingDir.resolve("custom-jdk-build-cache") + project( + projectName = "simple".fullProjectName, + gradleVersion = gradleVersion, + projectPathAdditionalSuffix = "1/cache-test", + buildOptions = defaultBuildOptions.copy(buildCacheEnabled = true) + ) { + enableLocalBuildCache(buildCache) + useJdk9ToCompile() + + build("assemble") + } + + project( + projectName = "simple".fullProjectName, + gradleVersion = gradleVersion, + projectPathAdditionalSuffix = "2/cache-test", + buildOptions = defaultBuildOptions.copy(buildCacheEnabled = true) + ) { + enableLocalBuildCache(buildCache) + useJdk9ToCompile() + + build("assemble") { + assertTasksFromCache(":compileKotlin") + } + } + } + + @GradleTest + @DisplayName("Kotlin compile task should not use build cache on using different JDK versions") + internal fun differentJdkBuildCacheMiss(gradleVersion: GradleVersion) { + val buildCache = workingDir.resolve("custom-jdk-build-cache") + project( + projectName = "simple".fullProjectName, + gradleVersion = gradleVersion, + projectPathAdditionalSuffix = "1/cache-test", + forceOutput = true, + buildOptions = defaultBuildOptions.copy(buildCacheEnabled = true) + ) { + enableLocalBuildCache(buildCache) + enableBuildCacheDebug() + useJdk9ToCompile() + build("assemble") + } + + project( + projectName = "simple".fullProjectName, + gradleVersion = gradleVersion, + projectPathAdditionalSuffix = "2/cache-test", + forceOutput = true, + buildOptions = defaultBuildOptions.copy(buildCacheEnabled = true) + ) { + enableLocalBuildCache(buildCache) + enableBuildCacheDebug() + build("assemble") { + assertTasksExecuted(":compileKotlin") + } + } + } + + private fun BuildResult.assertDaemonIsUsingJdk( + javaexecPath: String + ) = assertOutputContains("i: connected to the daemon. Daemon is using following 'java' executable to run itself: $javaexecPath") + + private fun getUserJdk(): JavaInfo = Jvm.forHome(File(System.getenv("JAVA_HOME"))) + private fun getJdk9(): JavaInfo = Jvm.forHome(File(System.getenv("JDK_9"))) + private val JavaInfo.javaExecutableRealPath + get() = javaExecutable + .toPath() + .toRealPath() + .toAbsolutePath() + .toString() + + private val String.fullProjectName get() = "kotlin-java-toolchain/$this" + + private fun TestProject.useJdk9ToCompile() { + // replace required for windows paths so Groovy will not complain about unexpected char '\' + val jdk9Path = getJdk9().javaHome.absolutePath.replace("\\", "\\\\") + //language=Groovy + rootBuildGradle.append( + """ + import org.gradle.api.JavaVersion + import org.jetbrains.kotlin.gradle.tasks.UsesKotlinJavaToolchain + + project.tasks + .withType(UsesKotlinJavaToolchain.class) + .configureEach { + it.kotlinJavaToolchain.setJdkHome( + "$jdk9Path", + JavaVersion.VERSION_1_9 + ) + } + """.trimIndent() + ) + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/build.gradle new file mode 100644 index 00000000000..e45c8e727de --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/build.gradle @@ -0,0 +1,8 @@ +plugins { + id("org.jetbrains.kotlin.jvm") +} + +repositories { + mavenLocal() + mavenCentral() +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/src/main/kotlin/main.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/src/main/kotlin/main.kt new file mode 100644 index 00000000000..63592fd783d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/kotlin-java-toolchain/simple/src/main/kotlin/main.kt @@ -0,0 +1,3 @@ +fun main() { + println("I know what you've done last summer...") +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt index 48cff2ae047..8b81bb84c0f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/GradleCompilerEnvironment.kt @@ -9,7 +9,6 @@ import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.report.ReportingSettings -import org.jetbrains.kotlin.gradle.tasks.findToolsJar import java.io.File internal class GradleCompilerEnvironment( @@ -21,9 +20,9 @@ internal class GradleCompilerEnvironment( val incrementalCompilationEnvironment: IncrementalCompilationEnvironment? = null, val kotlinScriptExtensions: Array = emptyArray() ) : CompilerEnvironment(Services.EMPTY, messageCollector, outputItemsCollector) { - val toolsJar: File? by lazy { findToolsJar() } - val compilerFullClasspath: List - get() = (compilerClasspath + toolsJar).filterNotNull() + fun compilerFullClasspath( + toolsJar: File? + ): List = if (toolsJar != null ) compilerClasspath + toolsJar else compilerClasspath.toList() } 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 c6c354d5116..705a5312a74 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 @@ -11,14 +11,17 @@ import org.gradle.workers.WorkParameters import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider +import java.io.File /** * Uses Gradle worker api to run kotlin compilation. */ internal class GradleCompilerRunnerWithWorkers( taskProvider: GradleCompileTaskProvider, + javaExecutable: File, + jdkToolsJar: File?, private val workerExecutor: WorkerExecutor -) : GradleCompilerRunner(taskProvider) { +) : GradleCompilerRunner(taskProvider, javaExecutable, 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 2f5ead2d8fa..c6c8b88e430 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 @@ -57,7 +57,11 @@ Using real taskProvider cause "field 'taskProvider' from type 'org.jetbrains.kot value 'fixed(class org.jetbrains.kotlin.gradle.tasks.KotlinCompile_Decorated, task ':compileKotlin')' is not assignable to 'org.gradle.api.tasks.TaskProvider'" exception */ -internal open class GradleCompilerRunner(protected val taskProvider: GradleCompileTaskProvider) { +internal open class GradleCompilerRunner( + protected val taskProvider: GradleCompileTaskProvider, + protected val javaExecutable: File, + protected val jdkToolsJar: File? +) { internal val pathProvider = taskProvider.path internal val loggerProvider = taskProvider.logger @@ -152,7 +156,7 @@ internal open class GradleCompilerRunner(protected val taskProvider: GradleCompi projectRootDirProvider, sessionDirProvider ), - compilerFullClasspath = environment.compilerFullClasspath, + compilerFullClasspath = environment.compilerFullClasspath(jdkToolsJar), compilerClassName = compilerClassName, compilerArgs = argsArray, isVerbose = compilerArgs.verbose, @@ -162,7 +166,8 @@ internal open class GradleCompilerRunner(protected val taskProvider: GradleCompi taskPath = pathProvider, reportingSettings = environment.reportingSettings, kotlinScriptExtensions = environment.kotlinScriptExtensions, - allWarningsAsErrors = compilerArgs.allWarningsAsErrors + allWarningsAsErrors = compilerArgs.allWarningsAsErrors, + javaExecutable = javaExecutable ) TaskLoggers.put(pathProvider, loggerProvider) runCompilerAsync(workArgs) @@ -179,10 +184,11 @@ internal open class GradleCompilerRunner(protected val taskProvider: GradleCompi clientIsAliveFlagFile: File, sessionIsAliveFlagFile: File, compilerFullClasspath: List, + javaExecutable: File, messageCollector: MessageCollector, isDebugEnabled: Boolean ): CompileServiceSession? { - val compilerId = CompilerId.makeCompilerId(compilerFullClasspath) + val compilerId = CompilerId.makeCompilerId(compilerFullClasspath, javaExecutable) 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 bd601c26920..34d247a543d 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 @@ -64,7 +64,8 @@ internal class GradleKotlinCompilerWorkArguments( val taskPath: String, val reportingSettings: ReportingSettings, val kotlinScriptExtensions: Array, - val allWarningsAsErrors: Boolean + val allWarningsAsErrors: Boolean, + val javaExecutable: File ) : Serializable { companion object { const val serialVersionUID: Long = 0 @@ -107,6 +108,7 @@ 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") } } @@ -176,6 +178,7 @@ 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/kapt/KaptWithKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt index f33bd97763c..549dddf5f86 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 @@ -5,14 +5,10 @@ package org.jetbrains.kotlin.gradle.internal -import com.intellij.openapi.util.SystemInfo -import org.gradle.api.GradleException import org.gradle.api.file.FileCollection import org.gradle.api.model.ObjectFactory -import org.gradle.api.tasks.Classpath -import org.gradle.api.tasks.InputFiles -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.TaskAction +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 import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment @@ -22,9 +18,8 @@ import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChan import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector -import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions -import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider -import org.jetbrains.kotlin.gradle.utils.getValue +import org.jetbrains.kotlin.gradle.tasks.* +import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.optionalProvider import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray import java.io.File @@ -32,7 +27,10 @@ import javax.inject.Inject abstract class KaptWithKotlincTask @Inject constructor( objectFactory: ObjectFactory -) : KaptTask(objectFactory), CompilerArgumentAwareWithInput { +) : KaptTask(objectFactory), + CompilerArgumentAwareWithInput, + UsesKotlinJavaToolchain { + @get:Internal internal val pluginOptions = CompilerPluginOptions() @@ -43,6 +41,9 @@ abstract class KaptWithKotlincTask @Inject constructor( @get:Internal val taskProvider = GradleCompileTaskProvider(this) + final override val kotlinJavaToolchainProvider: Provider = + objectFactory.propertyWithNewInstance() + override fun createCompilerArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments() private val compileKotlinArgumentsContributor by project.provider { @@ -103,11 +104,12 @@ abstract class KaptWithKotlincTask @Inject constructor( reportingSettings = reportingSettings, outputFiles = allOutputFiles() ) - if (environment.toolsJar == null && !isAtLeastJava9) { - throw GradleException("Could not find tools.jar in system classpath, which is required for kapt to work") - } - val compilerRunner = GradleCompilerRunner(taskProvider) + val compilerRunner = GradleCompilerRunner( + taskProvider, + kotlinJavaToolchainProvider.get().javaExecutable.get().asFile, + kotlinJavaToolchainProvider.get().jdkToolsJar.orNull + ) compilerRunner.runJvmCompilerAsync( sourcesToCompile = emptyList(), commonSources = emptyList(), @@ -117,7 +119,4 @@ abstract class KaptWithKotlincTask @Inject constructor( environment = environment ) } - - private val isAtLeastJava9: Boolean - get() = SystemInfo.isJavaVersionAtLeast(9, 0, 0) -} \ No newline at end of file +} 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 4668d1a8b55..3193ce7ad2c 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 @@ -10,6 +10,7 @@ import org.gradle.api.tasks.CacheableTask import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunnerWithWorkers import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider +import java.io.File import javax.inject.Inject @CacheableTask @@ -19,9 +20,13 @@ constructor( objectFactory: ObjectFactory, private val workerExecutor: WorkerExecutor ) : KotlinJsIrLink(objectFactory) { - override fun compilerRunner() = - GradleCompilerRunnerWithWorkers( - GradleCompileTaskProvider(this), - workerExecutor - ) + override fun compilerRunner( + javaExecutable: File, + jdkToolsJar: File? + ) = GradleCompilerRunnerWithWorkers( + GradleCompileTaskProvider(this), + javaExecutable, + jdkToolsJar, + workerExecutor + ) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index a9a8df75471..f4395d0bebe 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -113,7 +113,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile = objects + .property(Jvm.current()) + .chainedFinalizeValueOnRead() + + private val _javaVersion: Property = objects + .propertyWithConvention( + currentJvm.map { jvm -> + jvm.javaVersion + ?: throw GradleException( + "Kotlin could not get java version for the JDK installation: " + + jvm.javaHome?.let { "'$it' " }.orEmpty() + ) + } + ) + + final override val javaVersion: Provider + get() = _javaVersion + + @get:Internal + internal val javaExecutable: RegularFileProperty = objects + .fileProperty() + .convention( + currentJvm.flatMap { jvm -> + files.file( + objects.property( + jvm.javaExecutable + ?: throw GradleException( + "Kotlin could not find 'java' executable in the JDK installation: " + + jvm.javaHome?.let { "'$it' " }.orEmpty() + ) + ) + ) + } + ) + .chainedFinalizeValueOnRead() + + private val _jdkToolsJar = objects + .propertyWithConvention( + currentJvm.flatMap { jvm -> + objects.propertyWithConvention(jvm.toolsJar) + } + ) + .chainedFinalizeValueOnRead() + + @get:Internal + internal val jdkToolsJar: Provider = _jdkToolsJar + .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." + ) + } + + objects.propertyWithConvention(null) + }) + + override fun setJdkHome( + jdkHomeLocation: File, + jdkVersion: JavaVersion + ) { + val jvm = Jvm.forHome(jdkHomeLocation) as Jvm + + javaExecutable.set(jvm.javaExecutable) + _jdkToolsJar.set(jvm.toolsJar) + _javaVersion.set(jdkVersion) + } +} \ 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 8689b751d50..fc8b6bed148 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 @@ -44,7 +44,7 @@ import org.jetbrains.kotlin.gradle.logging.kotlinWarn import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib -import org.jetbrains.kotlin.gradle.utils.getValue +import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.isParentOf import org.jetbrains.kotlin.gradle.utils.pathsAsStringRelativeTo import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray @@ -165,7 +165,7 @@ public class GradleCompileTaskProvider { val buildModulesInfo: Provider /*= GradleCompilerRunner.buildModulesInfo(project.gradle)*/ } -abstract class AbstractKotlinCompile() : AbstractKotlinCompileTool() { +abstract class AbstractKotlinCompile : AbstractKotlinCompileTool(), UsesKotlinJavaToolchain { init { cacheOnlyIfEnabledForKotlin() @@ -318,11 +318,28 @@ abstract class AbstractKotlinCompile() : AbstractKo private val kotlinLogger by lazy { GradleKotlinLogger(logger) } - /** Keep lazy to avoid computing before all projects are evaluated. */ - @get:Internal - internal val compilerRunner by lazy { compilerRunner() } + final override val kotlinJavaToolchainProvider: Provider = + objects.propertyWithNewInstance() - internal open fun compilerRunner(): GradleCompilerRunner = GradleCompilerRunner(GradleCompileTaskProvider(this)) + @get:Internal + internal val compilerRunner: Provider = + objects.propertyWithConvention( + kotlinJavaToolchainProvider.map { + compilerRunner( + it.javaExecutable.get().asFile, + it.jdkToolsJar.orNull + ) + } + ) + + internal open fun compilerRunner( + javaExecutable: File, + jdkToolsJar: File? + ): GradleCompilerRunner = GradleCompilerRunner( + GradleCompileTaskProvider(this), + javaExecutable, + jdkToolsJar + ) private val systemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project.gradle) @@ -365,9 +382,6 @@ abstract class AbstractKotlinCompile() : AbstractKo private val projectDir = project.rootProject.projectDir private fun executeImpl(inputs: IncrementalTaskInputs) { - // Check that the JDK tools are available in Gradle (fail-fast, instead of a fail during the compiler run): - findToolsJar() - val sourceRoots = getSourceRoots() val allKotlinSources = sourceRoots.kotlinSourceFiles @@ -529,7 +543,7 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors) val outputItemCollector = OutputItemsCollectorImpl() - val compilerRunner = compilerRunner + val compilerRunner = compilerRunner.get() val icEnv = if (isIncrementalCompilationEnabled()) { logger.info(USING_JVM_INCREMENTAL_COMPILATION_MESSAGE) @@ -605,11 +619,15 @@ internal open class KotlinCompileWithWorkers @Inject constructor( private val workerExecutor: WorkerExecutor ) : KotlinCompile() { - override fun compilerRunner() = - GradleCompilerRunnerWithWorkers( - GradleCompileTaskProvider(this), - workerExecutor - ) + override fun compilerRunner( + javaExecutable: File, + jdkToolsJar: File? + ) = GradleCompilerRunnerWithWorkers( + GradleCompileTaskProvider(this), + javaExecutable, + jdkToolsJar, + workerExecutor + ) } @CacheableTask @@ -618,22 +636,30 @@ internal open class Kotlin2JsCompileWithWorkers @Inject constructor( private val workerExecutor: WorkerExecutor ) : Kotlin2JsCompile(objectFactory) { - override fun compilerRunner() = - GradleCompilerRunnerWithWorkers( - GradleCompileTaskProvider(this), - workerExecutor - ) + override fun compilerRunner( + javaExecutable: File, + jdkToolsJar: File? + ) = GradleCompilerRunnerWithWorkers( + GradleCompileTaskProvider(this), + javaExecutable, + jdkToolsJar, + workerExecutor + ) } @CacheableTask internal open class KotlinCompileCommonWithWorkers @Inject constructor( private val workerExecutor: WorkerExecutor ) : KotlinCompileCommon() { - override fun compilerRunner() = - GradleCompilerRunnerWithWorkers( - GradleCompileTaskProvider(this), - workerExecutor - ) + override fun compilerRunner( + javaExecutable: File, + jdkToolsJar: File? + ) = GradleCompilerRunnerWithWorkers( + GradleCompileTaskProvider(this), + javaExecutable, + jdkToolsJar, + workerExecutor + ) } @CacheableTask @@ -789,7 +815,7 @@ open class Kotlin2JsCompile @Inject constructor( val messageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors) val outputItemCollector = OutputItemsCollectorImpl() - val compilerRunner = compilerRunner + val compilerRunner = compilerRunner.get() val icEnv = if (isIncrementalCompilationEnabled()) { logger.info(USING_JS_INCREMENTAL_COMPILATION_MESSAGE)