[Gradle] Make Kotlin Native tool runners GCC friendly

Remove project usage with either GradleExecutionContext or
associated Settings class.

Set of Setting classes are meant to be created upon configuration phase.
Therefore, they have to be easily serializable without heavy
payload. They also annotated for Input/Output checks.

^KT-43293
This commit is contained in:
Anton Lakotka
2022-06-27 12:45:05 +02:00
committed by Space
parent c6d32f7a60
commit 508235ce08
2 changed files with 100 additions and 29 deletions
@@ -34,6 +34,11 @@ abstract class KotlinToolRunner(
val logger: Logger,
) {
companion object {
/**
* Executing [KotlinToolRunner] during Gradle Configuration Phase is undesired behaviour.
* Currently only [KotlinNativeLibraryGenerationRunner] used in this way.
* It should be fixed as part of KT-51255
*/
@Deprecated(
"Building execution context from Project object isn't compatible with Gradle Configuration Cache",
ReplaceWith("fromTaskContext()"),
@@ -41,7 +46,7 @@ abstract class KotlinToolRunner(
)
fun fromProject(project: Project) = GradleExecutionContext(
filesProvider = project::files,
javaexec = project::javaexec,
javaexec = { spec -> project.javaexec(spec) }, // project::javaexec won't work due to different Classloaders
logger = project.logger
)
@@ -6,6 +6,10 @@
package org.jetbrains.kotlin.compilerRunner
import org.gradle.api.Project
import org.gradle.api.tasks.Classpath
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.InputFile
import org.gradle.api.tasks.Nested
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
@@ -18,6 +22,7 @@ import org.jetbrains.kotlin.konan.properties.resolvablePropertyString
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.DependencyDirectories
import java.io.File
import java.nio.file.Files
import java.util.*
@@ -45,10 +50,46 @@ internal fun Project.getKonanCacheKind(target: KonanTarget): NativeCacheKind {
}
}
private val Project.kotlinNativeCompilerJar: String
get() = if (nativeUseEmbeddableCompilerJar)
"$konanHome/konan/lib/kotlin-native-compiler-embeddable.jar"
else
"$konanHome/konan/lib/kotlin-native.jar"
internal abstract class KotlinNativeToolRunner(
protected val toolName: String,
project: Project
) : KotlinToolRunner(project) {
private val settings: Settings,
executionContext: GradleExecutionContext
) : KotlinToolRunner(executionContext) {
class Settings(
@get:Input
val konanVersion: CompilerVersion,
@get:Input
val konanHome: String,
@get:InputFile
val konanPropertiesFile: File,
@get:Input
val jvmArgs: List<String>,
classpathProvider: () -> Set<File>,
) {
@get:Classpath
val classpath by lazy(classpathProvider)
constructor(project: Project) : this(
konanVersion = project.konanVersion,
konanHome = project.konanHome,
konanPropertiesFile = project.file("${project.konanHome}/konan/konan.properties"),
jvmArgs = project.jvmArgs,
classpathProvider = {
project.files(
project.kotlinNativeCompilerJar,
"${project.konanHome}/konan/lib/trove4j.jar"
).files
}
)
}
final override val displayName get() = toolName
final override val mainClass get() = "org.jetbrains.kotlin.cli.utilities.MainKt"
@@ -65,29 +106,18 @@ internal abstract class KotlinNativeToolRunner(
final override val execSystemProperties by lazy {
// Still set konan.home for versions prior to 1.4-M3.
val konanHomeRequired = project.konanVersion.let {
val konanHomeRequired = settings.konanVersion.let {
!it.isAtLeast(1, 4, 0) ||
it.toString(showMeta = false, showBuild = false) in listOf("1.4-M1", "1.4-M2")
}
listOfNotNull(
if (konanHomeRequired) "konan.home" to project.konanHome else null,
if (konanHomeRequired) "konan.home" to settings.konanHome else null,
MessageRenderer.PROPERTY_KEY to MessageRenderer.GRADLE_STYLE.name
).toMap()
}
final override val classpath by lazy {
project.files(
project.kotlinNativeCompilerJar,
"${project.konanHome}/konan/lib/trove4j.jar"
).files
}
private val Project.kotlinNativeCompilerJar: String
get() = if (nativeUseEmbeddableCompilerJar)
"$konanHome/konan/lib/kotlin-native-compiler-embeddable.jar"
else
"$konanHome/konan/lib/kotlin-native.jar"
final override val classpath get() = settings.classpath
final override fun checkClasspath() =
check(classpath.isNotEmpty()) {
@@ -98,18 +128,23 @@ internal abstract class KotlinNativeToolRunner(
""".trimIndent()
}
data class IsolatedClassLoaderCacheKey(val classpath: Set<java.io.File>)
data class IsolatedClassLoaderCacheKey(val classpath: Set<File>)
// TODO: can't we use this for other implementations too?
final override val isolatedClassLoaderCacheKey get() = IsolatedClassLoaderCacheKey(classpath)
override fun transformArgs(args: List<String>) = listOf(toolName) + args
final override fun getCustomJvmArgs() = project.jvmArgs
final override fun getCustomJvmArgs() = settings.jvmArgs
}
/** A common ancestor for all runners that run the cinterop tool. */
internal abstract class AbstractKotlinNativeCInteropRunner(toolName: String, project: Project) : KotlinNativeToolRunner(toolName, project) {
internal abstract class AbstractKotlinNativeCInteropRunner(
toolName: String,
settings: Settings,
executionContext: GradleExecutionContext
) : KotlinNativeToolRunner(toolName, settings, executionContext) {
override val mustRunViaExec get() = true
override val execEnvironment by lazy {
@@ -126,7 +161,7 @@ internal abstract class AbstractKotlinNativeCInteropRunner(toolName: String, pro
if (HostManager.host == KonanTarget.MINGW_X64) {
// TODO: Read it from Platform properties when it is accessible.
val konanProperties = Properties().apply {
project.file("${project.konanHome}/konan/konan.properties").inputStream().use(::load)
settings.konanPropertiesFile.inputStream().use(::load)
}
konanProperties.resolvablePropertyString("llvmHome.mingw_x64")?.let { toolchainDir ->
@@ -140,25 +175,47 @@ internal abstract class AbstractKotlinNativeCInteropRunner(toolName: String, pro
}
/** Kotlin/Native C-interop tool runner */
internal class KotlinNativeCInteropRunner private constructor(project: Project) : AbstractKotlinNativeCInteropRunner("cinterop", project) {
internal class KotlinNativeCInteropRunner
private constructor(
private val settings: Settings,
gradleExecutionContext: GradleExecutionContext,
) : AbstractKotlinNativeCInteropRunner("cinterop", settings, gradleExecutionContext) {
interface ExecutionContext {
val project: Project
val runnerSettings: Settings
val gradleExecutionContext: GradleExecutionContext
fun runWithContext(action: () -> Unit)
}
companion object {
fun ExecutionContext.run(args: List<String>) {
val runner = KotlinNativeCInteropRunner(project)
val runner = KotlinNativeCInteropRunner(runnerSettings, gradleExecutionContext)
runWithContext { runner.run(args) }
}
}
}
/** Kotlin/Native compiler runner */
internal class KotlinNativeCompilerRunner(project: Project) : KotlinNativeToolRunner("konanc", project) {
private val useArgFile get() = project.disableKonanDaemon
internal class KotlinNativeCompilerRunner(
private val settings: Settings,
executionContext: GradleExecutionContext
) : KotlinNativeToolRunner("konanc", settings.parent, executionContext) {
class Settings(
@get:Nested
val parent: KotlinNativeToolRunner.Settings,
override val mustRunViaExec get() = project.disableKonanDaemon
@get:Input
val disableKonanDaemon: Boolean,
) {
constructor(project: Project) : this(
parent = KotlinNativeToolRunner.Settings(project),
disableKonanDaemon = project.disableKonanDaemon,
)
}
private val useArgFile get() = settings.disableKonanDaemon
override val mustRunViaExec get() = settings.disableKonanDaemon
override fun transformArgs(args: List<String>): List<String> {
if (!useArgFile) return super.transformArgs(args)
@@ -178,8 +235,17 @@ internal class KotlinNativeCompilerRunner(project: Project) : KotlinNativeToolRu
}
/** Platform libraries generation tool. Runs the cinterop tool under the hood. */
internal class KotlinNativeLibraryGenerationRunner(project: Project) :
AbstractKotlinNativeCInteropRunner("generatePlatformLibraries", project) {
internal class KotlinNativeLibraryGenerationRunner(
private val settings: Settings,
executionContext: GradleExecutionContext
) :
AbstractKotlinNativeCInteropRunner("generatePlatformLibraries", settings, executionContext) {
constructor(project: Project): this(
settings = Settings(project),
executionContext = GradleExecutionContext.fromProject(project)
)
// The library generator works for a long time so enabling C2 can improve performance.
override val disableC2: Boolean = false
}