diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt index 3e7e20aab3a..e06bde6d83c 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTarget.kt @@ -43,7 +43,7 @@ interface KotlinTarget : Named, HasAttributes { val publishable: Boolean - val components: Set + val components: Set fun mavenPublication(action: Closure) fun mavenPublication(action: Action) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 0275182e962..930d03d64b1 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -359,7 +359,7 @@ internal abstract class AbstractKotlinPlugin( registry.register(KotlinModelBuilder(kotlinPluginVersion, null)) } - private fun rewriteMppDependenciesInPom(target: KotlinTarget) { + private fun rewriteMppDependenciesInPom(target: AbstractKotlinTarget) { val project = target.project fun shouldRewritePoms(): Boolean = @@ -370,7 +370,7 @@ internal abstract class AbstractKotlinPlugin( publishing.publications.withType(MavenPublication::class.java).all { publication -> publication.pom.withXml { xml -> if (shouldRewritePoms()) - project.rewritePomMppDependenciesToActualTargetModules(xml, target.components.single()) + project.rewritePomMppDependenciesToActualTargetModules(xml, target.kotlinComponents.single()) } } } @@ -381,7 +381,7 @@ internal abstract class AbstractKotlinPlugin( uploadTask.repositories.withType(MavenResolver::class.java).all { mavenResolver -> mavenResolver.pom.withXml { xml -> if (shouldRewritePoms()) - project.rewritePomMppDependenciesToActualTargetModules(xml, target.components.single()) + project.rewritePomMppDependenciesToActualTargetModules(xml, target.kotlinComponents.single()) } } } 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 84c04cc2b4c..7827881e8bd 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 @@ -186,27 +186,28 @@ class KotlinMultiplatformPlugin( private fun AbstractKotlinTarget.createMavenPublications(publications: PublicationContainer) { components - .filter { it.publishable } - .forEach { variant -> - val variantPublication = publications.create(variant.name, MavenPublication::class.java).apply { + .map { gradleComponent -> gradleComponent to kotlinComponents.single { it.name == gradleComponent.name } } + .filter { (_, kotlinComponent) -> kotlinComponent.publishable } + .forEach { (gradleComponent, kotlinComponent) -> + val componentPublication = publications.create(kotlinComponent.name, MavenPublication::class.java).apply { // do this in whenEvaluated since older Gradle versions seem to check the files in the variant eagerly: project.whenEvaluated { - from(variant) - variant.sourcesArtifacts.forEach { sourceArtifact -> + from(gradleComponent) + kotlinComponent.sourcesArtifacts.forEach { sourceArtifact -> artifact(sourceArtifact) } } (this as MavenPublicationInternal).publishWithOriginalFileName() - artifactId = variant.defaultArtifactId + artifactId = kotlinComponent.defaultArtifactId pom.withXml { xml -> if (PropertiesProvider(project).keepMppDependenciesIntactInPoms != true) - project.rewritePomMppDependenciesToActualTargetModules(xml, variant) + project.rewritePomMppDependenciesToActualTargetModules(xml, kotlinComponent) } } - (variant as? KotlinTargetComponentWithPublication)?.publicationDelegate = variantPublication - publicationConfigureActions.all { it.execute(variantPublication) } + (kotlinComponent as? KotlinTargetComponentWithPublication)?.publicationDelegate = componentPublication + publicationConfigureActions.all { it.execute(componentPublication) } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt index 4da78cd7973..b15a74b8f1d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinSoftwareComponent.kt @@ -13,12 +13,12 @@ import org.gradle.api.attributes.Usage import org.gradle.api.capabilities.Capability import org.gradle.api.component.ComponentWithCoordinates import org.gradle.api.component.ComponentWithVariants +import org.gradle.api.component.SoftwareComponent import org.gradle.api.internal.component.SoftwareComponentInternal import org.gradle.api.internal.component.UsageContext import org.gradle.api.publish.maven.MavenPublication import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinTarget -import org.jetbrains.kotlin.gradle.plugin.KotlinTargetComponent import org.jetbrains.kotlin.gradle.plugin.ProjectLocalConfigurations open class KotlinSoftwareComponent( @@ -28,7 +28,7 @@ open class KotlinSoftwareComponent( override fun getUsages(): Set = emptySet() - override fun getVariants(): Set = + override fun getVariants(): Set = kotlinTargets.flatMap { it.components }.toSet() override fun getName(): String = name diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt index 35451918cb2..2e93a6ecc2b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinTargets.kt @@ -10,10 +10,18 @@ import org.gradle.api.DomainObjectSet import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project import org.gradle.api.artifacts.ConfigurablePublishArtifact +import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.PublishArtifact +import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.Usage.JAVA_API import org.gradle.api.attributes.Usage.JAVA_RUNTIME_JARS +import org.gradle.api.component.ComponentWithCoordinates +import org.gradle.api.component.ComponentWithVariants +import org.gradle.api.component.SoftwareComponent +import org.gradle.api.internal.component.SoftwareComponentInternal +import org.gradle.api.internal.component.UsageContext +import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.publish.maven.MavenPublication import org.gradle.util.ConfigureUtil import org.gradle.util.WrapUtil @@ -48,7 +56,7 @@ abstract class AbstractKotlinTarget( override val publishable: Boolean get() = true - override val components: Set by lazy { + internal open val kotlinComponents: Set by lazy { val mainCompilation = compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) val usageContexts = createUsageContexts(mainCompilation) setOf( @@ -65,7 +73,86 @@ abstract class AbstractKotlinTarget( } else { KotlinVariant(mainCompilation, usageContexts) } - ).also { project.components.addAll(it) } + ) + } + + override val components: Set by lazy { + val kotlinVariants = kotlinComponents + if (isGradleVersionAtLeast(5, 3)) { + buildAdhocComponentsFromKotlinVariants(kotlinVariants) + } else { + kotlinVariants.also { project.components.addAll(it) } + } + } + + // This API is introduced in Gradle 5.3. TODO when we build against Gradle 5.3+, rewrite this function + private fun buildAdhocComponentsFromKotlinVariants(kotlinVariants: Set): Set { + val softwareComponentFactoryClass = Class.forName("org.gradle.api.component.SoftwareComponentFactory") + // TODO replace internal API access with injection (not possible until we have this class on the compile classpath) + val softwareComponentFactory = (project as ProjectInternal).services.get(softwareComponentFactoryClass) + + val adhocMethod = softwareComponentFactoryClass.getMethod("adhoc", String::class.java) + val adhocSoftwareComponentClass = Class.forName("org.gradle.api.component.AdhocComponentWithVariants") + val addVariantsFromConfigurationMethod = adhocSoftwareComponentClass.getMethod( + "addVariantsFromConfiguration", Configuration::class.java, org.gradle.api.Action::class.java + ) + val configurationVariantDetailsClass = Class.forName("org.gradle.api.component.ConfigurationVariantDetails") + val mapToMavenScopeMethod = configurationVariantDetailsClass.getMethod( + "mapToMavenScope", String::class.java + ) + + return kotlinVariants.map { kotlinVariant -> + val adhocVariant = adhocMethod(softwareComponentFactory, kotlinVariant.name) + + project.whenEvaluated { + (kotlinVariant as SoftwareComponentInternal).usages.filterIsInstance().forEach { kotlinUsageContext -> + val configuration = project.configurations.findByName(kotlinUsageContext.name) + ?: project.configurations.create(kotlinUsageContext.name).also { configuration -> + configuration.isCanBeConsumed = false + configuration.isCanBeResolved = false + configuration.dependencies.addAll(kotlinUsageContext.dependencies) + configuration.dependencyConstraints.addAll(kotlinUsageContext.dependencyConstraints) + configuration.artifacts.addAll(kotlinUsageContext.artifacts) + + kotlinUsageContext.attributes.keySet().forEach { + // capture type parameter T + fun copyAttribute(key: Attribute, from: AttributeContainer, to: AttributeContainer) { + to.attribute(key, from.getAttribute(key)!!) + } + copyAttribute(it, kotlinUsageContext.attributes, configuration.attributes) + } + } + + val chooseMavenScopeAction = Action { configurationVariantDetails -> + val mavenScope = when (kotlinUsageContext.usage.name) { + "java-api-jars" -> "compile" + JAVA_RUNTIME_JARS -> "runtime" + else -> error("unexpected usage value '${kotlinUsageContext.usage.name}'") + } + mapToMavenScopeMethod(configurationVariantDetails, mavenScope) + } + + addVariantsFromConfigurationMethod(adhocVariant, configuration, chooseMavenScopeAction) + } + } + + adhocVariant as SoftwareComponent + + if (kotlinVariant is KotlinVariantWithMetadataVariant) { + object : ComponentWithVariants, ComponentWithCoordinates, SoftwareComponentInternal { + override fun getCoordinates() = kotlinVariant.coordinates + override fun getVariants(): Set = kotlinVariant.variants + override fun getName(): String = adhocVariant.name + override fun getUsages(): MutableSet = (adhocVariant as SoftwareComponentInternal).usages + } + } else { + object : ComponentWithCoordinates, SoftwareComponentInternal { + override fun getCoordinates() = (kotlinVariant as? ComponentWithCoordinates)?.coordinates + override fun getName(): String = adhocVariant.name + override fun getUsages(): MutableSet = (adhocVariant as SoftwareComponentInternal).usages + } + } + }.toSet() } protected fun createKotlinVariant( @@ -80,7 +167,8 @@ abstract class AbstractKotlinTarget( if (targetName == KotlinMultiplatformPlugin.METADATA_TARGET_NAME) return KotlinVariantWithCoordinates(compilation, usageContexts) - val separateMetadataTarget = kotlinExtension.targets.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME) + val separateMetadataTarget = + kotlinExtension.targets.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME) as AbstractKotlinTarget val result = if (kotlinExtension.isGradleMetadataAvailable) { KotlinVariantWithMetadataVariant(compilation, usageContexts, separateMetadataTarget) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt index ecdcb166582..48524b163be 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinVariants.kt @@ -91,7 +91,7 @@ open class KotlinVariantWithCoordinates( class KotlinVariantWithMetadataVariant( producingCompilation: KotlinCompilation<*>, usages: Set, - private val metadataTarget: KotlinTarget + internal val metadataTarget: AbstractKotlinTarget ) : KotlinVariantWithCoordinates(producingCompilation, usages), ComponentWithVariants { override fun getVariants() = metadataTarget.components } @@ -99,14 +99,14 @@ class KotlinVariantWithMetadataVariant( class KotlinVariantWithMetadataDependency( producingCompilation: KotlinCompilation<*>, val originalUsages: Set, - private val metadataTarget: KotlinTarget + private val metadataTarget: AbstractKotlinTarget ) : KotlinVariantWithCoordinates(producingCompilation, originalUsages) { override fun getUsages(): Set = originalUsages.mapTo(mutableSetOf()) { usageContext -> KotlinUsageContextWithAdditionalDependencies(usageContext, setOf(metadataDependency())) } private fun metadataDependency(): ModuleDependency { - val metadataPublication = (metadataTarget.components.single() as KotlinTargetComponentWithPublication).publicationDelegate!! + val metadataPublication = (metadataTarget.kotlinComponents.single() as KotlinTargetComponentWithPublication).publicationDelegate!! val metadataGroupId = metadataPublication.groupId val metadataArtifactId = metadataPublication.artifactId val metadataVersion = metadataPublication.version diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt index ed26e062815..40d81738fdc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/mppDependencyRewritingUtils.kt @@ -124,8 +124,8 @@ private fun associateDependenciesWithActualModuleDependencies( val resolvedToConfiguration = resolved.configuration val dependencyTargetComponent: KotlinTargetComponent = run { - dependencyProjectKotlinExtension.targets.forEach { target -> - target.components.forEach { component -> + dependencyProjectKotlinExtension.targets.withType(AbstractKotlinTarget::class.java).forEach { target -> + target.kotlinComponents.forEach { component -> if (component.findUsageContext(resolvedToConfiguration) != null) return@run component } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt index 17bd4de0d7b..a8f8d7b8706 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/KotlinAndroidTarget.kt @@ -86,7 +86,7 @@ open class KotlinAndroidTarget( ) } - override val components by lazy { + override val kotlinComponents by lazy { checkPublishLibraryVariantsExist() KotlinAndroidPlugin.androidTargetHandler(project.getKotlinPluginVersion()!!, this).doCreateComponents()