From bc65bb07751ce538d43dea5c6c1b76c071cba743 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Mon, 6 Dec 2021 11:40:58 +0400 Subject: [PATCH] Improve friend paths calculation in KPM: use actual resolution results Avoid adding compilation outputs of all variants to the friend paths, as this leads to false task dependencies, and also the real file system paths on the classpath may not point to the compilation outputs and will rather use the *Elements artifacts. --- .../mpp/pm20/DependencyGraphResolver.kt | 12 +++++ .../plugin/mpp/pm20/KotlinCompilationData.kt | 52 +++++++++++++++++-- 2 files changed, 59 insertions(+), 5 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt index 3055044dedb..8fa6ce903f4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt @@ -111,3 +111,15 @@ class GradleDependencyGraph( override val requestingModule: KotlinGradleModule, override val root: GradleDependencyGraphNode ) : DependencyGraphResolution.DependencyGraph(requestingModule, root) + +val GradleDependencyGraph.allGraphNodes: Iterable + get() = mutableSetOf().apply { + fun visit(node: GradleDependencyGraphNode) { + if (add(node)) + node.dependenciesByFragment.values.flatten().forEach(::visit) + } + visit(root) + } + +val GradleDependencyGraph.allDependencyModules: Iterable + get() = allGraphNodes.map { it.module }.filter { it != root.module } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationData.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationData.kt index 42e1805a8e0..8de54b13061 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationData.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationData.kt @@ -5,15 +5,18 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.pm20 -import org.gradle.api.Project +import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.file.FileCollection import org.gradle.api.file.SourceDirectorySet import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.pm20Extension import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.mpp.GradleModuleVariantResolver import org.jetbrains.kotlin.gradle.plugin.mpp.isMain import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.disambiguateName +import org.jetbrains.kotlin.gradle.utils.filesProvider import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import org.jetbrains.kotlin.project.model.VariantResolution import org.jetbrains.kotlin.project.model.refinesClosure interface KotlinVariantCompilationDataInternal : KotlinVariantCompilationData { @@ -27,11 +30,27 @@ interface KotlinVariantCompilationDataInternal : Kotlin get() = owner.refinesClosure.filterIsInstance().associate { it.disambiguateName("") to it.kotlinSourceRoots } override val friendPaths: Iterable - // TODO for now, all output classes of the module are considered friends, even those not on the classpath get() { - // FIXME support compiling against the artifact task outputs - // TODO note for Android: see the friend artifacts code in KotlinAndroidCompilation - return owner.containingModule.project.kpmModules.flatMap { it.variants.map { it.compilationOutputs.classesDirs } } + // TODO note for Android: see the friend artifacts code in KotlinAndroidCompilation; should we port it here? + return listOf( + project.filesProvider { + val friendVariants = resolveFriendVariants() + val friendModuleClassifiers = friendVariants.map { it.containingModule.moduleClassifier }.toSet() + val artifactView = owner.compileDependenciesConfiguration + .incoming.artifactView { view -> + view.componentFilter { id -> + // FIXME rewrite using the proper module resolution after those changes are merged + val asProject = id as? ProjectComponentIdentifier + asProject?.build?.isCurrentBuild == true && + asProject.projectPath == owner.project.path + } + }.artifacts + artifactView.filter { + // FIXME rewrite using the proper module resolution after those changes are merged + moduleClassifiersFromCapabilities(it.variant.capabilities).any { it in friendModuleClassifiers } + }.map { it.file } + } + ) } override val moduleName: String @@ -41,6 +60,29 @@ interface KotlinVariantCompilationDataInternal : Kotlin override val ownModuleName: String get() = owner.ownModuleName() + + private fun resolveFriendVariants(): Iterable { + val moduleResolver = GradleModuleDependencyResolver.getForCurrentBuild(project) + val variantResolver = GradleModuleVariantResolver.getForCurrentBuild(project) + val dependencyGraphResolver = GradleKotlinDependencyGraphResolver(moduleResolver) + + val friendModules = + ((dependencyGraphResolver.resolveDependencyGraph(owner.containingModule) as? GradleDependencyGraph) + ?: error("Failed to resolve dependencies of ${owner.containingModule}")) + .allDependencyModules + .filterIsInstance() + .filter { + // the module comes from the same Gradle project // todo: extend to other friends once supported + it.project == owner.containingModule.project && + // also, important to check that the owner variant really requests this module: + variantResolver.getChosenVariant(owner, it) is VariantResolution.VariantMatch + } + + val friendVariants = friendModules.map { + (variantResolver.getChosenVariant(owner, it) as VariantResolution.VariantMatch).chosenVariant + } + return friendVariants.filterIsInstance() + } } fun KotlinCompilationData<*>.isMainCompilationData(): Boolean = when (this) {