From 3a5ffe479eb43f53db55b33280cbdca72bf23dc8 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Tue, 29 Sep 2020 18:45:24 +0300 Subject: [PATCH] General fixes for composite builds in HMPP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Register project structure metadata providers globally, so included builds can access it from the root build. * Rework some dependency management logic so that it doesn't assume that dependencies resolved to projects are safe to access – it is so only if the project is in the same build; also, in dependency handling, use proper keys which distinguish project with same ID in different builds. * Add a separate implementation of `MppDependencyMetadataExtractor` that reads the project structure metadata from the mentioned global storage (as we can't read it from artifacts – those are not yet build at the project configuration phase) but when it comes to artifacts processing, takes real artifacts rather than introspect the project structure. * Register the Kotlin/Native host-specific metadata artifact configurations as consumable, so that a consumer from a different build can properly resolve a dependency to such a configuration and get the artifact. --- .../mpp/GranularMetadataTransformation.kt | 99 +++++++++++++------ .../plugin/mpp/KotlinMultiplatformPlugin.kt | 10 ++ .../mpp/KotlinProjectStructureMetadata.kt | 29 +++++- .../kotlin/gradle/plugin/mpp/ModuleIds.kt | 8 +- .../plugin/mpp/ResolvedMppVariantsProvider.kt | 29 +++--- .../mpp/TransformKotlinGranularMetadata.kt | 4 +- .../plugin/sources/DefaultKotlinSourceSet.kt | 1 + .../KotlinMetadataTargetConfigurator.kt | 14 ++- .../targets/native/KotlinNativeTarget.kt | 32 ++---- .../native/KotlinNativeTargetConfigurator.kt | 23 ++++- .../gradle/tasks/KotlinCompileCommon.kt | 2 +- 11 files changed, 168 insertions(+), 83 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index b66861d9cbd..d34557a0e11 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -6,8 +6,9 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project -import org.gradle.api.artifacts.* -import org.gradle.api.artifacts.component.* +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.Dependency +import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.result.ResolvedComponentResult import org.gradle.api.artifacts.result.ResolvedDependencyResult import org.gradle.api.attributes.Attribute @@ -164,15 +165,12 @@ internal class GranularMetadataTransformation( while (resolvedDependencyQueue.isNotEmpty()) { val (resolvedDependency: ResolvedComponentResult, parent: ResolvedComponentResult?) = resolvedDependencyQueue.poll() - val resolvedToProject: Project? = (resolvedDependency.id as? ProjectComponentIdentifier)?.projectPath?.let(project::project) - visitedDependencies.add(resolvedDependency) val dependencyResult = processDependency( resolvedDependency, parentResolutions[ModuleIds.fromComponent(project, resolvedDependency)].orEmpty(), - parent, - resolvedToProject + parent ) result.add(dependencyResult) @@ -196,7 +194,9 @@ internal class GranularMetadataTransformation( result.add( MetadataDependencyResolution.ExcludeAsUnrequested( resolvedDependency.selected, - (resolvedDependency.selected.id as? ProjectComponentIdentifier)?.let { project.project(it.projectPath) } + (resolvedDependency.selected.id as? ProjectComponentIdentifier) + ?.takeIf { it.build.isCurrentBuild() } + ?.let { project.project(it.projectPath) } ) ) } @@ -222,23 +222,28 @@ internal class GranularMetadataTransformation( private fun processDependency( module: ResolvedComponentResult, parentResolutionsForModule: Iterable, - parent: ResolvedComponentResult?, - resolvedToProject: Project? + parent: ResolvedComponentResult? ): MetadataDependencyResolution { val resolvedMppVariantsProvider = ResolvedMppVariantsProvider.get(project) - - val mppDependencyMetadataExtractor = if (resolvedToProject != null) { - ProjectMppDependencyMetadataExtractor(project, module, resolvedToProject) - } else { - val metadataArtifact = resolvedMppVariantsProvider.getPlatformArtifactByPlatformModule( - ModuleIds.fromComponent(project, module), - configurationToResolve - ) - if (metadataArtifact != null) { - JarArtifactMppDependencyMetadataExtractor(project, module, metadataArtifact) - } else null + val metadataArtifact = resolvedMppVariantsProvider.getPlatformArtifactByPlatformModule( + ModuleIds.fromComponent(project, module), + configurationToResolve + ) + val moduleId = module.id + val mppDependencyMetadataExtractor: MppDependencyMetadataExtractor? = when { + moduleId is ProjectComponentIdentifier -> when { + moduleId.build.isCurrentBuild -> + ProjectMppDependencyMetadataExtractor(project, module, project.project(moduleId.projectPath)) + metadataArtifact != null -> + IncludedBuildMetadataExtractor(project, module, metadataArtifact) + else -> null + } + metadataArtifact != null -> JarArtifactMppDependencyMetadataExtractor(project, module, metadataArtifact) + else -> null } + val resolvedToProject: Project? = (mppDependencyMetadataExtractor as? ProjectMppDependencyMetadataExtractor)?.dependencyProject + val projectStructureMetadata = mppDependencyMetadataExtractor?.getProjectStructureMetadata() ?: return MetadataDependencyResolution.KeepOriginalDependency(module, resolvedToProject) @@ -318,7 +323,7 @@ private abstract class MppDependencyMetadataExtractor(val project: Project, val private class ProjectMppDependencyMetadataExtractor( project: Project, dependency: ResolvedComponentResult, - private val dependencyProject: Project + val dependencyProject: Project ) : MppDependencyMetadataExtractor(project, dependency) { override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? = buildKotlinProjectStructureMetadata(dependencyProject) @@ -337,7 +342,26 @@ private class ProjectMppDependencyMetadataExtractor( } } -private class JarArtifactMppDependencyMetadataExtractor( +private class IncludedBuildMetadataExtractor( + project: Project, + dependency: ResolvedComponentResult, + primaryArtifact: File +) : JarArtifactMppDependencyMetadataExtractor(project, dependency, primaryArtifact) { + + private val id: ProjectComponentIdentifier + + init { + val id = dependency.id + require(id is ProjectComponentIdentifier) { "dependency should resolve to a project" } + require(!(id as ProjectComponentIdentifier).build.isCurrentBuild) { "should be a project from an included build" } + this.id = id + } + + override fun getProjectStructureMetadata(): KotlinProjectStructureMetadata? = + GlobalProjectStructureMetadataStorage.getProjectStructureMetadata(project, id.build.name, id.projectPath) +} + +private open class JarArtifactMppDependencyMetadataExtractor( project: Project, dependency: ResolvedComponentResult, val primaryArtifact: File @@ -394,20 +418,31 @@ private class JarArtifactMppDependencyMetadataExtractor( val projectStructureMetadata = projectStructureMetadata artifactBySourceSet.forEach { (sourceSetName, artifact) -> - ZipFile(artifact).use { zip -> - val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") }.toList() + val extension = projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension + ?: SourceSetMetadataLayout.METADATA.archiveExtension + val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension") - // TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR - // Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed + /** NB: the result may contain files that do not exist and won't be created if the actual metadata artifact doesn't contain + * entries for the corresponding source set. It's the consumer's responsibility to filter the result if they need only + * existing files! */ + resultFiles[sourceSetName] = project.files(extractToJarFile) - if (entries.any()) { - val extension = projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension - ?: SourceSetMetadataLayout.METADATA.archiveExtension + if (doProcessFiles) { + if (extractToJarFile.exists()) { + extractToJarFile.delete() + } - val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension") - resultFiles[sourceSetName] = project.files(extractToJarFile) + /** In composite builds, we don't really need tro process the file in IDE import, so ignore it if it's missing */ + // refactor: allow only included builds to provide no artifacts, and allow this only in IDE import + if (!artifact.isFile) return@forEach - if (doProcessFiles) { + ZipFile(artifact).use { zip -> + val entries = zip.entries().asSequence().filter { it.name.startsWith("$sourceSetName/") }.toList() + + // TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR + // Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed + + if (entries.any()) { ZipOutputStream(extractToJarFile.outputStream()).use { resultZipOutput -> for (entry in entries) { if (entry.isDirectory) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 176fdc488f6..06f6f3fb0ef 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -110,6 +110,16 @@ class KotlinMultiplatformPlugin( project.setupGeneralKotlinExtensionParameters() project.pluginManager.apply(ScriptingGradleSubplugin::class.java) + + exportProjectStructureMetadataForOtherBuilds(project) + } + + private fun exportProjectStructureMetadataForOtherBuilds( + project: Project + ) { + GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(project) { + checkNotNull(buildKotlinProjectStructureMetadata(project)) + } } private fun setupAdditionalCompilerArguments(project: Project) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt index 65f848b66a9..6651d20687d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt @@ -125,7 +125,9 @@ internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjec } sourceSet.name to sourceSetExportedDependencies.map { ModuleIds.fromDependency(it) }.toSet() }, - hostSpecificSourceSets = getHostSpecificSourceSets(project).map { it.name }.toSet(), + hostSpecificSourceSets = getHostSpecificSourceSets(project) + .filter { it in sourceSetsWithMetadataCompilations }.map { it.name } + .toSet(), sourceSetBinaryLayout = sourceSetsWithMetadataCompilations.keys.associate { sourceSet -> sourceSet.name to SourceSetMetadataLayout.chooseForProducingProject(project) }, @@ -289,6 +291,31 @@ internal fun parseKotlinSourceSetMetadata( ) } +object GlobalProjectStructureMetadataStorage { + + fun propertyName(buildName: String, projectPath: String) = "kotlin.projectStructureMetadata.build.$buildName.path.$projectPath" + + fun registerProjectStructureMetadata(project: Project, metadataProvider: () -> KotlinProjectStructureMetadata) { + val compositeBuildRoot = generateSequence(project.gradle) { it.parent }.last().rootProject + compositeBuildRoot.extensions.extraProperties.set( + propertyName(project.rootProject.name, project.path), + { metadataProvider().toJson() } + ) + } + + fun getProjectStructureMetadata(project: Project, otherBuildName: String, otherProjectPath: String): KotlinProjectStructureMetadata? { + val compositeBuildRoot = generateSequence(project.gradle) { it.parent }.last().rootProject + val property = propertyName(otherBuildName, otherProjectPath) + return with(compositeBuildRoot.extensions.extraProperties) { + if (has(property)) { + val jsonStringProvider = get(property) as? Function0<*> ?: return null + val jsonString = jsonStringProvider.invoke() as? String ?: return null + parseKotlinSourceSetMetadataFromJson(jsonString) + } else null + } + } +} + private const val ROOT_NODE_NAME = "projectStructure" private const val PUBLISHED_AS_ROOT_NAME = "isPublishedAsRoot" private const val FORMAT_VERSION_NODE_NAME = "formatVersion" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ModuleIds.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ModuleIds.kt index 48d6fc9f468..9df4166a486 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ModuleIds.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ModuleIds.kt @@ -28,7 +28,7 @@ internal object ModuleIds { else -> idFromName(componentSelector.displayName) } - fun fromComponentId( + private fun fromComponentId( thisProject: Project, componentIdentifier: ComponentIdentifier ): ModuleDependencyIdentifier = @@ -39,7 +39,11 @@ internal object ModuleIds { } fun fromComponent(thisProject: Project, component: ResolvedComponentResult) = - fromComponentId(thisProject, component.id) + // If the project component comes from another build, we can't extract anything from it, so just use the module coordinates: + if ((component.id as? ProjectComponentIdentifier)?.build?.isCurrentBuild == false) + ModuleDependencyIdentifier(component.moduleVersion?.group ?: "unspecified", component.moduleVersion?.name ?: "unspecified") + else + fromComponentId(thisProject, component.id) private fun idOfRootModule(project: Project): ModuleDependencyIdentifier = if (project.multiplatformExtensionOrNull != null) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ResolvedMppVariantsProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ResolvedMppVariantsProvider.kt index 22507d165d4..0e7238e20b1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ResolvedMppVariantsProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/ResolvedMppVariantsProvider.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.gradle.api.artifacts.Configuration -import org.gradle.api.artifacts.component.ComponentIdentifier import org.gradle.api.artifacts.component.ProjectComponentIdentifier import org.gradle.api.artifacts.result.ResolvedArtifactResult import org.gradle.api.artifacts.result.ResolvedComponentResult @@ -61,6 +60,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje if (configuration !in resolvedMetadataArtifactByConfiguration) { resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.METADATA) } + // At this point the map should contain the result if calculation above succeeded. If not, put null to avoid recalculation. resolvedMetadataArtifactByConfiguration.getOrPut(configuration) { null } } } @@ -71,6 +71,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje if (configuration !in resolvedArtifactByConfiguration) { resolveConfigurationAndSaveVariants(configuration, artifactResolutionMode = ArtifactResolutionMode.NORMAL) } + // At this point the map should contain the result if the calculation above succeeded. If not, put null to avoid recalculation. resolvedArtifactByConfiguration.getOrPut(configuration) { null } } @@ -79,7 +80,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje private val entriesCache: MutableMap = mutableMapOf() - private val mppComponentIdsByConfiguration: MutableMap> = mutableMapOf() + private val mppComponentsByConfiguration: MutableMap> = mutableMapOf() private enum class ArtifactResolutionMode { NONE, NORMAL, METADATA @@ -89,7 +90,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje configuration: Configuration, artifactResolutionMode: ArtifactResolutionMode ) { - val mppComponentIds: Set = mppComponentIdsByConfiguration.getOrPut(configuration) { + val mppComponentIds: Set = mppComponentsByConfiguration.getOrPut(configuration) { resolveMppComponents(configuration) } @@ -99,7 +100,7 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje } } - private fun resolveMppComponents(configuration: Configuration): MutableSet { + private fun resolveMppComponents(configuration: Configuration): Set { val result = mutableListOf() configuration.incoming.resolutionResult.allComponents { component -> @@ -123,14 +124,16 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje } } - return result.mapTo(mutableSetOf()) { it.id } + return result.toSet() } private fun resolveArtifacts( artifactResolutionMode: ArtifactResolutionMode, configuration: Configuration, - mppComponentIds: Set - ): Map { + mppComponents: Set + ): Map { + val mppComponentById = mppComponents.associateBy { it.id } + val artifactsConfiguration = if ( artifactResolutionMode == ArtifactResolutionMode.NORMAL || @@ -144,22 +147,22 @@ internal class ResolvedMppVariantsProvider private constructor(private val proje } return artifactsConfiguration.incoming.artifactView { view -> - view.componentFilter { it in mppComponentIds } + view.componentFilter { it in mppComponentById } view.attributes { attrs -> attrs.attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA)) } view.lenient(true) - }.artifacts.associateBy { it.id.componentIdentifier } + }.artifacts.associateBy { mppComponentById.getValue(it.id.componentIdentifier) } } private fun matchMppComponentsWithResolvedArtifacts( - mppComponentIds: Set, - artifacts: Map, + mppComponentIds: Set, + artifacts: Map, configuration: Configuration, artifactResolutionMode: ArtifactResolutionMode ) { - val mppModuleIds = mppComponentIds.mapTo(mutableSetOf()) { ModuleIds.fromComponentId(project, it) } + val mppModuleIds = mppComponentIds.mapTo(mutableSetOf()) { ModuleIds.fromComponent(project, it) } mppComponentIds.forEach { componentId -> - val moduleEntry = getEntryForModule(ModuleIds.fromComponentId(project, componentId)) + val moduleEntry = getEntryForModule(ModuleIds.fromComponent(project, componentId)) val artifact = artifacts[componentId] when { // With project dependencies, we don't need the host-specific metadata artifacts, as we have the compilation outputs: diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt index 626ce90a18d..2840cf1f053 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/TransformKotlinGranularMetadata.kt @@ -101,7 +101,9 @@ open class TransformKotlinGranularMetadata @get:Internal internal val filesByResolution: Map - get() = extractableFilesByResolution.mapValues { (_, value) -> project.files(value.getMetadataFilesPerSourceSet(false).values) } + get() = extractableFilesByResolution.mapValues { (_, value) -> + project.files(value.getMetadataFilesPerSourceSet(false).values) + } private val extractableFiles by project.provider { extractableFilesByResolution.values } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt index 5495bdaf09e..91196ed071d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt @@ -177,6 +177,7 @@ class DefaultKotlinSourceSet( baseDir, doProcessFiles = true ) + MetadataDependencyTransformation( group, name, projectPath, resolution.projectStructureMetadata, diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index d65e352ed30..3140523aeba 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.targets.metadata import org.gradle.api.Project import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.component.ComponentIdentifier import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE import org.gradle.api.file.FileCollection import org.gradle.api.internal.component.SoftwareComponentInternal @@ -28,7 +29,6 @@ import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics -import java.util.concurrent.Callable internal const val ALL_COMPILE_METADATA_CONFIGURATION_NAME = "allSourceSetsCompileDependenciesMetadata" internal const val ALL_RUNTIME_METADATA_CONFIGURATION_NAME = "allSourceSetsRuntimeDependenciesMetadata" @@ -408,12 +408,12 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : project.locateTask(transformGranularMetadataTaskName(hierarchySourceSet.name)) } - val allResolutionsByModule: Map> = - mutableMapOf>().apply { + val allResolutionsByComponentId: Map> = + mutableMapOf>().apply { transformationTaskHolders.forEach { val resolutions = it.get().metadataDependencyResolutions resolutions.forEach { resolution -> - getOrPut(ModuleIds.fromComponent(project, resolution.dependency)) { mutableListOf() }.add(resolution) + getOrPut(resolution.dependency.id) { mutableListOf() }.add(resolution) } } } @@ -428,8 +428,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : val artifactView = fromFiles.incoming.artifactView { view -> view.componentFilter { id -> - val moduleId = ModuleIds.fromComponentId(project, id) - allResolutionsByModule[moduleId].let { resolutions -> + allResolutionsByComponentId[id].let { resolutions -> resolutions == null || resolutions.any { it !is MetadataDependencyResolution.ExcludeAsUnrequested } } } @@ -438,8 +437,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : mutableSetOf().apply { addAll(dependsOnCompilationOutputs) artifactView.artifacts.forEach { artifact -> - val resolutions = - allResolutionsByModule[ModuleIds.fromComponentId(project, artifact.id.componentIdentifier)] + val resolutions = allResolutionsByComponentId[artifact.id.componentIdentifier] if (resolutions == null) { add(artifact.file) } else { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt index 869d96ac3bf..753de8b5282 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt @@ -44,7 +44,7 @@ open class KotlinNativeTarget @Inject constructor( private val hostSpecificMetadataJarTaskName get() = disambiguateName("MetadataJar") - private val hostSpecificMetadataElementsConfigurationName get() = disambiguateName("MetadataElements") + internal val hostSpecificMetadataElementsConfigurationName get() = disambiguateName("MetadataElements") override val kotlinComponents: Set by lazy { if (!project.isKotlinGranularMetadataEnabled) @@ -60,13 +60,10 @@ open class KotlinNativeTarget @Inject constructor( .intersect(mainCompilation.allKotlinSourceSets) if (hostSpecificSourceSets.isNotEmpty()) { - val hostSpecificMetadataJar = project.locateOrRegisterTask(hostSpecificMetadataJarTaskName) { - it.archiveAppendix.set(project.provider { disambiguationClassifier.orEmpty().toLowerCase() }) - it.archiveClassifier.set("metadata") - } - project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar) + val hostSpecificMetadataJar = project.locateOrRegisterTask(hostSpecificMetadataJarTaskName) { metadataJar -> + metadataJar.archiveAppendix.set(project.provider { disambiguationClassifier.orEmpty().toLowerCase() }) + metadataJar.archiveClassifier.set("metadata") - hostSpecificMetadataJar.configure { metadataJar -> metadataJar.onlyIf { this@KotlinNativeTarget.publishable } val metadataCompilations = hostSpecificSourceSets.mapNotNull { @@ -80,29 +77,18 @@ open class KotlinNativeTarget @Inject constructor( metadataJar.dependsOn(it.output.classesDirs) } } + project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar) - val metadataConfiguration = project.configurations.findByName(hostSpecificMetadataElementsConfigurationName) - ?: project.configurations.create(hostSpecificMetadataElementsConfigurationName) { configuration -> - configuration.isCanBeConsumed = false - configuration.isCanBeResolved = false - project.artifacts.add(configuration.name, hostSpecificMetadataJar) { artifact -> - artifact.classifier = "metadata" - } - - configuration.extendsFrom(*configurations.getByName(apiElementsConfigurationName).extendsFrom.toTypedArray()) - } - - val metadataAttributes = - HierarchyAttributeContainer(project.configurations.getByName(apiElementsConfigurationName).attributes).apply { - attribute(Usage.USAGE_ATTRIBUTE, project.usageByName(KotlinUsages.KOTLIN_METADATA)) - } + val metadataConfiguration = project.configurations.getByName(hostSpecificMetadataElementsConfigurationName) + project.artifacts.add(metadataConfiguration.name, hostSpecificMetadataJar) { artifact -> + artifact.classifier = "metadata" + } mutableUsageContexts.add( DefaultKotlinUsageContext( mainCompilation, project.usageByName(javaApiUsageForMavenScoping()), metadataConfiguration.name, - overrideConfigurationAttributes = metadataAttributes, includeIntoProjectStructureMetadata = false ) ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index c7bcae48a59..5a593a75b37 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -10,6 +10,9 @@ import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.Dependency +import org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.AttributeContainer +import org.gradle.api.attributes.Usage import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE import org.gradle.api.internal.artifacts.ArtifactAttributes import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet @@ -23,6 +26,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPI import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.KOTLIN_NATIVE_IGNORE_INCORRECT_DEPENDENCIES import org.jetbrains.kotlin.gradle.plugin.mpp.* +import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.targets.native.* import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeHostTest import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest @@ -243,8 +247,23 @@ open class KotlinNativeTargetConfigurator( createKlibCompilationTask(it) } - with(configurations.getByName(target.apiElementsConfigurationName)) { - outgoing.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB) + val apiElements = configurations.getByName(target.apiElementsConfigurationName) + + apiElements.outgoing.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB) + + if (project.isKotlinGranularMetadataEnabled) { + project.configurations.create(target.hostSpecificMetadataElementsConfigurationName) { configuration -> + configuration.isCanBeConsumed = true + configuration.isCanBeResolved = false + + configuration.extendsFrom(*apiElements.extendsFrom.toTypedArray()) + + fun copyAttribute(from: AttributeContainer, to: AttributeContainer, attribute: Attribute) { + to.attribute(attribute, from.getAttribute(attribute)!!) + } + with(apiElements.attributes) { keySet().forEach { copyAttribute(this, configuration.attributes, it) } } + configuration.attributes.attribute(USAGE_ATTRIBUTE, objects.named(Usage::class.java, KotlinUsages.KOTLIN_METADATA)) + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index ebcf8c02833..96fc0cd5a87 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -64,7 +64,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile