[Gradle] Pass multiplatform structure to K2

^KT-56210 Verification Pending
This commit is contained in:
Sebastian Sellmair
2023-02-22 15:45:30 +01:00
committed by Space Team
parent 6c618ae5cc
commit 4f48cac601
9 changed files with 218 additions and 34 deletions
@@ -78,7 +78,6 @@ internal open class GradleCompilerRunner(
*/
fun runJvmCompilerAsync(
sourcesToCompile: List<File>,
commonSources: List<File>,
javaPackagePrefix: String?,
args: K2JVMCompilerArguments,
environment: GradleCompilerEnvironment,
@@ -86,7 +85,6 @@ internal open class GradleCompilerRunner(
taskOutputsBackup: TaskOutputsBackup?
): WorkQueue? {
args.freeArgs += sourcesToCompile.map { it.absolutePath }
args.commonSources = commonSources.map { it.absolutePath }.toTypedArray()
args.javaPackagePrefix = javaPackagePrefix
if (args.jdkHome == null && !args.noJdk) args.jdkHome = jdkHome.absolutePath
loggerProvider.kotlinInfo("Kotlin compilation 'jdkHome' argument: ${args.jdkHome}")
@@ -99,13 +97,11 @@ internal open class GradleCompilerRunner(
*/
fun runJsCompilerAsync(
kotlinSources: List<File>,
kotlinCommonSources: List<File>,
args: K2JSCompilerArguments,
environment: GradleCompilerEnvironment,
taskOutputsBackup: TaskOutputsBackup?
): WorkQueue? {
args.freeArgs += kotlinSources.map { it.absolutePath }
args.commonSources = kotlinCommonSources.map { it.absolutePath }.toTypedArray()
return runCompilerAsync(KotlinCompilerClass.JS, args, environment, taskOutputsBackup)
}
@@ -0,0 +1,13 @@
/*
* Copyright 2010-2023 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.dsl
import org.gradle.api.provider.Provider
internal val KotlinCommonCompilerOptions.usesK2: Provider<Boolean>
get() = this.languageVersion
.orElse(KotlinVersion.DEFAULT)
.map { version -> version >= KotlinVersion.KOTLIN_2_0 }
@@ -0,0 +1,32 @@
/*
* Copyright 2010-2023 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.plugin.mpp.compilationImpl
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory
import org.jetbrains.kotlin.gradle.tasks.K2Compile
import org.jetbrains.kotlin.gradle.tasks.K2MultiplatformStructure
internal object KotlinCompilationK2MultiplatformConfigurator : KotlinCompilationImplFactory.PreConfigure {
override fun configure(compilation: KotlinCompilationImpl) {
compilation.project.tasks.matching { it.name == compilation.compileKotlinTaskName }.configureEach { compileTask ->
if (compileTask !is K2Compile) return@configureEach
compileTask.multiplatformStructure.dependsOnEdges.set(compilation.project.provider {
compilation.allKotlinSourceSets.flatMap { sourceSet ->
sourceSet.dependsOn.map { dependsOn ->
K2MultiplatformStructure.DependsOnEdge(sourceSet.name, dependsOn.name)
}
}
})
compileTask.multiplatformStructure.fragments.set(compilation.project.provider {
compilation.allKotlinSourceSets.map { sourceSet ->
K2MultiplatformStructure.Fragment(sourceSet.name, sourceSet.kotlin.asFileTree)
}
})
}
}
}
@@ -42,7 +42,7 @@ internal class KotlinCompilationImplFactory(
DefaultProcessResourcesTaskNameFactory,
private val preConfigureAction: PreConfigure =
EmptyPreConfigure,
KotlinCompilationK2MultiplatformConfigurator,
private val postConfigureAction: PostConfigure =
DefaultKotlinCompilationPostConfigure
@@ -10,8 +10,11 @@ import org.gradle.api.file.FileTree
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerToolOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions
import org.jetbrains.kotlin.gradle.dsl.usesK2
import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.fragmentSourcesCompilerArgs
import org.jetbrains.kotlin.gradle.tasks.fragmentsCompilerArgs
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.project.model.LanguageSettings
@@ -46,7 +49,8 @@ internal fun buildKotlinNativeKlibCompilerArgs(
libraryVersion: String,
sharedCompilationData: SharedCompilationData?,
source: FileTree,
commonSourcesTree: FileTree
commonSourcesTree: FileTree,
k2MultiplatformCompilationData: K2MultiplatformStructure
): List<String> = mutableListOf<String>().apply {
addAll(buildKotlinNativeMainArgs(outFile, optimized, debuggable, target, CompilerOutputKind.LIBRARY, libraries))
@@ -76,10 +80,23 @@ internal fun buildKotlinNativeKlibCompilerArgs(
}
}
if (compilerOptions.usesK2.get()) {
/*
For now, we only pass multiplatform structure to K2 for platform compilations
Metadata compilations will compile against pre-compiled klibs from their dependsOn
*/
if (sharedCompilationData == null) {
add("-Xfragments=${k2MultiplatformCompilationData.fragmentsCompilerArgs.joinToString(",")}")
add("-Xfragment-sources=${k2MultiplatformCompilationData.fragmentSourcesCompilerArgs.joinToString(",")}")
add("-Xdepends-on=${k2MultiplatformCompilationData.dependsOnCompilerArgs.joinToString(",")}")
}
}
addAll(buildKotlinNativeCompileCommonArgs(languageSettings, compilerOptions, compilerPlugins))
addAll(source.map { it.absolutePath })
if (!commonSourcesTree.isEmpty) {
if (!compilerOptions.usesK2.get() && !commonSourcesTree.isEmpty) {
add("-Xcommon-sources=${commonSourcesTree.joinToString(separator = ",") { it.absolutePath }}")
}
}
@@ -37,7 +37,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmNativeCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.tcsOrNull
import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService
import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer
import org.jetbrains.kotlin.gradle.targets.native.tasks.*
@@ -314,6 +313,7 @@ internal constructor(
private val execOperations: ExecOperations
) : AbstractKotlinNativeCompile<KotlinCommonOptions, StubK2NativeCompilerArguments>(objectFactory),
KotlinCompile<KotlinCommonOptions>,
K2Compile,
KotlinCompilationTask<KotlinNativeCompilerOptions> {
@get:Input
@@ -354,6 +354,9 @@ internal constructor(
@get:Internal // these sources are normally a subset of `source` ones which are already tracked
val commonSources: ConfigurableFileCollection = project.files()
@get:Nested
override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance()
private val commonSourcesTree: FileTree
get() = commonSources.asFileTree
@@ -454,33 +457,33 @@ internal constructor(
return SharedCompilationData(manifestFile, isAllowCommonizer, refinesModule)
}
internal fun buildKotlinNativeKlibCompilerArgs(): List<String> = buildKotlinNativeKlibCompilerArgs(
outFile = outputFile.get(),
optimized = optimized,
debuggable = debuggable,
target = konanTarget,
libraries = libraries.files.filterKlibsPassedToCompiler(),
languageSettings = languageSettings,
compilerOptions = compilerOptions,
compilerPlugins = listOfNotNull(
compilerPluginClasspath?.let { CompilerPluginData(it, compilerPluginOptions) },
kotlinPluginData?.orNull?.let { CompilerPluginData(it.classpath, it.options) }
),
shortModuleName = shortModuleName,
friendModule = friendModule,
libraryVersion = artifactVersion,
sharedCompilationData = createSharedCompilationDataOrNull(),
source = sources.asFileTree,
commonSourcesTree = commonSourcesTree,
k2MultiplatformCompilationData = multiplatformStructure
)
@TaskAction
fun compile() {
val output = outputFile.get()
output.parentFile.mkdirs()
val plugins = listOfNotNull(
compilerPluginClasspath?.let { CompilerPluginData(it, compilerPluginOptions) },
kotlinPluginData?.orNull?.let { CompilerPluginData(it.classpath, it.options) }
)
val buildArgs = buildKotlinNativeKlibCompilerArgs(
output,
optimized,
debuggable,
konanTarget,
libraries.files.filterKlibsPassedToCompiler(),
languageSettings,
compilerOptions,
plugins,
shortModuleName,
friendModule,
artifactVersion,
createSharedCompilationDataOrNull(),
sources.asFileTree,
commonSourcesTree
)
val buildArgs = buildKotlinNativeKlibCompilerArgs()
KotlinNativeCompilerRunner(
settings = runnerSettings,
@@ -0,0 +1,25 @@
/*
* Copyright 2010-2023 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.tasks.Internal
import org.gradle.api.tasks.Nested
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
/**
* Analogous to [KotlinCompile] for K2
* This does not extend [KotlinCompile], since [KotlinCompile] carries an unwanted/conflicting
* type parameter `<out T : KotlinCommonOptions>`
*/
internal interface K2Compile : Task {
@get:Internal
val kotlinOptions: KotlinCommonOptions
@get:Nested
val multiplatformStructure: K2MultiplatformStructure
}
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2023 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.file.FileCollection
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.*
import org.gradle.work.Incremental
import org.gradle.work.NormalizeLineEndings
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
import org.jetbrains.kotlin.gradle.dsl.usesK2
@InternalKotlinGradlePluginApi
abstract class K2MultiplatformStructure {
@InternalKotlinGradlePluginApi
data class DependsOnEdge(
@Input
val fromFragmentName: String,
@Input
val toFragmentName: String
)
@InternalKotlinGradlePluginApi
data class Fragment(
@Input
val fragmentName: String,
@get:InputFiles
@get:IgnoreEmptyDirectories
@get:Incremental
@get:NormalizeLineEndings
@get:PathSensitive(PathSensitivity.RELATIVE)
val sources: FileCollection
)
@get:Nested
abstract val dependsOnEdges: SetProperty<DependsOnEdge>
@get:Nested
abstract val fragments: ListProperty<Fragment>
}
internal val K2MultiplatformStructure.fragmentsCompilerArgs: Array<String>
get() = fragments.get().map { it.fragmentName }.toSet().toTypedArray()
internal val K2MultiplatformStructure.fragmentSourcesCompilerArgs: Array<String>
get() = fragments.get().flatMap { sourceSet ->
sourceSet.sources.files.map { sourceFile -> "${sourceSet.fragmentName};${sourceFile.absolutePath}" }
}.toTypedArray()
internal val K2MultiplatformStructure.dependsOnCompilerArgs: Array<String>
get() = dependsOnEdges.get().map { edge ->
"${edge.fromFragmentName}:${edge.toFragmentName}"
}.toTypedArray()
internal fun CommonCompilerArguments.configureK2Multiplatform(multiplatformStructure: K2MultiplatformStructure) {
fragments = multiplatformStructure.fragmentsCompilerArgs
fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs
dependsOnDependencies = multiplatformStructure.dependsOnCompilerArgs
}
internal fun CommonCompilerArguments.configureMultiplatform(
options: KotlinCommonCompilerOptions,
k1CommonSources: FileCollection,
k2MultiplatformFragments: K2MultiplatformStructure
) {
if (options.usesK2.get()) {
configureK2Multiplatform(k2MultiplatformFragments)
} else {
commonSources = k1CommonSources.map { it.absolutePath }.toTypedArray()
}
}
@@ -526,6 +526,7 @@ abstract class KotlinCompile @Inject constructor(
workerExecutor: WorkerExecutor,
objectFactory: ObjectFactory
) : AbstractKotlinCompile<K2JVMCompilerArguments>(objectFactory, workerExecutor),
K2Compile,
@Suppress("TYPEALIAS_EXPANSION_DEPRECATION") KotlinJvmCompileDsl,
KotlinCompilationTask<KotlinJvmCompilerOptions>,
UsesKotlinJavaToolchain {
@@ -546,6 +547,9 @@ abstract class KotlinCompile @Inject constructor(
.property(kotlinOptions)
.chainedDisallowChanges()
@get:Nested
override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance()
/** A package prefix that is used for locating Java sources in a directory structure with non-full-depth packages.
*
* Example: a Java source file with `package com.example.my.package` is located in directory `src/main/java/my/package`.
@@ -689,6 +693,12 @@ abstract class KotlinCompile @Inject constructor(
)
)
args.configureMultiplatform(
compilerOptions,
k1CommonSources = commonSourceSet.asFileTree,
k2MultiplatformFragments = multiplatformStructure
)
if (reportingSettings().buildReportMode == BuildReportMode.VERBOSE) {
args.reportPerf = true
}
@@ -714,7 +724,7 @@ abstract class KotlinCompile @Inject constructor(
val scriptSources = scriptSources.asFileTree.files
val javaSources = javaSources.files
val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors,)
val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors)
val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector, kotlinPluginVersion = getKotlinPluginVersion(logger))
val outputItemCollector = OutputItemsCollectorImpl()
val compilerRunner = compilerRunner.get()
@@ -751,7 +761,6 @@ abstract class KotlinCompile @Inject constructor(
logger.info("Script file extensions: ${scriptExtensions.get().joinToString()}")
compilerRunner.runJvmCompilerAsync(
(kotlinSources + scriptSources + javaSources).toList(),
commonSourceSet.toList(),
javaPackagePrefix,
args,
environment,
@@ -913,7 +922,8 @@ abstract class Kotlin2JsCompile @Inject constructor(
) : AbstractKotlinCompile<K2JSCompilerArguments>(objectFactory, workerExecutor),
KotlinCompilationTask<KotlinJsCompilerOptions>,
UsesLibraryFilterCachingService,
KotlinJsCompile {
KotlinJsCompile,
K2Compile {
init {
incremental = true
@@ -977,6 +987,9 @@ abstract class Kotlin2JsCompile @Inject constructor(
@get:Internal
internal var executionTimeFreeCompilerArgs: List<String>? = null
@get:Nested
override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance()
override fun createCompilerArgs(): K2JSCompilerArguments =
K2JSCompilerArguments()
@@ -1003,6 +1016,13 @@ abstract class Kotlin2JsCompile @Inject constructor(
} else {
args.outputFile = outputFileProperty.get().absoluteFile.normalize().absolutePath
}
args.configureMultiplatform(
compilerOptions,
k1CommonSources = commonSourceSet.asFileTree,
k2MultiplatformFragments = multiplatformStructure
)
// Overriding freeArgs from compilerOptions with enhanced one + additional one set on execution phase
// containing additional arguments based on the js compilation configuration
val localExecutionTimeFreeCompilerArgs = executionTimeFreeCompilerArgs
@@ -1155,7 +1175,6 @@ abstract class Kotlin2JsCompile @Inject constructor(
processArgs(args)
compilerRunner.runJsCompilerAsync(
kotlinSources.toList(),
commonSourceSet.toList(),
args,
environment,
taskOutputsBackup