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)