[Gradle] Extract allInteropGroups from CInteropCommonizerTask

This information is needed to create consumable configurations for
Commonized Cinterop outputs. This way CInteropCommonizerTask is not
required to be created eagerly.

^KT-59596 Verification Pending
This commit is contained in:
Anton Lakotka
2023-08-14 17:02:34 +02:00
committed by Space Team
parent cbe11e8c9a
commit b2bef4ad41
4 changed files with 93 additions and 67 deletions
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.*
@@ -28,8 +27,7 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetType
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinWasmTargetPreset
import org.jetbrains.kotlin.gradle.targets.native.createFatFrameworks
import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask
import org.jetbrains.kotlin.gradle.targets.native.internal.createCommonizedCInteropApiElementsKlibArtifact
import org.jetbrains.kotlin.gradle.targets.native.internal.configureCInteropCommonizer
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.registerKotlinArtifactsExtension
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
@@ -75,7 +73,7 @@ class KotlinMultiplatformPlugin : Plugin<Project> {
// Ensure that the instance is created and configured during apply
project.kotlinIdeMultiplatformImport
project.locateOrRegisterIdeResolveDependenciesTask()
project.launch { project.createCommonizedCInteropApiElementsKlibArtifact() }
project.launch { project.configureCInteropCommonizer() }
project.addBuildListenerForXcode()
project.whenEvaluated { kotlinMultiplatformExtension.createFatFrameworks() }
}
@@ -20,13 +20,9 @@ import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.commonizer.*
import org.jetbrains.kotlin.compilerRunner.*
import org.jetbrains.kotlin.compilerRunner.GradleCliCommonizer
import org.jetbrains.kotlin.compilerRunner.KotlinNativeCommonizerToolRunner
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.withDependsOnClosure
import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter
@@ -95,6 +91,10 @@ internal abstract class CInteropCommonizerTask
override val outputDirectory: File get() = projectLayout.buildDirectory.get().asFile.resolve("classes/kotlin/commonizer")
internal fun outputDirectoriesOfCommonizerGroup(group: CInteropCommonizerGroup): Map<SharedCommonizerTarget, File> = group
.targets
.associateWith { target -> CommonizerOutputFileLayout.resolveCommonizedDirectory(outputDirectory, target) }
@get:Internal
internal val kotlinPluginVersion: Property<String> = objectFactory
.property<String>()
@@ -256,24 +256,7 @@ internal abstract class CInteropCommonizerTask
}
@get:Internal
internal val allInteropGroups: Future<Set<CInteropCommonizerGroup>> = project.lazyFuture {
val dependents = allDependents.await()
val allScopeSets = dependents.map { it.scopes }.toSet()
val rootScopeSets = allScopeSets.filter { scopeSet ->
allScopeSets.none { otherScopeSet -> otherScopeSet != scopeSet && otherScopeSet.containsAll(scopeSet) }
}
rootScopeSets.map { scopeSet ->
val dependentsForScopes = dependents.filter { dependent ->
scopeSet.containsAll(dependent.scopes)
}
CInteropCommonizerGroup(
targets = dependentsForScopes.map { it.target }.toSet(),
interops = dependentsForScopes.flatMap { it.interops }.toSet()
)
}.toSet()
}
internal val allInteropGroups: CompletableFuture<Set<CInteropCommonizerGroup>> = CompletableFuture()
@get:Nested
@Suppress("unused") // UP-TO-DATE check
@@ -290,26 +273,6 @@ internal abstract class CInteropCommonizerTask
return suitableGroups.firstOrNull()
}
private val allDependents: Future<Set<CInteropCommonizerDependent>> = project.lazyFuture {
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return@lazyFuture emptySet()
val fromSharedNativeCompilations = multiplatformExtension
.targets.flatMap { target -> target.compilations }
.filterIsInstance<KotlinSharedNativeCompilation>()
.mapNotNull { compilation -> CInteropCommonizerDependent.from(compilation) }
.toSet()
val fromSourceSets = multiplatformExtension.awaitSourceSets()
.mapNotNull { sourceSet -> CInteropCommonizerDependent.from(sourceSet) }
.toSet()
val fromSourceSetsAssociateCompilations = multiplatformExtension.awaitSourceSets()
.mapNotNull { sourceSet -> CInteropCommonizerDependent.fromAssociateCompilations(sourceSet) }
.toSet()
(fromSharedNativeCompilations + fromSourceSets + fromSourceSetsAssociateCompilations)
}
}
private fun CInteropProcess.toGist(): CInteropGist {
@@ -9,14 +9,11 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.*
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator.NativeArtifactFormat
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl
import org.jetbrains.kotlin.gradle.plugin.categoryByName
import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
import org.jetbrains.kotlin.gradle.plugin.launchInStage
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes
import org.jetbrains.kotlin.gradle.plugin.sources.internal
@@ -41,23 +38,6 @@ internal fun createCInteropApiElementsKlibArtifact(
}
}
internal suspend fun Project.createCommonizedCInteropApiElementsKlibArtifact() {
// TODO: Find a way to not materialize task. i.e. initialize only outputDirectory and allInteropGroups
val interopTask = project.commonizeCInteropTask()?.get() ?: return
for (commonizerGroup in interopTask.allInteropGroups.await()) {
for (sharedCommonizerTargets in commonizerGroup.targets) {
val configuration = locateOrCreateCommonizedCInteropApiElementsConfiguration(sharedCommonizerTargets)
val artifactPath = CommonizerOutputFileLayout.resolveCommonizedDirectory(interopTask.outputDirectory(commonizerGroup), sharedCommonizerTargets)
project.artifacts.add(configuration.name, artifactPath) { artifact ->
artifact.extension = "klib"
artifact.type = "klib"
artifact.classifier = "cinterop-" + sharedCommonizerTargets.dashedIdentityString()
artifact.builtBy(interopTask)
}
}
}
}
internal fun Project.locateOrCreateCInteropDependencyConfiguration(
compilation: KotlinNativeCompilation,
): Configuration {
@@ -162,7 +142,7 @@ private fun cInteropApiElementsConfigurationName(target: KotlinTarget): String {
/**
* Same as [org.jetbrains.kotlin.commonizer.identityString] but target segments separated with dash
*/
private fun SharedCommonizerTarget.dashedIdentityString() = targets.map { it.name }.sorted().joinToString("-")
internal fun SharedCommonizerTarget.dashedIdentityString() = targets.map { it.name }.sorted().joinToString("-")
private fun commonizedCInteropApiElementsConfigurationName(commonizerTarget: SharedCommonizerTarget): String {
return commonizerTarget.dashedIdentityString() + "CInteropApiElements"
}
@@ -0,0 +1,85 @@
/*
* 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.targets.native.internal
import org.gradle.api.Project
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
internal suspend fun Project.configureCInteropCommonizer() {
val interopTask = commonizeCInteropTask() ?: return
val cinteropGroups = getCInteropGroups()
configureCInteropCommonizerConsumableConfigurations(cinteropGroups, interopTask)
interopTask.configure {
it.allInteropGroups.complete(cinteropGroups)
}
}
private fun Project.configureCInteropCommonizerConsumableConfigurations(
cinteropGroups: Set<CInteropCommonizerGroup>,
interopTask: TaskProvider<CInteropCommonizerTask>,
) {
for (commonizerGroup in cinteropGroups) {
for (sharedCommonizerTargets in commonizerGroup.targets) {
val configuration = locateOrCreateCommonizedCInteropApiElementsConfiguration(sharedCommonizerTargets)
val commonizerTargetOutputDir = interopTask.map { task ->
task.outputDirectoriesOfCommonizerGroup(commonizerGroup)[sharedCommonizerTargets]
?: error("Can't find output of Shared Commonizer Target $sharedCommonizerTargets")
}
project.artifacts.add(configuration.name, commonizerTargetOutputDir) { artifact ->
artifact.extension = "klib"
artifact.type = "klib"
artifact.classifier = "cinterop-" + sharedCommonizerTargets.dashedIdentityString()
artifact.builtBy(interopTask)
}
}
}
}
private suspend fun Project.allCinteropCommonizerDependents(): Set<CInteropCommonizerDependent> {
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return emptySet()
val fromSharedNativeCompilations = multiplatformExtension
.targets.flatMap { target -> target.compilations }
.filterIsInstance<KotlinSharedNativeCompilation>()
.mapNotNull { compilation -> CInteropCommonizerDependent.from(compilation) }
.toSet()
val fromSourceSets = multiplatformExtension.awaitSourceSets()
.mapNotNull { sourceSet -> CInteropCommonizerDependent.from(sourceSet) }
.toSet()
val fromSourceSetsAssociateCompilations = multiplatformExtension.awaitSourceSets()
.mapNotNull { sourceSet -> CInteropCommonizerDependent.fromAssociateCompilations(sourceSet) }
.toSet()
return (fromSharedNativeCompilations + fromSourceSets + fromSourceSetsAssociateCompilations)
}
private suspend fun Project.getCInteropGroups(): Set<CInteropCommonizerGroup> {
val dependents = allCinteropCommonizerDependents()
val allScopeSets = dependents.map { it.scopes }.toSet()
val rootScopeSets = allScopeSets.filter { scopeSet ->
allScopeSets.none { otherScopeSet -> otherScopeSet != scopeSet && otherScopeSet.containsAll(scopeSet) }
}
val result = rootScopeSets.map { scopeSet ->
val dependentsForScopes = dependents.filter { dependent ->
scopeSet.containsAll(dependent.scopes)
}
CInteropCommonizerGroup(
targets = dependentsForScopes.map { it.target }.toSet(),
interops = dependentsForScopes.flatMap { it.interops }.toSet()
)
}.toSet()
return result
}