Add new ways to set Kotlin daemon JVM arguments.

Additionally to inheriting Gradle daemon arguments or configuring via
 Gradle daemon arguments system property, it is also possible now
 to configure arguments either using "kotlin.daemon.jvmargs" property
 or extension DSL.

Extension DSL overrides special gradle property arguments, which
overrides Gradle daemon arguments.

^KT-45747 Fixed
This commit is contained in:
Yahor Berdnikau
2021-06-27 21:07:26 +02:00
committed by Space
parent b98322c1b4
commit da1d49e622
13 changed files with 341 additions and 15 deletions
@@ -47,14 +47,32 @@ object KotlinCompilerRunnerUtils {
isDebugEnabled: Boolean,
daemonOptions: DaemonOptions = configureDaemonOptions(),
additionalJvmParams: Array<String> = arrayOf()
): CompileServiceSession? {
val daemonJVMOptions = configureDaemonJVMOptions(
): CompileServiceSession? = newDaemonConnection(
compilerId,
clientAliveFlagFile,
sessionAliveFlagFile,
messageCollector,
isDebugEnabled,
daemonOptions,
configureDaemonJVMOptions(
*additionalJvmParams,
inheritMemoryLimits = true,
inheritOtherJvmOptions = false,
inheritAdditionalProperties = true
)
)
@Synchronized
@JvmStatic
fun newDaemonConnection(
compilerId: CompilerId,
clientAliveFlagFile: File,
sessionAliveFlagFile: File,
messageCollector: MessageCollector,
isDebugEnabled: Boolean,
daemonOptions: DaemonOptions = configureDaemonOptions(),
daemonJVMOptions: DaemonJVMOptions
): CompileServiceSession? {
val daemonReportMessages = ArrayList<DaemonReportMessage>()
val daemonReportingTargets = DaemonReportingTargets(messages = daemonReportMessages)
@@ -0,0 +1,21 @@
/*
* 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.Task
import org.gradle.api.provider.ListProperty
import org.gradle.api.tasks.Internal
/**
* Task is using Kotlin daemon to run compilation.
*/
interface CompileUsingKotlinDaemon : Task {
/**
* Provides JVM arguments to Kotlin daemon, default is `null` if "kotlin.daemon.jvmargs" property is not set.
*/
@get:Internal
val kotlinDaemonJvmArguments: ListProperty<String>
}
@@ -0,0 +1,204 @@
/*
* 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.api.logging.LogLevel
import org.gradle.testkit.runner.BuildResult
import org.gradle.tooling.internal.consumer.ConnectorServices
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.Test
@DaemonsGradlePluginTests
@DisplayName("Kotlin daemon JVM args")
class KotlinDaemonJvmArgsTest : KGPBaseTest() {
override val defaultBuildOptions: BuildOptions
get() = super.defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
@AfterEach
internal fun tearDown() {
// Stops Gradle and Kotlin daemon, so new run will pick up new jvm arguments
ConnectorServices.reset()
}
@GradleTest
@DisplayName("Kotlin daemon by default should inherit Gradle daemon max jvm heap size")
internal fun shouldInheritGradleDaemonArgsByDefault(gradleVersion: GradleVersion) {
project("simpleProject", gradleVersion) {
gradleProperties.append(
"""
org.gradle.jvmargs = -Xmx758m
""".trimIndent()
)
build("assemble") {
assertKotlinDaemonJvmOptions(
listOf("-Xmx758m")
)
}
}
}
@DisplayName("Kotlin daemon should allow to define own jvm options via gradle daemon jvm args system property")
@GradleTest
internal fun shouldAllowToRedefineViaDGradleOption(gradleVersion: GradleVersion) {
project("simpleProject", gradleVersion) {
gradleProperties.append(
"""
org.gradle.jvmargs =-Xmx758m -Dkotlin.daemon.jvm.options=Xmx1g,Xms128m
""".trimIndent()
)
build("assemble") {
assertKotlinDaemonJvmOptions(
listOf("-Xmx1g", "--Xms128m")
)
}
}
}
@DisplayName("Jvm args defined in gradle.properties should override Gradle daemon jvm arguments inheritance")
@GradleTest
internal fun shouldUseArgumentsFromGradleProperties(gradleVersion: GradleVersion) {
project("simpleProject", gradleVersion) {
gradleProperties.append(
"""
org.gradle.jvmargs =-Xmx758m -Xms128m
kotlin.daemon.jvmargs = -Xmx486m -Xms256m
""".trimIndent()
)
build("assemble") {
assertKotlinDaemonJvmOptions(
listOf("-Xmx486m", "--Xms256m")
)
}
}
}
@DisplayName("Should use arguments from extension DSL")
@GradleTest
internal fun shouldUseDslArguments(gradleVersion: GradleVersion) {
project("simpleProject", gradleVersion) {
gradleProperties.append(
"""
org.gradle.jvmargs =-Xmx758m -Xms128m
""".trimIndent()
)
//language=Groovy
rootBuildGradle.append(
"""
kotlin {
kotlinDaemonJvmArgs = ["-Xmx486m", "-Xms256m", "-Duser.country=US"]
}
""".trimIndent()
)
build("assemble") {
assertKotlinDaemonJvmOptions(
listOf("-Xmx486m", "--Xms256m", "--Duser.country=US")
)
}
}
}
@DisplayName("Should allow to override global arguments for specific task")
@GradleTest
internal fun allowOverrideArgsForSpecificTask(gradleVersion: GradleVersion) {
project(
projectName = "simpleProject",
gradleVersion = gradleVersion
) {
gradleProperties.append(
"""
org.gradle.jvmargs = -Xmx758m -Xms128m
kotlin.daemon.jvmargs = -Xmx486m -Xms256m
""".trimIndent()
)
//language=Groovy
rootBuildGradle.append(
"""
import org.jetbrains.kotlin.gradle.tasks.CompileUsingKotlinDaemon
tasks
.matching {
it.name == "compileTestKotlin" && it instanceof CompileUsingKotlinDaemon
}
.configureEach {
kotlinDaemonJvmArguments.set(["-Xmx1g", "-Xms512m"])
}
""".trimIndent()
)
build("build") {
assertKotlinDaemonJvmOptions(
listOf("-Xmx486m", "--Xms256m")
)
assertKotlinDaemonJvmOptions(
listOf("-Xmx1g", "--Xms512m")
)
}
}
}
@DisplayName("Should inherit Gradle memory settings if it is not set in Kotlin daemon jvm args")
@GradleTest
fun inheritGradleMemorySettingsIfKotlinArgsNotContain(gradleVersion: GradleVersion) {
project("simpleProject", gradleVersion) {
gradleProperties.append(
"""
org.gradle.jvmargs =-Xmx758m -Xms128m
""".trimIndent()
)
//language=Groovy
rootBuildGradle.append(
"""
kotlin {
kotlinDaemonJvmArgs = ["-Duser.country=US"]
}
""".trimIndent()
)
build("assemble") {
assertKotlinDaemonJvmOptions(
listOf("-Xmx758m", "--Duser.country=US")
)
}
}
}
private fun BuildResult.assertKotlinDaemonJvmOptions(
expectedOptions: List<String>
) {
val jvmArgsCommonMessage = "Kotlin compile daemon JVM options: "
assertOutputContains(jvmArgsCommonMessage)
val argsRegex = "\\[.+?]".toRegex()
val argsStrings = output.lineSequence()
.filter { it.contains(jvmArgsCommonMessage) }
.map {
argsRegex.findAll(it).last().value.removePrefix("[").removeSuffix("]").split(", ")
}
val containsArgs = argsStrings.any {
it.containsAll(expectedOptions)
}
assert(containsArgs) {
printBuildOutput()
"${argsStrings.toList()} does not contain expected args: $expectedOptions"
}
}
}
@@ -20,9 +20,9 @@ import java.io.File
internal class GradleCompilerRunnerWithWorkers(
taskProvider: GradleCompileTaskProvider,
jdkToolsJar: File?,
kotlinDaemonJvmArgs: List<String>?,
private val workerExecutor: WorkerExecutor
) : GradleCompilerRunner(taskProvider, jdkToolsJar) {
) : GradleCompilerRunner(taskProvider, jdkToolsJar, kotlinDaemonJvmArgs) {
override fun runCompilerAsync(workArgs: GradleKotlinCompilerWorkArguments): WorkQueue {
loggerProvider.kotlinDebug { "Starting Kotlin compiler work from task '${pathProvider}'" }
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.cli.common.messages.MessageCollector
import org.jetbrains.kotlin.daemon.client.CompileServiceSession
import org.jetbrains.kotlin.daemon.common.CompilerId
import org.jetbrains.kotlin.daemon.common.configureDaemonJVMOptions
import org.jetbrains.kotlin.daemon.common.filterExtractProps
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
@@ -59,7 +61,8 @@ is not assignable to 'org.gradle.api.tasks.TaskProvider'" exception
*/
internal open class GradleCompilerRunner(
protected val taskProvider: GradleCompileTaskProvider,
protected val jdkToolsJar: File?
protected val jdkToolsJar: File?,
protected val kotlinDaemonJvmArgs: List<String>?
) {
internal val pathProvider = taskProvider.path.get()
@@ -185,7 +188,8 @@ internal open class GradleCompilerRunner(
taskPath = pathProvider,
reportingSettings = environment.reportingSettings,
kotlinScriptExtensions = environment.kotlinScriptExtensions,
allWarningsAsErrors = compilerArgs.allWarningsAsErrors
allWarningsAsErrors = compilerArgs.allWarningsAsErrors,
daemonJvmArgs = kotlinDaemonJvmArgs
)
TaskLoggers.put(pathProvider, loggerProvider)
return runCompilerAsync(workArgs)
@@ -204,15 +208,27 @@ internal open class GradleCompilerRunner(
sessionIsAliveFlagFile: File,
compilerFullClasspath: List<File>,
messageCollector: MessageCollector,
daemonJvmArgs: List<String>?,
isDebugEnabled: Boolean
): CompileServiceSession? {
val compilerId = CompilerId.makeCompilerId(compilerFullClasspath)
val additionalJvmParams = arrayListOf<String>()
val daemonJvmOptions = configureDaemonJVMOptions(
inheritMemoryLimits = true,
inheritOtherJvmOptions = false,
inheritAdditionalProperties = true
).also { opts ->
if (!daemonJvmArgs.isNullOrEmpty()) {
opts.jvmParams.addAll(
daemonJvmArgs.filterExtractProps(opts.mappers, "", opts.restMapper)
)
}
}
return KotlinCompilerRunnerUtils.newDaemonConnection(
compilerId, clientIsAliveFlagFile, sessionIsAliveFlagFile,
messageCollector = messageCollector,
isDebugEnabled = isDebugEnabled,
additionalJvmParams = additionalJvmParams.toTypedArray()
daemonJVMOptions = daemonJvmOptions
)
}
@@ -62,7 +62,8 @@ internal class GradleKotlinCompilerWorkArguments(
val taskPath: String,
val reportingSettings: ReportingSettings,
val kotlinScriptExtensions: Array<String>,
val allWarningsAsErrors: Boolean
val allWarningsAsErrors: Boolean,
val daemonJvmArgs: List<String>?
) : Serializable {
companion object {
const val serialVersionUID: Long = 0
@@ -105,6 +106,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<String> = emptyList()
private val daemonJvmArgs = config.daemonJvmArgs
private val log: KotlinLogger =
TaskLoggers.get(taskPath)?.let { GradleKotlinLogger(it).apply { debug("Using '$taskPath' logger") } }
@@ -175,7 +177,8 @@ internal class GradleKotlinCompilerWork @Inject constructor(
sessionFlagFile,
compilerFullClasspath,
daemonMessageCollector,
isDebugEnabled = isDebugEnabled
isDebugEnabled = isDebugEnabled,
daemonJvmArgs = daemonJvmArgs
)
} catch (e: Throwable) {
log.error("Caught an exception trying to connect to Kotlin Daemon:")
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.js.calculateJsCompilerType
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsTargetDsl
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrSingleTargetPreset
import org.jetbrains.kotlin.gradle.tasks.CompileUsingKotlinDaemon
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
@@ -72,6 +74,24 @@ open class KotlinTopLevelExtension (internal val project: Project) {
toolchainSupport.applyToolchain(action)
}
/**
* Configures Kotlin daemon JVM arguments for all tasks in this project.
*
* **Note**: In case other projects are using different JVM arguments, new instance of Kotlin daemon will be started.
*/
@get:JvmSynthetic
var kotlinDaemonJvmArgs: List<String>
@Deprecated("", level = DeprecationLevel.ERROR)
get() = throw UnsupportedOperationException()
set(value) {
project
.tasks
.withType<CompileUsingKotlinDaemon>()
.configureEach {
it.kotlinDaemonJvmArguments.set(value)
}
}
var explicitApi: ExplicitApiMode? = null
fun explicitApi() {
@@ -509,6 +509,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
KaptWithoutKotlincTask.Configurator(kotlinCompileTask).configure(kaptTask)
} else {
KaptWithKotlincTask.Configurator(kotlinCompileTask).configure(kaptTask as KaptWithKotlincTask)
PropertiesProvider(project).mapKotlinDaemonProperties(kaptTask)
}
kaptTask.stubsDir.set(getKaptStubsDir())
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.internal
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
@@ -30,7 +31,8 @@ import javax.inject.Inject
abstract class KaptWithKotlincTask @Inject constructor(
objectFactory: ObjectFactory
) : KaptTask(objectFactory),
CompilerArgumentAwareWithInput<K2JVMCompilerArguments> {
CompilerArgumentAwareWithInput<K2JVMCompilerArguments>,
CompileUsingKotlinDaemonWithNormalization {
class Configurator(kotlinCompileTask: KotlinCompile): KaptTask.Configurator<KaptWithKotlincTask>(kotlinCompileTask) {
override fun configure(task: KaptWithKotlincTask) {
@@ -58,6 +60,8 @@ abstract class KaptWithKotlincTask @Inject constructor(
override fun createCompilerArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments()
abstract override val kotlinDaemonJvmArguments: ListProperty<String>
@get:Internal
internal abstract val compileKotlinArgumentsContributor: Property<CompilerArgumentsContributor<K2JVMCompilerArguments>>
@@ -117,7 +121,8 @@ abstract class KaptWithKotlincTask @Inject constructor(
val compilerRunner = GradleCompilerRunner(
taskProvider.get(),
defaultKotlinJavaToolchain.get().currentJvmJdkToolsJar.orNull
defaultKotlinJavaToolchain.get().currentJvmJdkToolsJar.orNull,
normalizedKotlinDaemonJvmArguments.orNull
)
compilerRunner.runJvmCompilerAsync(
sourcesToCompile = emptyList(),
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.gradle.targets.js.dukat.ExternalsOutputFormat.Compan
import org.jetbrains.kotlin.gradle.targets.js.webpack.WebpackMajorVersion
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.CompileUsingKotlinDaemon
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
@@ -51,6 +52,12 @@ internal fun PropertiesProvider.mapKotlinTaskProperties(task: AbstractKotlinComp
}
}
internal fun PropertiesProvider.mapKotlinDaemonProperties(task: CompileUsingKotlinDaemon) {
kotlinDaemonJvmArgs?.let {
task.kotlinDaemonJvmArguments.set(it.split("\\s+".toRegex()))
}
}
internal class PropertiesProvider private constructor(private val project: Project) {
private val localProperties: Properties by lazy {
Properties().apply {
@@ -348,6 +355,9 @@ internal class PropertiesProvider private constructor(private val project: Proje
val jvmTargetValidationMode: JvmTargetValidationMode
get() = enumProperty("kotlin.jvm.target.validation.mode", JvmTargetValidationMode.WARNING)
val kotlinDaemonJvmArgs: String?
get() = property("kotlin.daemon.jvmargs")
private fun propertyWithDeprecatedVariant(propName: String, deprecatedPropName: String): String? {
val deprecatedProperty = property(deprecatedPropName)
if (deprecatedProperty != null) {
@@ -27,6 +27,7 @@ constructor(
GradleCompilerRunnerWithWorkers(
it,
null,
normalizedKotlinDaemonJvmArguments.orNull,
workerExecutor
) as GradleCompilerRunner
}
@@ -0,0 +1,18 @@
/*
* 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.provider.Provider
import org.gradle.api.tasks.Internal
internal interface CompileUsingKotlinDaemonWithNormalization : CompileUsingKotlinDaemon {
@get:Internal
val normalizedKotlinDaemonJvmArguments: Provider<List<String>>
get() = kotlinDaemonJvmArguments.map {
it.map { arg -> arg.trim().removePrefix("-") }
}
}
@@ -167,7 +167,8 @@ abstract class GradleCompileTaskProvider @Inject constructor(
)
}
abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotlinCompileTool<T>() {
abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotlinCompileTool<T>(),
CompileUsingKotlinDaemonWithNormalization {
open class Configurator<T : AbstractKotlinCompile<*>>(protected val compilation: KotlinCompilationData<*>) : TaskConfigurator<T> {
override fun configure(task: T) {
@@ -197,6 +198,8 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}")
).disallowChanges()
task.localStateDirectories.from(task.taskBuildDirectory).disallowChanges()
PropertiesProvider(task.project).mapKotlinDaemonProperties(task)
}
}
@@ -295,6 +298,8 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
abstract override val kotlinDaemonJvmArguments: ListProperty<String>
@get:Internal
protected val gradleCompileTaskProvider: Provider<GradleCompileTaskProvider> = objects
.property(
@@ -305,7 +310,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> : AbstractKotl
internal open val compilerRunner: Provider<GradleCompilerRunner> =
objects.propertyWithConvention(
gradleCompileTaskProvider.map {
GradleCompilerRunner(it, null)
GradleCompilerRunner(it, null, normalizedKotlinDaemonJvmArguments.orNull)
}
)
@@ -496,7 +501,8 @@ abstract class KotlinCompile @Inject constructor(
objects.property(gradleCompileTaskProvider.map {
GradleCompilerRunner(
it,
toolchain.currentJvmJdkToolsJar.orNull
toolchain.currentJvmJdkToolsJar.orNull,
normalizedKotlinDaemonJvmArguments.orNull
)
})
}
@@ -644,6 +650,7 @@ internal abstract class KotlinCompileWithWorkers @Inject constructor(
GradleCompilerRunnerWithWorkers(
it,
null,
normalizedKotlinDaemonJvmArguments.orNull,
workerExecutor
) as GradleCompilerRunner
}
@@ -662,6 +669,7 @@ internal abstract class Kotlin2JsCompileWithWorkers @Inject constructor(
GradleCompilerRunnerWithWorkers(
it,
null,
normalizedKotlinDaemonJvmArguments.orNull,
workerExecutor
) as GradleCompilerRunner
}
@@ -679,6 +687,7 @@ internal abstract class KotlinCompileCommonWithWorkers @Inject constructor(
GradleCompilerRunnerWithWorkers(
it,
null,
normalizedKotlinDaemonJvmArguments.orNull,
workerExecutor
) as GradleCompilerRunner
}