Add basic support for Kotlin/Native variants to the PM20 Gradle plugin

This commit is contained in:
Sergey Igushkin
2021-03-19 18:24:03 +03:00
parent 401fbae8d8
commit f029179fe0
30 changed files with 713 additions and 391 deletions
@@ -10,6 +10,7 @@ import org.gradle.api.Action
import org.gradle.api.Named import org.gradle.api.Named
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
interface CInteropSettings : Named { interface CInteropSettings : Named {
@@ -22,7 +23,7 @@ interface CInteropSettings : Named {
} }
// TODO: Provide an interface for native compilations. // TODO: Provide an interface for native compilations.
val compilation: KotlinCompilation<KotlinCommonOptions> val compilation: KotlinCompilationData<out KotlinCommonOptions>
val dependencyConfigurationName: String val dependencyConfigurationName: String
var dependencyFiles: FileCollection var dependencyFiles: FileCollection
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMain import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
import org.jetbrains.kotlin.gradle.targets.js.ir.* import org.jetbrains.kotlin.gradle.targets.js.ir.*
@@ -281,7 +281,7 @@ internal class Kotlin2JsSourceSetProcessor(
kotlinOptions.freeCompilerArgs.contains(PRODUCE_ZIPPED_KLIB) kotlinOptions.freeCompilerArgs.contains(PRODUCE_ZIPPED_KLIB)
) { ) {
// Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721).
val baseName = if (kotlinCompilation.isMain()) { val baseName = if (kotlinCompilation.isMainCompilationData()) {
project.name project.name
} else { } else {
"${project.name}_${kotlinCompilation.compilationPurpose}" "${project.name}_${kotlinCompilation.compilationPurpose}"
@@ -366,7 +366,7 @@ internal class KotlinCommonSourceSetProcessor(
override fun doTargetSpecificProcessing() { override fun doTargetSpecificProcessing() {
project.tasks.named(kotlinCompilation.compileAllTaskName).dependsOn(kotlinTask) project.tasks.named(kotlinCompilation.compileAllTaskName).dependsOn(kotlinTask)
// can be missing (e.g. in case of tests) // can be missing (e.g. in case of tests)
if ((kotlinCompilation as? AbstractKotlinCompilation<*>)?.isMain() == true) { if ((kotlinCompilation as? AbstractKotlinCompilation<*>)?.isMainCompilationData() == true) {
project.locateTask<Task>(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask) project.locateTask<Task>(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask)
} }
@@ -281,11 +281,7 @@ class GradleModuleVariantResolver(val project: Project) : ModuleVariantResolver
val compileClasspath = getCompileDependenciesConfigurationForVariant(project, requestingVariant) val compileClasspath = getCompileDependenciesConfigurationForVariant(project, requestingVariant)
// TODO optimize O(n) search, store the mapping val dependencyModuleId = dependencyModule.moduleIdentifier
val component = compileClasspath.incoming.resolutionResult.allComponents.find { it.id.matchesModule(dependencyModule) }
?: return VariantResolution.NotRequested(requestingVariant, dependencyModule)
val dependencyModuleId = ModuleIds.fromComponent(project, component)
// FIXME check composite builds, it's likely that resolvedVariantProvider fails on them? // FIXME check composite builds, it's likely that resolvedVariantProvider fails on them?
val resolvedGradleVariantName = resolvedVariantProvider.getResolvedVariantName(dependencyModuleId, compileClasspath) val resolvedGradleVariantName = resolvedVariantProvider.getResolvedVariantName(dependencyModuleId, compileClasspath)
val kotlinVariantName = when (dependencyModule) { val kotlinVariantName = when (dependencyModule) {
@@ -323,7 +319,7 @@ class GradleModuleVariantResolver(val project: Project) : ModuleVariantResolver
project.configurations.getByName(compilation.compileDependencyConfigurationName) project.configurations.getByName(compilation.compileDependencyConfigurationName)
} }
is KotlinPm20ProjectExtension -> { is KotlinPm20ProjectExtension -> {
project.configurations.getByName((requestingVariant as KotlinGradleVariant).compileDependencyConfigurationName) (requestingVariant as KotlinGradleVariant).compileDependencyConfiguration
} }
else -> error("could not find the compile dependencies configuration for variant $requestingVariant") else -> error("could not find the compile dependencies configuration for variant $requestingVariant")
} }
@@ -427,7 +427,7 @@ private class IncludedBuildMetadataExtractor(
GlobalProjectStructureMetadataStorage.getProjectStructureMetadata(project, id.build.name, id.projectPath) GlobalProjectStructureMetadataStorage.getProjectStructureMetadata(project, id.build.name, id.projectPath)
} }
private open class JarArtifactMppDependencyMetadataExtractor( internal open class JarArtifactMppDependencyMetadataExtractor(
project: Project, project: Project,
dependency: ResolvedComponentResult, dependency: ResolvedComponentResult,
val primaryArtifact: File val primaryArtifact: File
@@ -602,7 +602,7 @@ private fun mppDependencyMetadataExtractor(
return when { return when {
moduleId is ProjectComponentIdentifier -> when { moduleId is ProjectComponentIdentifier -> when {
moduleId.build.isCurrentBuild -> moduleId.build.isCurrentBuild ->
ProjectMppDependencyMetadataExtractor(project, actualComponent, project.project(moduleId.projectPath)) ProjectMppDependencyMetadataExtractor(project, actualComponent, moduleIdentifier, project.project(moduleId.projectPath))
metadataArtifact != null -> metadataArtifact != null ->
IncludedBuildMetadataExtractor(project, actualComponent, metadataArtifact) IncludedBuildMetadataExtractor(project, actualComponent, metadataArtifact)
else -> null else -> null
@@ -10,18 +10,16 @@ import com.google.gson.JsonObject
import com.google.gson.JsonParser import com.google.gson.JsonParser
import com.google.gson.stream.JsonWriter import com.google.gson.stream.JsonWriter
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal import org.gradle.api.tasks.Internal
import org.gradle.api.tasks.Nested import org.gradle.api.tasks.Nested
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
import org.jetbrains.kotlin.gradle.dsl.topLevelExtensionOrNull import org.jetbrains.kotlin.gradle.dsl.topLevelExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.refinesClosure import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.refinesClosure
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.withAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
import org.jetbrains.kotlin.gradle.targets.metadata.dependsOnClosureWithInterCompilationDependencies import org.jetbrains.kotlin.gradle.targets.metadata.dependsOnClosureWithInterCompilationDependencies
import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations
@@ -133,10 +131,7 @@ data class KotlinProjectStructureMetadata(
internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjectStructureMetadata? { internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjectStructureMetadata? {
val topLevelExtensionOrNull = project.topLevelExtensionOrNull val topLevelExtensionOrNull = project.topLevelExtensionOrNull
if (topLevelExtensionOrNull is KotlinPm20ProjectExtension) { require(topLevelExtensionOrNull is KotlinMultiplatformExtension) { "this function only works with the stable plugin" }
// FIXME: get module by ID, don't just take the main module
return buildProjectStructureMetadata(topLevelExtensionOrNull.main)
}
val sourceSetsWithMetadataCompilations = val sourceSetsWithMetadataCompilations =
project.multiplatformExtensionOrNull?.targets?.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME)?.compilations?.associate { project.multiplatformExtensionOrNull?.targets?.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME)?.compilations?.associate {
@@ -195,7 +190,7 @@ internal fun buildProjectStructureMetadata(module: KotlinGradleModule): KotlinPr
val kotlinFragmentsPerKotlinVariant = val kotlinFragmentsPerKotlinVariant =
module.variants.associate { variant -> variant.name to variant.refinesClosure.map { it.name }.toSet() } module.variants.associate { variant -> variant.name to variant.refinesClosure.map { it.name }.toSet() }
val fragmentRefinesRelation = val fragmentRefinesRelation =
module.fragments.associate { it.name to it.directRefinesDependencies.map { it.name }.toSet() } module.fragments.associate { it.name to it.directRefinesDependencies.map { it.fragmentName }.toSet() }
// FIXME: support native implementation-as-api-dependencies // FIXME: support native implementation-as-api-dependencies
// FIXME: support dependencies on auxiliary modules // FIXME: support dependencies on auxiliary modules
@@ -211,7 +206,7 @@ internal fun buildProjectStructureMetadata(module: KotlinGradleModule): KotlinPr
fragmentRefinesRelation, fragmentRefinesRelation,
module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB }, module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB },
fragmentDependencies, fragmentDependencies,
emptySet(), getHostSpecificFragments(module).mapTo(mutableSetOf()) { it.name },
isPublishedAsRoot = true isPublishedAsRoot = true
) )
} }
@@ -288,7 +288,7 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val project: Project override val project: Project
get() = target.project get() = target.project
override val owner: Any? override val owner: KotlinTarget
get() = target get() = target
override val compilationClassifier: String? override val compilationClassifier: String?
@@ -39,15 +39,18 @@ class GradleKotlinDependencyGraphResolver(
configurationToResolveMetadataDependencies(project, requestingModule) configurationToResolveMetadataDependencies(project, requestingModule)
override fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution { override fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution {
if (!requestingModule.representsProject(project)) if (requestingModule !is KotlinGradleModule)
return DependencyGraphResolution.Unknown(requestingModule) return DependencyGraphResolution.Unknown(requestingModule)
return resolveAsGraph(requestingModule)
}
private fun resolveAsGraph(requestingModule: KotlinGradleModule): GradleDependencyGraph {
val excludeLegacyMetadataModulesFromResult = mutableSetOf<ResolvedComponentResult>() val excludeLegacyMetadataModulesFromResult = mutableSetOf<ResolvedComponentResult>()
val nodeByModuleId = mutableMapOf<KotlinModuleIdentifier, DependencyGraphNode>() val nodeByModuleId = mutableMapOf<KotlinModuleIdentifier, GradleDependencyGraphNode>()
fun nodeFromComponent(component: ResolvedComponentResult, isRoot: Boolean /*refactor*/): DependencyGraphNode { fun nodeFromComponent(component: ResolvedComponentResult, isRoot: Boolean /*refactor me*/): GradleDependencyGraphNode {
val id = component.toModuleIdentifier() val id = component.toSingleModuleIdentifier()
return nodeByModuleId.getOrPut(id) { return nodeByModuleId.getOrPut(id) {
val module = if (isRoot) val module = if (isRoot)
requestingModule requestingModule
@@ -55,14 +58,20 @@ class GradleKotlinDependencyGraphResolver(
.takeIf { component !in excludeLegacyMetadataModulesFromResult } .takeIf { component !in excludeLegacyMetadataModulesFromResult }
?: buildSyntheticModule(component, component.variants.singleOrNull()?.displayName ?: "default") ?: buildSyntheticModule(component, component.variants.singleOrNull()?.displayName ?: "default")
val componentContainingTransitiveDependencies = val metadataSourceComponent =
(module as? ExternalImportedKotlinModule) (module as? ExternalImportedKotlinModule)
?.takeIf { it.hasLegacyMetadataModule } ?.takeIf { it.hasLegacyMetadataModule }
?.let { (component.dependencies.singleOrNull() as? ResolvedDependencyResult)?.selected } ?.let { (component.dependencies.singleOrNull() as? ResolvedDependencyResult)?.selected }
?: component ?: component
val resolvedComponentDependencies = componentContainingTransitiveDependencies.dependencies val dependenciesRequestedByModule =
module.fragments.flatMap { fragment -> fragment.declaredModuleDependencies.map { it.moduleIdentifier } }.toSet()
val resolvedComponentDependencies = metadataSourceComponent.dependencies
.filterIsInstance<ResolvedDependencyResult>() .filterIsInstance<ResolvedDependencyResult>()
// This filter statement is used to only visit the dependencies of the variant(s) of the requested Kotlin module and not
// other variants. This prevents infinite recursion when visiting multiple Kotlin modules within one Gradle components
.filter { dependency -> dependency.requested.toModuleIdentifiers().any { it in dependenciesRequestedByModule } }
.flatMap { dependency -> dependency.requested.toModuleIdentifiers().map { id -> id to dependency.selected } } .flatMap { dependency -> dependency.requested.toModuleIdentifiers().map { id -> id to dependency.selected } }
.toMap() .toMap()
@@ -72,13 +81,30 @@ class GradleKotlinDependencyGraphResolver(
deps.mapNotNull { resolvedComponentDependencies[it.moduleIdentifier] }.map { nodeFromComponent(it, isRoot = false) } deps.mapNotNull { resolvedComponentDependencies[it.moduleIdentifier] }.map { nodeFromComponent(it, isRoot = false) }
} }
DependencyGraphNode(module, nodeDependenciesMap) GradleDependencyGraphNode(
module,
component,
metadataSourceComponent,
nodeDependenciesMap
)
} }
} }
return DependencyGraphResolution.DependencyGraph( return GradleDependencyGraph(
requestingModule, requestingModule,
nodeFromComponent(configurationToResolve(requestingModule).incoming.resolutionResult.root, isRoot = true) nodeFromComponent(configurationToResolve(requestingModule).incoming.resolutionResult.root, isRoot = true)
) )
} }
} }
class GradleDependencyGraphNode(
override val module: KotlinModule,
val selectedComponent: ResolvedComponentResult,
val metadataSourceComponent: ResolvedComponentResult?,
override val dependenciesByFragment: Map<KotlinModuleFragment, Iterable<GradleDependencyGraphNode>>
) : DependencyGraphNode(module, dependenciesByFragment)
class GradleDependencyGraph(
override val requestingModule: KotlinGradleModule,
override val root: GradleDependencyGraphNode
) : DependencyGraphResolution.DependencyGraph(requestingModule, root)
@@ -163,7 +163,8 @@ internal class ExternalSyntheticKotlinModule(private val moduleData: BasicKotlin
internal class ExternalImportedKotlinModule( internal class ExternalImportedKotlinModule(
private val moduleData: BasicKotlinModule, private val moduleData: BasicKotlinModule,
val projectStructureMetadata: KotlinProjectStructureMetadata val projectStructureMetadata: KotlinProjectStructureMetadata,
val hostSpecificFragments: Set<KotlinModuleFragment>
) : KotlinModule by moduleData { ) : KotlinModule by moduleData {
val hasLegacyMetadataModule = !projectStructureMetadata.isPublishedAsRoot val hasLegacyMetadataModule = !projectStructureMetadata.isPublishedAsRoot
@@ -51,14 +51,12 @@ internal class FragmentGranularMetadataResolver(
if (dependencyGraph is DependencyGraphResolution.Unknown) if (dependencyGraph is DependencyGraphResolution.Unknown)
error("unexpected failure in dependency graph resolution for $requestingFragment in $project") error("unexpected failure in dependency graph resolution for $requestingFragment in $project")
dependencyGraph as DependencyGraphResolution.DependencyGraph dependencyGraph as GradleDependencyGraph // refactor the type hierarchy to avoid this downcast? FIXME?
val fragmentsToInclude = requestingFragment.refinesClosure val fragmentsToInclude = requestingFragment.refinesClosure
val requestedDependencies = dependencyGraph.root.dependenciesByFragment.filterKeys { it in fragmentsToInclude }.values.flatten() val requestedDependencies = dependencyGraph.root.dependenciesByFragment.filterKeys { it in fragmentsToInclude }.values.flatten()
val visited = mutableSetOf<DependencyGraphNode>() val visited = mutableSetOf<GradleDependencyGraphNode>()
val fragmentResolutionQueue = ArrayDeque<DependencyGraphNode>().apply { val fragmentResolutionQueue = ArrayDeque<GradleDependencyGraphNode>(requestedDependencies)
addAll(requestedDependencies)
}
val results = mutableSetOf<MetadataDependencyResolution>() val results = mutableSetOf<MetadataDependencyResolution>()
@@ -69,18 +67,15 @@ internal class FragmentGranularMetadataResolver(
val dependencyModule = dependencyNode.module val dependencyModule = dependencyNode.module
val fragmentVisibility = fragmentResolver.getChosenFragments(requestingFragment, dependencyModule) val fragmentVisibility = fragmentResolver.getChosenFragments(requestingFragment, dependencyModule)
val visibleFragments = (fragmentVisibility as? FragmentResolution.ChosenFragments)?.visibleFragments?.toList().orEmpty() val chosenFragments = fragmentVisibility as? FragmentResolution.ChosenFragments
val variantResolutions = val visibleFragments = chosenFragments?.visibleFragments?.toList().orEmpty()
(fragmentVisibility as? FragmentResolution.ChosenFragments)?.variantResolutions?.associateBy { it.requestingVariant }
val visibleTransitiveDependencies = val visibleTransitiveDependencies =
dependencyNode.dependenciesByFragment.filterKeys { it in visibleFragments }.values.flattenTo(mutableSetOf()) dependencyNode.dependenciesByFragment.filterKeys { it in visibleFragments }.values.flattenTo(mutableSetOf())
//FIXME host-specific fragments
fragmentResolutionQueue.addAll(visibleTransitiveDependencies.filter { it !in visited }) fragmentResolutionQueue.addAll(visibleTransitiveDependencies.filter { it !in visited })
val resolvedComponentResult = resolvedComponentsByModuleId.getValue(dependencyModule.moduleIdentifier) val resolvedComponentResult = dependencyNode.selectedComponent
val isResolvedAsProject = resolvedComponentResult.toProjectOrNull(project) val isResolvedAsProject = resolvedComponentResult.toProjectOrNull(project)
val result = when (dependencyModule) { val result = when (dependencyModule) {
is ExternalSyntheticKotlinModule -> { is ExternalSyntheticKotlinModule -> {
@@ -90,14 +85,7 @@ internal class FragmentGranularMetadataResolver(
val projectStructureMetadata = (dependencyModule as? ExternalImportedKotlinModule)?.projectStructureMetadata val projectStructureMetadata = (dependencyModule as? ExternalImportedKotlinModule)?.projectStructureMetadata
?: checkNotNull(getProjectStructureMetadata(project, resolvedComponentResult, configurationToResolve)) ?: checkNotNull(getProjectStructureMetadata(project, resolvedComponentResult, configurationToResolve))
// FIXME host-specific metadata!!! val metadataSourceComponent = dependencyNode.run { metadataSourceComponent ?: selectedComponent }
val metadataSourceComponent = when {
dependencyModule is ExternalImportedKotlinModule && dependencyModule.hasLegacyMetadataModule ->
resolvedComponentResult.dependencies.filterIsInstance<ResolvedDependencyResult>().singleOrNull()?.selected
?: resolvedComponentResult
else -> resolvedComponentResult
}
val parentResolutionsForDependency = val parentResolutionsForDependency =
parentResultsByModuleIdentifier[metadataSourceComponent.toSingleModuleIdentifier()].orEmpty() parentResultsByModuleIdentifier[metadataSourceComponent.toSingleModuleIdentifier()].orEmpty()
@@ -106,6 +94,15 @@ internal class FragmentGranularMetadataResolver(
.flatMapTo(mutableSetOf()) { it.allVisibleSourceSetNames } .flatMapTo(mutableSetOf()) { it.allVisibleSourceSetNames }
val visibleFragmentNames = visibleFragments.map { it.fragmentName }.toSet() val visibleFragmentNames = visibleFragments.map { it.fragmentName }.toSet()
val metadataExtractor = getMetadataExtractor(project, resolvedComponentResult, configurationToResolve, true)
if (dependencyModule is ExternalImportedKotlinModule &&
metadataExtractor is JarArtifactMppDependencyMetadataExtractor &&
chosenFragments != null
) {
resolveHostSpecificMetadataArtifacts(dependencyModule, chosenFragments, metadataExtractor)
}
ChooseVisibleSourceSetsImpl( ChooseVisibleSourceSetsImpl(
metadataSourceComponent, metadataSourceComponent,
isResolvedAsProject, isResolvedAsProject,
@@ -113,14 +110,14 @@ internal class FragmentGranularMetadataResolver(
visibleFragmentNames, visibleFragmentNames,
visibleFragmentNames.minus(fragmentsVisibleByParents), visibleFragmentNames.minus(fragmentsVisibleByParents),
visibleTransitiveDependencies.map { resolvedDependenciesByModuleId.getValue(it.module.moduleIdentifier) }.toSet(), visibleTransitiveDependencies.map { resolvedDependenciesByModuleId.getValue(it.module.moduleIdentifier) }.toSet(),
checkNotNull(getMetadataExtractor(project, resolvedComponentResult, configurationToResolve, true)) checkNotNull(metadataExtractor)
) )
} }
} }
results.add(result) results.add(result)
fragmentResolutionQueue.addAll(visibleTransitiveDependencies.filterNot(visited::contains))
} }
// FIXME this code is based on whole components; use module IDs with classifiers instead
val resultSourceComponents = results.mapTo(mutableSetOf()) { it.dependency } val resultSourceComponents = results.mapTo(mutableSetOf()) { it.dependency }
resolvedComponentsByModuleId.values.minus(resultSourceComponents).forEach { resolvedComponentsByModuleId.values.minus(resultSourceComponents).forEach {
results.add(MetadataDependencyResolution.ExcludeAsUnrequested(it, it.toProjectOrNull(project))) results.add(MetadataDependencyResolution.ExcludeAsUnrequested(it, it.toProjectOrNull(project)))
@@ -128,4 +125,33 @@ internal class FragmentGranularMetadataResolver(
return results return results
} }
private fun resolveHostSpecificMetadataArtifacts(
dependencyModule: ExternalImportedKotlinModule,
chosenFragments: FragmentResolution.ChosenFragments,
metadataExtractor: JarArtifactMppDependencyMetadataExtractor
) {
val visibleFragments = chosenFragments.visibleFragments
val variantResolutions = chosenFragments.variantResolutions
val hostSpecificFragments = dependencyModule.hostSpecificFragments
val hostSpecificFragmentToArtifact = visibleFragments.intersect(hostSpecificFragments).mapNotNull { hostSpecificFragment ->
val relevantResolution = variantResolutions
.filterIsInstance<VariantResolution.VariantMatch>()
// find some of our variants that resolved a dependency's variant containing the fragment
.find { hostSpecificFragment in it.chosenVariant.refinesClosure }
// resolve the dependencies of that variant getting the host-specific metadata artifact
relevantResolution?.let { resolution ->
val variantResolvingPlatformArtifact =
(resolution.requestingVariant as KotlinGradleVariant).compileDependencyConfiguration
val configuration = variantResolvingPlatformArtifact
val hostSpecificArtifact = ResolvedMppVariantsProvider.get(project)
.getHostSpecificMetadataArtifactByRootModule(
dependencyModule.moduleIdentifier,
configuration
)
hostSpecificArtifact?.let { hostSpecificFragment.fragmentName to it }
}
}
metadataExtractor.metadataArtifactBySourceSet.putAll(hostSpecificFragmentToArtifact)
}
} }
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier
import javax.inject.Inject import javax.inject.Inject
import kotlin.reflect.KClass
abstract class KotlinPm20GradlePlugin @Inject constructor( abstract class KotlinPm20GradlePlugin @Inject constructor(
@Inject private val softwareComponentFactory: SoftwareComponentFactory @Inject private val softwareComponentFactory: SoftwareComponentFactory
@@ -35,11 +36,28 @@ abstract class KotlinPm20GradlePlugin @Inject constructor(
} }
private fun registerDefaultVariantFactories(project: Project) { private fun registerDefaultVariantFactories(project: Project) {
project.pm20Extension.modules.configureEach { project.pm20Extension.modules.configureEach { module ->
it.fragments.registerFactory( module.fragments.registerFactory(
KotlinJvmVariant::class.java, KotlinJvmVariant::class.java,
KotlinJvmVariantFactory(it) KotlinJvmVariantFactory(module)
) )
fun <T: KotlinNativeVariantInternal> registerNativeVariantFactory(variantClass: KClass<T>) {
module.fragments.registerFactory(
variantClass.java,
KotlinNativeVariantFactory(module, variantClass)
)
}
listOf(
// FIXME codegen, add missing native targets
KotlinLinuxX64Variant::class,
KotlinMacosX64Variant::class,
KotlinMacosArm64Variant::class,
KotlinIosX64Variant::class,
KotlinIosArm64Variant::class
).forEach { variantClass ->
registerNativeVariantFactory(variantClass)
}
} }
} }
@@ -1,115 +0,0 @@
/*
* Copyright 2010-2021 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.pm20
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.mpp.filterModuleName
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
import org.jetbrains.kotlin.gradle.targets.metadata.createTransformedMetadataClasspath
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
internal class KotlinFragmentMetadataCompilationData(
override val project: Project,
val fragment: KotlinGradleFragment,
private val module: KotlinGradleModule,
private val compileAllTask: TaskProvider<DefaultTask>,
val metadataCompilationRegistry: MetadataCompilationRegistry,
private val resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : KotlinCompilationData<KotlinMultiplatformCommonOptions> {
override val owner
get() = project.pm20Extension
override val compilationPurpose: String
get() = fragment.fragmentName
override val compilationClassifier: String
get() = lowerCamelCaseName(module.name, "metadata")
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = mapOf(fragment.fragmentName to fragment.kotlinSourceRoots)
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinMetadata")
override val compileAllTaskName: String
get() = compileAllTask.name
override val compileDependencyFiles: FileCollection by project.provider {
createTransformedMetadataClasspath(
project,
resolvableMetadataConfiguration(fragment.containingModule),
lazy { fragment.refinesClosure.minus(fragment).map { metadataCompilationRegistry.byFragment(it).output.classesDirs } },
resolvedMetadataFiles
)
}
override val output: KotlinCompilationOutput = DefaultKotlinCompilationOutput(
project,
project.provider { project.buildDir.resolve("processedResources/${fragment.disambiguateName("metadata")}") }
)
override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() // FIXME apply settings
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.common
override val moduleName: String
get() { // FIXME deduplicate with ownModuleName
val baseName = project.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName
?: project.name
val suffix = if (module.moduleClassifier == null) "" else "_${module.moduleClassifier}"
return filterModuleName("$baseName$suffix")
}
override val ownModuleName: String
get() = moduleName
override val kotlinOptions: KotlinMultiplatformCommonOptions = // FIXME expose for configuration
KotlinMultiplatformCommonOptionsImpl()
override val friendPaths: Iterable<FileCollection>
get() = metadataCompilationRegistry.run {
fragment.refinesClosure.minus(fragment)
.map {
metadataCompilationRegistry.byFragment(it).output.classesDirs
}
}
}
internal class MetadataCompilationRegistry {
private val compilationDataPerFragment = mutableMapOf<KotlinGradleFragment, KotlinFragmentMetadataCompilationData>()
fun register(fragment: KotlinGradleFragment, compilationData: KotlinFragmentMetadataCompilationData) {
compilationDataPerFragment[fragment]?.let { error("compilation data for fragment $fragment already registered") }
compilationDataPerFragment[fragment] = compilationData
withAllCallbacks.forEach { it.invoke(compilationData) }
}
fun byFragment(fragment: KotlinGradleFragment): KotlinFragmentMetadataCompilationData =
compilationDataPerFragment.getValue(fragment)
private val withAllCallbacks = mutableListOf<(KotlinFragmentMetadataCompilationData) -> Unit>()
fun withAll(action: (KotlinFragmentMetadataCompilationData) -> Unit) {
compilationDataPerFragment.forEach { action(it.value) }
withAllCallbacks += action
}
}
@@ -5,19 +5,11 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20 package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention import org.gradle.api.plugins.BasePluginConvention
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.pm20Extension import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.filterModuleName import org.jetbrains.kotlin.gradle.plugin.mpp.filterModuleName
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.refinesClosure
open class KotlinJvmVariant(containingModule: KotlinGradleModule, fragmentName: String) : open class KotlinJvmVariant(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinGradlePublishedVariantWithRuntime(containingModule, fragmentName) { KotlinGradlePublishedVariantWithRuntime(containingModule, fragmentName) {
@@ -29,48 +21,6 @@ open class KotlinJvmVariant(containingModule: KotlinGradleModule, fragmentName:
class KotlinJvmVariantCompilationData(val variant: KotlinJvmVariant) : KotlinVariantCompilationDataInternal<KotlinJvmOptions> { class KotlinJvmVariantCompilationData(val variant: KotlinJvmVariant) : KotlinVariantCompilationDataInternal<KotlinJvmOptions> {
override val owner: KotlinJvmVariant get() = variant override val owner: KotlinJvmVariant get() = variant
override val compilationPurpose: String
get() = variant.containingModule.name
override val compilationClassifier: String
get() = variant.name
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = variant.refinesClosure.filterIsInstance<KotlinGradleVariant>().associate { it.disambiguateName("") to it.kotlinSourceRoots }
override val output: KotlinCompilationOutput
get() = variant.compilationOutputs
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", compilationPurpose.takeIf { it != "main" }, "Kotlin", compilationClassifier)
override val compileAllTaskName: String
get() = variant.disambiguateName("classes")
override val compileDependencyFiles: FileCollection
get() = variant.compileDependencyFiles
override val languageSettings: LanguageSettingsBuilder
get() = variant.languageSettings
override val platformType: KotlinPlatformType
get() = variant.platformType
override val friendPaths: Iterable<FileCollection>
// TODO for now, all output classes of the module are considered friends, even those not on the classpath
get() {
// FIXME support compiling against the JARs
return variant.containingModule.project.pm20Extension.modules.flatMap { it.variants.map { it.compilationOutputs.classesDirs } }
}
override val moduleName: String
get() = // TODO accurate module names that don't rely on all variants having a main counterpart
variant.containingModule.project.pm20Extension.modules
.getByName(KotlinGradleModule.MAIN_MODULE_NAME).variants.findByName(variant.name)?.ownModuleName() ?: ownModuleName
override val ownModuleName: String
get() = variant.ownModuleName()
// TODO pull out to the variant // TODO pull out to the variant
override val kotlinOptions: KotlinJvmOptions override val kotlinOptions: KotlinJvmOptions
get() = KotlinJvmOptionsImpl() get() = KotlinJvmOptionsImpl()
@@ -0,0 +1,206 @@
/*
* Copyright 2010-2021 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.pm20
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
import org.jetbrains.kotlin.gradle.targets.metadata.createTransformedMetadataClasspath
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
interface KotlinMetadataCompilationData<T : KotlinCommonOptions> : KotlinCompilationData<T> {
val isActive: Boolean
}
interface KotlinCommonFragmentMetadataCompilationData : KotlinMetadataCompilationData<KotlinMultiplatformCommonOptions>
internal abstract class AbstractKotlinFragmentMetadataCompilationData<T : KotlinCommonOptions>(
final override val project: Project,
val fragment: KotlinGradleFragment,
private val module: KotlinGradleModule,
private val compileAllTask: TaskProvider<DefaultTask>,
val metadataCompilationRegistry: MetadataCompilationRegistry,
private val resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : KotlinMetadataCompilationData<T> {
override val owner
get() = project.pm20Extension
override val compilationPurpose: String
get() = fragment.fragmentName
override val compilationClassifier: String
get() = lowerCamelCaseName(module.name, "metadata")
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = mapOf(fragment.fragmentName to fragment.kotlinSourceRoots)
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinMetadata")
override val compileAllTaskName: String
get() = compileAllTask.name
override val compileDependencyFiles: FileCollection by project.provider {
createTransformedMetadataClasspath(
project,
resolvableMetadataConfiguration(fragment.containingModule),
lazy { fragment.refinesClosure.minus(fragment).map { metadataCompilationRegistry.byFragment(it).output.classesDirs } },
resolvedMetadataFiles
)
}
override val output: KotlinCompilationOutput = DefaultKotlinCompilationOutput(
project,
project.provider { project.buildDir.resolve("processedResources/${fragment.disambiguateName("metadata")}") }
)
override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() // FIXME apply settings
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.common
override val moduleName: String
get() { // FIXME deduplicate with ownModuleName
val baseName = project.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName
?: project.name
val suffix = if (module.moduleClassifier == null) "" else "_${module.moduleClassifier}"
return filterModuleName("$baseName$suffix")
}
override val ownModuleName: String
get() = moduleName
override val friendPaths: Iterable<FileCollection>
get() = metadataCompilationRegistry.run {
fragment.refinesClosure.minus(fragment)
.map {
metadataCompilationRegistry.byFragment(it).output.classesDirs
}
}
}
internal open class KotlinCommonFragmentMetadataCompilationDataImpl(
project: Project,
fragment: KotlinGradleFragment,
module: KotlinGradleModule,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry,
resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : AbstractKotlinFragmentMetadataCompilationData<KotlinMultiplatformCommonOptions>(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
resolvedMetadataFiles), KotlinCommonFragmentMetadataCompilationData {
override val isActive: Boolean
get() = !fragment.isNativeShared()
override val kotlinOptions: KotlinMultiplatformCommonOptions = KotlinMultiplatformCommonOptionsImpl()
}
interface KotlinNativeFragmentMetadataCompilationData :
KotlinMetadataCompilationData<KotlinCommonOptions>,
KotlinNativeCompilationData<KotlinCommonOptions>
internal fun KotlinGradleFragment.isNativeShared(): Boolean =
containingModule.variantsContainingFragment(this).all { it.platformType == KotlinPlatformType.native }
internal fun KotlinGradleFragment.isNativeHostSpecific(): Boolean =
this in getHostSpecificFragments(containingModule)
internal open class KotlinNativeFragmentMetadataCompilationDataImpl(
project: Project,
fragment: KotlinGradleFragment,
module: KotlinGradleModule,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry,
resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : AbstractKotlinFragmentMetadataCompilationData<KotlinCommonOptions>(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
resolvedMetadataFiles
), KotlinNativeFragmentMetadataCompilationData {
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinNativeMetadata")
override val isActive: Boolean
get() = fragment.isNativeShared()
override val kotlinOptions: NativeCompileOptions
get() = NativeCompileOptions { languageSettings }
override val konanTarget: KonanTarget
get() {
val nativeVariants =
fragment.containingModule.variantsContainingFragment(fragment).filterIsInstance<KotlinNativeVariantInternal>()
return nativeVariants.firstOrNull { it.konanTarget.enabledOnCurrentHost }?.konanTarget
?: nativeVariants.firstOrNull()?.konanTarget
?: HostManager.host
}
// FIXME endorsed libs?
override val enableEndorsedLibs: Boolean
get() = false
}
// TODO think about more generic case: a fragment that can be compiled by an arbitrary compiler
// what tasks should we create? should there be a generic task for that?
internal class MetadataCompilationRegistry {
private val commonCompilationDataPerFragment = mutableMapOf<KotlinGradleFragment, KotlinCommonFragmentMetadataCompilationDataImpl>()
private val nativeCompilationDataPerFragment = mutableMapOf<KotlinGradleFragment, KotlinNativeFragmentMetadataCompilationDataImpl>()
fun registerCommon(fragment: KotlinGradleFragment, compilationData: KotlinCommonFragmentMetadataCompilationDataImpl) {
commonCompilationDataPerFragment.compute(fragment) { _, existing ->
existing?.let { error("common compilation data for fragment $fragment already registered") }
compilationData
}
withAllCommonCallbacks.forEach { it.invoke(compilationData) }
}
fun registerNative(fragment: KotlinGradleFragment, compilationData: KotlinNativeFragmentMetadataCompilationDataImpl) {
nativeCompilationDataPerFragment.compute(fragment) { _, existing ->
existing?.let { error("native compilation data for fragment $fragment already registered") }
compilationData
}
withAllNativeCallbacks.forEach { it.invoke(compilationData) }
}
fun byFragment(fragment: KotlinGradleFragment): KotlinMetadataCompilationData<*> =
listOf(commonCompilationDataPerFragment.getValue(fragment), nativeCompilationDataPerFragment.getValue(fragment)).single {
it.isActive
}
private val withAllCommonCallbacks = mutableListOf<(AbstractKotlinFragmentMetadataCompilationData<*>) -> Unit>()
private val withAllNativeCallbacks = mutableListOf<(AbstractKotlinFragmentMetadataCompilationData<*>) -> Unit>()
fun withAll(action: (AbstractKotlinFragmentMetadataCompilationData<*>) -> Unit) {
commonCompilationDataPerFragment.forEach { action(it.value) }
nativeCompilationDataPerFragment.forEach { action(it.value) }
withAllCommonCallbacks += action
withAllNativeCallbacks += action
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2021 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.pm20
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultCInteropSettings
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeCompileOptions
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.konan.target.KonanTarget
import javax.inject.Inject
open class KotlinNativeVariantInternal(
containingModule: KotlinGradleModule,
fragmentName: String,
val konanTarget: KonanTarget
) : KotlinNativeVariant,
KotlinGradleVariantInternal(containingModule, fragmentName),
SingleMavenPublicationHolder by DefaultSingleMavenPublicationHolder(containingModule, fragmentName) {
override var enableEndorsedLibraries: Boolean = false
override val gradleVariantNames: Set<String>
get() = listOf(apiElementsConfigurationName).flatMap { listOf(it, publishedConfigurationName(it)) }.toSet()
val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
DefaultCInteropSettings(project, cinteropName, compilationData)
}
internal val compilationData by lazy { KotlinNativeVariantCompilationData(this) }
}
// FIXME codegen
open class KotlinLinuxX64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.LINUX_X64)
open class KotlinMacosX64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.MACOS_X64)
open class KotlinMacosArm64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.MACOS_ARM64)
open class KotlinIosX64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.IOS_X64)
open class KotlinIosArm64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.IOS_ARM64)
internal val KotlinNativeVariant.hostSpecificMetadataConfigurationName
get() = disambiguateName("MetadataElements")
interface KotlinNativeCompilationData<T : KotlinCommonOptions> : KotlinCompilationData<T> {
val konanTarget: KonanTarget
val enableEndorsedLibs: Boolean
}
internal class KotlinNativeVariantCompilationData(
val variant: KotlinNativeVariantInternal
) : KotlinVariantCompilationDataInternal<KotlinCommonOptions>, KotlinNativeCompilationData<KotlinCommonOptions> {
override val konanTarget: KonanTarget
get() = variant.konanTarget
override val enableEndorsedLibs: Boolean
get() = variant.enableEndorsedLibraries
override val project: Project
get() = variant.containingModule.project
override val owner: KotlinNativeVariant
get() = variant
override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { languageSettings }
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.project.model.refinesClosure import org.jetbrains.kotlin.project.model.refinesClosure
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
import java.util.concurrent.Callable
import kotlin.reflect.KClass import kotlin.reflect.KClass
open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>( open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
@@ -27,12 +27,13 @@ abstract class AbstractKotlinGradleVariantFactory<T : KotlinGradleVariant>(
module: KotlinGradleModule module: KotlinGradleModule
) : AbstractKotlinGradleFragmentFactory<T>(module) { ) : AbstractKotlinGradleFragmentFactory<T>(module) {
override fun create(name: String): T = super.create(name).also { fragment -> override fun create(name: String): T =
createSourcesArchiveTask(fragment) super.create(name).also { fragment ->
configureKotlinCompilation(fragment) createSourcesArchiveTask(fragment)
createElementsConfigurations(fragment) createElementsConfigurations(fragment)
// TODO configure resources processing configureKotlinCompilation(fragment)
} // TODO configure resources processing
}
protected open fun setPlatformAttributesInConfiguration(fragment: T, configuration: Configuration) { protected open fun setPlatformAttributesInConfiguration(fragment: T, configuration: Configuration) {
configuration.attributes.attribute(KotlinPlatformType.attribute, fragment.platformType) configuration.attributes.attribute(KotlinPlatformType.attribute, fragment.platformType)
@@ -57,6 +57,9 @@ abstract class KotlinGradleVariantInternal(
override fun toString(): String = "variant $fragmentName in $containingModule" override fun toString(): String = "variant $fragmentName in $containingModule"
} }
internal val KotlinGradleVariant.compileDependencyConfiguration: Configuration
get() = containingModule.project.configurations.getByName(compileDependencyConfigurationName)
class DefaultSingleMavenPublicationHolder( class DefaultSingleMavenPublicationHolder(
private var module: KotlinGradleModule, private var module: KotlinGradleModule,
override val defaultPublishedModuleSuffix: String? override val defaultPublishedModuleSuffix: String?
@@ -32,7 +32,7 @@ abstract class AbstractKotlinGradleFragmentFactory<T : KotlinGradleFragment>(
with(project.configurations) { with(project.configurations) {
fragment.relatedConfigurationNames.forEach { configurationName -> fragment.relatedConfigurationNames.forEach { configurationName ->
maybeCreate(configurationName).apply { maybeCreate(configurationName).apply {
// FIXME add metadata configurations? // FIXME add metadata configurations or API for IDE import?
if (!configurationName.endsWith(METADATA_CONFIGURATION_NAME_SUFFIX)) { if (!configurationName.endsWith(METADATA_CONFIGURATION_NAME_SUFFIX)) {
isCanBeResolved = false isCanBeResolved = false
} }
@@ -10,7 +10,6 @@ import org.gradle.api.Project
import org.gradle.api.attributes.Usage import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.jvm.tasks.Jar import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.pm20Extension import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinCommonSourceSetProcessor import org.jetbrains.kotlin.gradle.plugin.KotlinCommonSourceSetProcessor
@@ -23,6 +22,7 @@ import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.tasks.withType import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.project.model.KotlinModuleFragment import org.jetbrains.kotlin.project.model.KotlinModuleFragment
import java.util.concurrent.Callable import java.util.concurrent.Callable
@@ -66,7 +66,7 @@ private fun generateAndExportProjectStructureMetadata(
module: KotlinGradleModule module: KotlinGradleModule
) { ) {
val project = module.project val project = module.project
val projectStructureMetadata = project.createGenerateProjectStructureMetadataTask(module.moduleClassifier) val projectStructureMetadata = project.createGenerateProjectStructureMetadataTask(module)
project.tasks.withType<Jar>().named(metadataJarName(module)).configure { jar -> project.tasks.withType<Jar>().named(metadataJarName(module)).configure { jar ->
jar.from(projectStructureMetadata.map { it.resultFile }) { spec -> jar.from(projectStructureMetadata.map { it.resultFile }) { spec ->
spec.into("META-INF") spec.into("META-INF")
@@ -74,7 +74,7 @@ private fun generateAndExportProjectStructureMetadata(
} }
} }
GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(project) { GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(project) {
checkNotNull(buildKotlinProjectStructureMetadata(project)) buildProjectStructureMetadata(module)
} }
} }
@@ -108,7 +108,13 @@ private fun configureMetadataCompilationsAndCreateRegistry(
} }
val compileAllTask = project.registerTask<DefaultTask>(lowerCamelCaseName(module.moduleClassifier, "metadataClasses")) val compileAllTask = project.registerTask<DefaultTask>(lowerCamelCaseName(module.moduleClassifier, "metadataClasses"))
module.fragments.all { fragment -> module.fragments.all { fragment ->
createMetadataCompilation(fragment, compileAllTask, metadataCompilationRegistry) createCommonMetadataCompilation(fragment, compileAllTask, metadataCompilationRegistry)
createNativeMetadataCompilation(fragment, compileAllTask, metadataCompilationRegistry)
}
metadataCompilationRegistry.withAll { compilation ->
project.tasks.matching { it.name == compilation.compileKotlinTaskName }.configureEach { task ->
task.onlyIf { compilation.isActive }
}
} }
} }
@@ -140,49 +146,83 @@ private fun configureMetadataJarTask(
internal fun metadataJarName(module: KotlinGradleModule) = internal fun metadataJarName(module: KotlinGradleModule) =
lowerCamelCaseName(module.moduleClassifier, "metadataJar") lowerCamelCaseName(module.moduleClassifier, "metadataJar")
private fun createMetadataCompilation( private fun createCommonMetadataCompilation(
fragment: KotlinGradleFragment, fragment: KotlinGradleFragment,
compileAllTask: TaskProvider<DefaultTask>, compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry metadataCompilationRegistry: MetadataCompilationRegistry
): KotlinCompilationData<out KotlinMultiplatformCommonOptions> { ) {
val module = fragment.containingModule val module = fragment.containingModule
val project = module.project val project = module.project
val metadataCompilationData = val metadataCompilationData =
KotlinFragmentMetadataCompilationData( KotlinCommonFragmentMetadataCompilationDataImpl(
project, project,
fragment, fragment,
module, module,
compileAllTask, compileAllTask,
metadataCompilationRegistry, metadataCompilationRegistry,
lazy { lazy { resolvedMetadataProviders(fragment) }
fragment.refinesClosure.map {
FragmentResolvedMetadataProvider(
project.tasks.withType<TransformKotlinGranularMetadataForFragment>()
.named(transformFragmentMetadataTaskName(it))
)
}
}
) )
metadataCompilationRegistry.register(fragment, metadataCompilationData)
addSourcesToKotlinCompileTask(
project,
metadataCompilationData.compileKotlinTaskName,
/*FIXME*/ emptyList(),
{ fragment.kotlinSourceRoots },
lazyOf(true)
)
KotlinCommonSourceSetProcessor( KotlinCommonSourceSetProcessor(
metadataCompilationData, metadataCompilationData,
KotlinTasksProvider(), KotlinTasksProvider(),
project.getKotlinPluginVersion() ?: "undefined" project.getKotlinPluginVersion() ?: "undefined"
).run() ).run()
addSourcesToMetadataCompileTask(metadataCompilationData)
return metadataCompilationData metadataCompilationRegistry.registerCommon(fragment, metadataCompilationData)
} }
private fun createNativeMetadataCompilation(
fragment: KotlinGradleFragment,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry
) {
val module = fragment.containingModule
val project = module.project
val metadataCompilationData =
KotlinNativeFragmentMetadataCompilationDataImpl(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
lazy { resolvedMetadataProviders(fragment) }
)
NativeSharedCompilationProcessor(metadataCompilationData).run()
addSourcesToMetadataCompileTask(metadataCompilationData)
metadataCompilationRegistry.registerNative(fragment, metadataCompilationData)
}
private fun addSourcesToMetadataCompileTask(compilationData: AbstractKotlinFragmentMetadataCompilationData<*>) {
val sources = { compilationData.fragment.kotlinSourceRoots }
when (compilationData) {
// Note: this call is invalid for compilations that use Kotlin/Native compile tasks!
is KotlinCommonFragmentMetadataCompilationData -> addSourcesToKotlinCompileTask(
compilationData.project,
compilationData.compileKotlinTaskName,
/*FIXME*/ emptyList(),
sources,
lazyOf(true)
)
is KotlinNativeFragmentMetadataCompilationData -> addSourcesToKotlinNativeCompileTask(
compilationData.project,
compilationData.compileKotlinTaskName,
sources,
lazyOf(true)
)
else -> error("unexpected compilation data $compilationData")
}
}
private fun resolvedMetadataProviders(fragment: KotlinGradleFragment) =
fragment.refinesClosure.map {
FragmentResolvedMetadataProvider(
fragment.project.tasks.withType<TransformKotlinGranularMetadataForFragment>()
.named(transformFragmentMetadataTaskName(it))
)
}
private fun createExtractMetadataTask( private fun createExtractMetadataTask(
project: Project, project: Project,
fragment: KotlinGradleFragment, fragment: KotlinGradleFragment,
@@ -206,7 +246,7 @@ private fun createExtractMetadataTask(
// FIXME: use this function once more than one platform is supported // FIXME: use this function once more than one platform is supported
private fun disableMetadataCompilationIfNotYetSupported( private fun disableMetadataCompilationIfNotYetSupported(
metadataCompilationData: KotlinFragmentMetadataCompilationData metadataCompilationData: AbstractKotlinFragmentMetadataCompilationData<*>
) { ) {
val fragment = metadataCompilationData.fragment val fragment = metadataCompilationData.fragment
val platforms = fragment.containingModule.variantsContainingFragment(fragment).map { it.platformType }.toSet() val platforms = fragment.containingModule.variantsContainingFragment(fragment).map { it.platformType }.toSet()
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2021 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.pm20
fun <T> publishVariantWithSinglePublication(
variant: T
) where T : SingleMavenPublicationHolder, T : KotlinGradleVariant {
}
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.CompilationSourceSetUtil.compilationsBySourceSets import org.jetbrains.kotlin.gradle.plugin.mpp.CompilationSourceSetUtil.compilationsBySourceSets
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleModule
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
import org.jetbrains.kotlin.gradle.plugin.sources.* import org.jetbrains.kotlin.gradle.plugin.sources.*
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
@@ -119,20 +121,6 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
else -> error("unsupported compilation type ${compilation::class.qualifiedName}") else -> error("unsupported compilation type ${compilation::class.qualifiedName}")
} }
private inner class NativeSharedCompilationProcessor(
override val kotlinCompilation: KotlinSharedNativeCompilation
) : KotlinCompilationProcessor<KotlinNativeCompile>(kotlinCompilation) {
private val nativeTargetConfigurator = KotlinNativeTargetConfigurator<KotlinNativeTarget>(kotlinPluginVersion)
override val kotlinTask: TaskProvider<out KotlinNativeCompile> =
with(nativeTargetConfigurator) {
project.createKlibCompilationTask(kotlinCompilation)
}
override fun run() = Unit
}
override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider<out Zip> { override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider<out Zip> {
if (!target.project.isKotlinGranularMetadataEnabled) if (!target.project.isKotlinGranularMetadataEnabled)
return super.createArchiveTasks(target) return super.createArchiveTasks(target)
@@ -486,8 +474,28 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
} }
} }
internal fun Project.createGenerateProjectStructureMetadataTask(moduleClassifier: String? = null): TaskProvider<GenerateProjectStructureMetadata> = internal class NativeSharedCompilationProcessor(
project.registerTask(lowerCamelCaseName("generate", moduleClassifier, "ProjectStructureMetadata")) { task -> override val kotlinCompilation: KotlinNativeFragmentMetadataCompilationData
) : KotlinCompilationProcessor<KotlinNativeCompile>(kotlinCompilation) {
private val nativeTargetConfigurator =
KotlinNativeTargetConfigurator<KotlinNativeTarget>(kotlinCompilation.project.getKotlinPluginVersion() ?: "" /*FIXME*/)
override val kotlinTask: TaskProvider<out KotlinNativeCompile> =
with(nativeTargetConfigurator) {
project.createKlibCompilationTask(kotlinCompilation)
}
override fun run() = Unit
}
internal fun Project.createGenerateProjectStructureMetadataTask(module: KotlinGradleModule): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generate", module.moduleClassifier, "ProjectStructureMetadata")) { task ->
task.lazyKotlinProjectStructureMetadata = lazy { buildProjectStructureMetadata(module) }
}
internal fun Project.createGenerateProjectStructureMetadataTask(): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generateProjectStructureMetadata")) { task ->
task.lazyKotlinProjectStructureMetadata = lazy { checkNotNull(buildKotlinProjectStructureMetadata(project)) } task.lazyKotlinProjectStructureMetadata = lazy { checkNotNull(buildKotlinProjectStructureMetadata(project)) }
} }
@@ -15,6 +15,10 @@ import org.gradle.api.provider.Property
import org.gradle.util.ConfigureUtil import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.CInteropSettings import org.jetbrains.kotlin.gradle.plugin.CInteropSettings
import org.jetbrains.kotlin.gradle.plugin.CInteropSettings.IncludeDirectories import org.jetbrains.kotlin.gradle.plugin.CInteropSettings.IncludeDirectories
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeVariantCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.disambiguateName
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropIdentifier import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropIdentifier
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import java.io.File import java.io.File
@@ -23,7 +27,7 @@ import javax.inject.Inject
open class DefaultCInteropSettings @Inject constructor( open class DefaultCInteropSettings @Inject constructor(
private val project: Project, private val project: Project,
private val name: String, private val name: String,
override val compilation: KotlinNativeCompilation override val compilation: KotlinNativeCompilationData<*>
) : CInteropSettings { ) : CInteropSettings {
inner class DefaultIncludeDirectories : CInteropSettings.IncludeDirectories { inner class DefaultIncludeDirectories : CInteropSettings.IncludeDirectories {
@@ -46,8 +50,8 @@ open class DefaultCInteropSettings @Inject constructor(
internal val identifier: CInteropIdentifier internal val identifier: CInteropIdentifier
get() = CInteropIdentifier(CInteropIdentifier.Scope.create(compilation), name) get() = CInteropIdentifier(CInteropIdentifier.Scope.create(compilation), name)
val target: KotlinNativeTarget val target: KotlinNativeTarget?
get() = compilation.target get() = (compilation as? KotlinNativeCompilation?)?.target
override val dependencyConfigurationName: String override val dependencyConfigurationName: String
get() = compilation.disambiguateName("${name.capitalize()}CInterop") get() = compilation.disambiguateName("${name.capitalize()}CInterop")
@@ -59,7 +63,7 @@ open class DefaultCInteropSettings @Inject constructor(
"cinterop", "cinterop",
compilation.compilationPurpose.takeIf { it != "main" }.orEmpty(), compilation.compilationPurpose.takeIf { it != "main" }.orEmpty(),
name, name,
target.disambiguationClassifier target?.disambiguationClassifier ?: compilation.compilationClassifier
) )
val defFileProperty: Property<File> = project.objects.property(File::class.java) val defFileProperty: Property<File> = project.objects.property(File::class.java)
@@ -129,3 +133,13 @@ open class DefaultCInteropSettings @Inject constructor(
_extraOptsProp.addAll(project.provider { values.map { it.toString() } }) _extraOptsProp.addAll(project.provider { values.map { it.toString() } })
} }
} }
private fun KotlinNativeCompilationData<*>.disambiguateName(simpleName: String): String = when (this) {
is AbstractKotlinNativeCompilation -> (this as AbstractKotlinCompilation<*>).disambiguateName(simpleName)
is KotlinNativeVariantCompilationData -> owner.disambiguateName(simpleName)
else -> lowerCamelCaseName(
this.compilationClassifier,
this.compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
simpleName
)
}
@@ -9,49 +9,58 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.util.ConfigureUtil import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.targets.metadata.getMetadataCompilationForSourceSet import org.jetbrains.kotlin.gradle.targets.metadata.getMetadataCompilationForSourceSet
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
import java.util.concurrent.Callable import java.util.concurrent.Callable
internal class NativeCompileOptions(languageSettingsProvider: () -> LanguageSettingsBuilder) : KotlinCommonOptions {
private val languageSettings: LanguageSettingsBuilder by lazy(languageSettingsProvider)
override var apiVersion: String?
get() = languageSettings.apiVersion
set(value) {
languageSettings.apiVersion = value
}
override var languageVersion: String?
get() = languageSettings.languageVersion
set(value) {
languageSettings.languageVersion = value
}
override var useFir: Boolean
get() = false
set(@Suppress("UNUSED_PARAMETER") value) {}
override var allWarningsAsErrors: Boolean = false
override var suppressWarnings: Boolean = false
override var verbose: Boolean = false
override var freeCompilerArgs: List<String> = listOf()
}
abstract class AbstractKotlinNativeCompilation( abstract class AbstractKotlinNativeCompilation(
target: KotlinTarget, target: KotlinTarget,
val konanTarget: KonanTarget, override val konanTarget: KonanTarget,
compilationName: String compilationName: String
) : AbstractKotlinCompilation<KotlinCommonOptions>(target, compilationName) { ) : AbstractKotlinCompilation<KotlinCommonOptions>(target, compilationName), KotlinNativeCompilationData<KotlinCommonOptions> {
override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { defaultSourceSet.languageSettings } override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { defaultSourceSet.languageSettings }
private class NativeCompileOptions(languageSettingsProvider: () -> LanguageSettingsBuilder) : KotlinCommonOptions {
private val languageSettings: LanguageSettingsBuilder by lazy(languageSettingsProvider)
override var apiVersion: String?
get() = languageSettings.apiVersion
set(value) { languageSettings.apiVersion = value }
override var languageVersion: String?
get() = languageSettings.languageVersion
set(value) { languageSettings.languageVersion = value }
override var useFir: Boolean
get() = false
set(@Suppress("UNUSED_PARAMETER") value) {}
override var allWarningsAsErrors: Boolean = false
override var suppressWarnings: Boolean = false
override var verbose: Boolean = false
override var freeCompilerArgs: List<String> = listOf()
}
override val compileKotlinTask: KotlinNativeCompile override val compileKotlinTask: KotlinNativeCompile
get() = super.compileKotlinTask as KotlinNativeCompile get() = super.compileKotlinTask as KotlinNativeCompile
@@ -59,14 +68,25 @@ abstract class AbstractKotlinNativeCompilation(
override val compileKotlinTaskProvider: TaskProvider<out KotlinNativeCompile> override val compileKotlinTaskProvider: TaskProvider<out KotlinNativeCompile>
get() = super.compileKotlinTaskProvider as TaskProvider<out KotlinNativeCompile> get() = super.compileKotlinTaskProvider as TaskProvider<out KotlinNativeCompile>
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) = override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
compileKotlinTaskProvider.configure { task -> addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources)
task.source(sourceSet.kotlin) }
task.commonSources.from(target.project.files(Callable { if (addAsCommonSources.value) sourceSet.kotlin else emptyList<Any>() }))
}
// Endorsed library controller. // Endorsed library controller.
var enableEndorsedLibs: Boolean = false override var enableEndorsedLibs: Boolean = false
}
internal fun addSourcesToKotlinNativeCompileTask(
project: Project,
taskName: String,
sourceFiles: () -> Iterable<File>,
addAsCommonSources: Lazy<Boolean>
) {
project.tasks.withType(KotlinNativeCompile::class.java).matching { it.name == taskName }.configureEach { task ->
task.source(sourceFiles)
task.commonSources.from(project.files(Callable { if (addAsCommonSources.value) sourceFiles() else emptyList() }))
}
} }
class KotlinNativeCompilation( class KotlinNativeCompilation(
@@ -117,6 +137,7 @@ class KotlinNativeCompilation(
} }
class KotlinSharedNativeCompilation(override val target: KotlinMetadataTarget, val konanTargets: List<KonanTarget>, name: String) : class KotlinSharedNativeCompilation(override val target: KotlinMetadataTarget, val konanTargets: List<KonanTarget>, name: String) :
KotlinNativeFragmentMetadataCompilationData,
AbstractKotlinNativeCompilation( AbstractKotlinNativeCompilation(
target, target,
// TODO: this will end up as '-target' argument passed to K2Native, which is wrong. // TODO: this will end up as '-target' argument passed to K2Native, which is wrong.
@@ -137,4 +158,7 @@ class KotlinSharedNativeCompilation(override val target: KotlinMetadataTarget, v
} }
project.files(friendSourceSets.mapNotNull { project.getMetadataCompilationForSourceSet(it)?.output?.classesDirs }) project.files(friendSourceSets.mapNotNull { project.getMetadataCompilationForSourceSet(it)?.output?.classesDirs })
}) })
override val isActive: Boolean
get() = true // old plugin only creates necessary compilations
} }
@@ -10,13 +10,14 @@ import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.Usage
import org.gradle.jvm.tasks.Jar import org.gradle.jvm.tasks.Jar
import org.gradle.util.WrapUtil import org.gradle.util.WrapUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isNativeShared
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.variantsContainingFragment
import org.jetbrains.kotlin.gradle.targets.metadata.* import org.jetbrains.kotlin.gradle.targets.metadata.*
import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
@@ -136,26 +137,49 @@ open class KotlinNativeTarget @Inject constructor(
} }
} }
internal fun getHostSpecificSourceSets(project: Project): List<KotlinSourceSet> { private val hostManager by lazy { HostManager() }
val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project)
val enabledByHost = HostManager().enabledByHost private fun isHostSpecificKonanTargetsSet(konanTargets: Iterable<KonanTarget>): Boolean {
val enabledByHost = hostManager.enabledByHost
val allHosts = enabledByHost.keys val allHosts = enabledByHost.keys
fun canBeBuiltOnHosts(konanTarget: KonanTarget) = enabledByHost.filterValues { konanTarget in it }.keys fun canBeBuiltOnHosts(konanTarget: KonanTarget) = enabledByHost.filterValues { konanTarget in it }.keys
return konanTargets.flatMapTo(mutableSetOf(), ::canBeBuiltOnHosts) != allHosts
}
return project.kotlinExtension.sourceSets.filter { sourceSet -> private fun <T> getHostSpecificElements(
if (sourceSet !in compilationsBySourceSet) return@filter false fragments: Iterable<T>,
isNativeShared: (T) -> Boolean,
getKonanTargets: (T) -> Set<KonanTarget>
): Set<T> = fragments.filterTo(mutableSetOf()) { isNativeShared(it) && isHostSpecificKonanTargetsSet(getKonanTargets(it)) }
// If the source set participates in compilations such that some host can't run either of them, then on that host, internal fun getHostSpecificFragments(
// we can't analyze the source set, so the source set's metadata can't be published from that host, and therefore module: KotlinGradleModule
// we consider it platform-specific and publish as a part of the Native targets where the source set takes part, ): Set<KotlinGradleFragment> = getHostSpecificElements<KotlinGradleFragment>(
// not the common metadata artifact; module.fragments,
val platformCompilations = compilationsBySourceSet.getValue(sourceSet).filter { it !is KotlinMetadataCompilation } isNativeShared = { it.isNativeShared() },
val nativeCompilations = platformCompilations.filterIsInstance<KotlinNativeCompilation>() getKonanTargets = {
val nativeEnabledOn = nativeCompilations.flatMapTo(mutableSetOf()) { compilation -> canBeBuiltOnHosts(compilation.konanTarget) } val nativeVariants = module.variantsContainingFragment(it).filterIsInstance<KotlinNativeVariantInternal>()
platformCompilations == nativeCompilations && allHosts != nativeEnabledOn nativeVariants.mapTo(mutableSetOf()) { it.konanTarget }
} }
)
internal fun getHostSpecificSourceSets(project: Project): Set<KotlinSourceSet> {
val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project).mapValues { (_, compilations) ->
compilations.filter { it !is KotlinMetadataCompilation<*> }
}
return getHostSpecificElements(
project.kotlinExtension.sourceSets,
isNativeShared = { sourceSet ->
val compilations = compilationsBySourceSet[sourceSet].orEmpty()
compilations.isNotEmpty() && compilations.all { it.platformType == KotlinPlatformType.native }
},
getKonanTargets = { sourceSet ->
compilationsBySourceSet[sourceSet].orEmpty()
.filterIsInstance<KotlinNativeCompilation>()
.mapTo(mutableSetOf()) { it.konanTarget }
}
)
} }
abstract class KotlinNativeTargetWithTests<T : KotlinNativeBinaryTestRun>( abstract class KotlinNativeTargetWithTests<T : KotlinNativeBinaryTestRun>(
@@ -7,6 +7,7 @@
package org.jetbrains.kotlin.gradle.plugin package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.NamedDomainObjectCollection
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPI
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.KOTLIN_NATIVE_IGNORE_INCORRECT_DEPENDENCIES 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.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.registerAssembleAppleFrameworkTask import org.jetbrains.kotlin.gradle.plugin.mpp.apple.registerAssembleAppleFrameworkTask
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.targets.native.* import org.jetbrains.kotlin.gradle.targets.native.*
import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask
@@ -51,10 +53,10 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
createTestCompilation = true createTestCompilation = true
) { ) {
private fun Project.klibOutputDirectory( private fun Project.klibOutputDirectory(
compilation: AbstractKotlinNativeCompilation compilation: KotlinCompilationData<*>
): File { ): File {
val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() val targetSubDirectory = compilation.compilationClassifier?.let { "$it/" }.orEmpty()
return buildDir.resolve("classes/kotlin/$targetSubDirectory${compilation.name}") return buildDir.resolve("classes/kotlin/$targetSubDirectory${compilation.compilationPurpose}")
} }
private fun addCompilerPlugins(compilation: AbstractKotlinNativeCompilation) { private fun addCompilerPlugins(compilation: AbstractKotlinNativeCompilation) {
@@ -73,9 +75,25 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
} }
} }
// region Artifact creation. private val KotlinNativeCompilationData<*>.apiElementsConfigurationName: String
get() = when (val dataOwner = owner) {
is KotlinGradleVariant -> dataOwner.apiElementsConfigurationName
is KotlinTarget -> dataOwner.apiElementsConfigurationName
else -> error("unexpected owner of $this")
}
internal fun Project.createRegularKlibArtifact(
compilation: KotlinNativeCompilationData<*>,
compileTask: TaskProvider<out KotlinNativeCompile>
) = createKlibArtifact(compilation, compileTask.map { it.outputFile.get() }, null, compileTask)
internal fun Project.createCInteropKlibArtifact(
interop: DefaultCInteropSettings,
interopTask: TaskProvider<out CInteropProcess>
) = createKlibArtifact(interop.compilation, interopTask.map { it.outputFile }, "cinterop-${interop.name}", interopTask, copy = true)
private fun Project.createKlibArtifact( private fun Project.createKlibArtifact(
compilation: KotlinNativeCompilation, compilation: KotlinNativeCompilationData<*>,
artifactFile: Provider<File>, artifactFile: Provider<File>,
classifier: String?, classifier: String?,
producingTask: TaskProvider<*>, producingTask: TaskProvider<*>,
@@ -85,14 +103,14 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
return return
} }
val apiElements = configurations.getByName(compilation.target.apiElementsConfigurationName) val apiElements = configurations.getByName(compilation.apiElementsConfigurationName)
val realProducingTask: TaskProvider<*> val realProducingTask: TaskProvider<*>
// TODO: Someone remove this HACK PLEASE! // TODO: Someone remove this HACK PLEASE!
val realArtifactFile = if (copy) { val realArtifactFile = if (copy) {
realProducingTask = project.registerTask<Copy>("copy${producingTask.name.capitalize()}") { realProducingTask = project.registerTask<Copy>("copy${producingTask.name.capitalize()}") {
val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() val targetSubDirectory = compilation.compilationClassifier?.let { "$it/" }.orEmpty()
it.destinationDir = project.buildDir.resolve("libs/$targetSubDirectory${compilation.name}") it.destinationDir = project.buildDir.resolve("libs/$targetSubDirectory${compilation.compilationPurpose}")
it.from(artifactFile) it.from(artifactFile)
it.dependsOn(producingTask) it.dependsOn(producingTask)
} }
@@ -104,7 +122,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
with(apiElements) { with(apiElements) {
val klibArtifact = project.artifacts.add(apiElements.name, realArtifactFile) { artifact -> val klibArtifact = project.artifacts.add(apiElements.name, realArtifactFile) { artifact ->
artifact.name = compilation.name artifact.name = compilation.compilationPurpose
artifact.extension = "klib" artifact.extension = "klib"
artifact.type = "klib" artifact.type = "klib"
artifact.classifier = classifier artifact.classifier = classifier
@@ -115,18 +133,6 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB) attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
} }
} }
private fun Project.createRegularKlibArtifact(
compilation: KotlinNativeCompilation,
compileTask: TaskProvider<out KotlinNativeCompile>
) = createKlibArtifact(compilation, compileTask.map { it.outputFile.get() }, null, compileTask)
private fun Project.createCInteropKlibArtifact(
interop: DefaultCInteropSettings,
interopTask: TaskProvider<out CInteropProcess>
) = createKlibArtifact(interop.compilation, interopTask.map { it.outputFile }, "cinterop-${interop.name}", interopTask, copy = true)
// endregion.
// region Task creation. // region Task creation.
private fun Project.createLinkTask(binary: NativeBinary) { private fun Project.createLinkTask(binary: NativeBinary) {
val result = registerTask<KotlinNativeLink>( val result = registerTask<KotlinNativeLink>(
@@ -258,12 +264,12 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
} }
} }
internal fun Project.createKlibCompilationTask(compilation: AbstractKotlinNativeCompilation): TaskProvider<KotlinNativeCompile> { internal fun Project.createKlibCompilationTask(compilation: KotlinNativeCompilationData<*>): TaskProvider<KotlinNativeCompile> {
val compileTaskProvider = registerTask<KotlinNativeCompile>( val compileTaskProvider = registerTask<KotlinNativeCompile>(
compilation.compileKotlinTaskName, listOf(compilation) compilation.compileKotlinTaskName, listOf(compilation)
) { ) {
it.group = BasePlugin.BUILD_GROUP it.group = BasePlugin.BUILD_GROUP
it.description = "Compiles a klibrary from the '${compilation.name}' " + it.description = "Compiles a klibrary from the '${compilation.compilationPurpose}' " +
"compilation for target '${compilation.platformType.name}'." "compilation for target '${compilation.platformType.name}'."
it.enabled = compilation.konanTarget.enabledOnCurrentHost it.enabled = compilation.konanTarget.enabledOnCurrentHost
@@ -275,33 +281,39 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
project.files(compileTaskProvider.map { it.outputFile }) project.files(compileTaskProvider.map { it.outputFile })
} }
project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTaskProvider) project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTaskProvider)
if (compilation.isMain()) { if (compilation.isMainCompilationData()) {
compilation as? KotlinNativeCompilation ?: error("Main shared-Native compilation is not yet supported!") if (compilation is KotlinNativeCompilation) {
project.tasks.getByName(compilation.target.artifactsTaskName).apply {
project.tasks.getByName(compilation.target.artifactsTaskName).apply { dependsOn(compileTaskProvider)
dependsOn(compileTaskProvider) }
} }
project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply { project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply {
dependsOn(compileTaskProvider) dependsOn(compileTaskProvider)
} }
createRegularKlibArtifact(compilation, compileTaskProvider) createRegularKlibArtifact(compilation, compileTaskProvider)
} }
addCompilerPlugins(compilation) if (compilation is AbstractKotlinNativeCompilation) {
// FIXME: support compiler plugins for PM20
addCompilerPlugins(compilation)
}
return compileTaskProvider return compileTaskProvider
} }
private fun Project.createCInteropTasks(compilation: KotlinNativeCompilation) { // FIXME support creating interop tasks for PM20
compilation.cinterops.all { interop -> private fun Project.createCInteropTasks(
compilation: KotlinNativeCompilation,
cinterops: NamedDomainObjectCollection<DefaultCInteropSettings>
) {
cinterops.all { interop ->
val interopTask = registerTask<CInteropProcess>(interop.interopProcessingTaskName, listOf(interop)) { val interopTask = registerTask<CInteropProcess>(interop.interopProcessingTaskName, listOf(interop)) {
it.destinationDir = provider { klibOutputDirectory(compilation).resolve("cinterop") } it.destinationDir = provider { klibOutputDirectory(compilation).resolve("cinterop") }
it.group = INTEROP_GROUP it.group = INTEROP_GROUP
it.description = "Generates Kotlin/Native interop library '${interop.name}' " + it.description = "Generates Kotlin/Native interop library '${interop.name}' " +
"for compilation '${compilation.name}'" + "for compilation '${compilation.compilationPurpose}'" +
"of target '${it.konanTarget.name}'." "of target '${it.konanTarget.name}'."
it.enabled = compilation.konanTarget.enabledOnCurrentHost it.enabled = compilation.konanTarget.enabledOnCurrentHost
} }
@@ -377,7 +389,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
protected fun configureCInterops(target: KotlinNativeTarget): Unit = with(target.project) { protected fun configureCInterops(target: KotlinNativeTarget): Unit = with(target.project) {
target.compilations.all { compilation -> target.compilations.all { compilation ->
createCInteropTasks(compilation) createCInteropTasks(compilation, compilation.cinterops)
compilation.cinterops.all { compilation.cinterops.all {
defineConfigurationsForCInterop(compilation, it, target, configurations) defineConfigurationsForCInterop(compilation, it, target, configurations)
} }
@@ -172,7 +172,8 @@ private fun CInteropProcess.toGist(): CInteropGist {
return CInteropGist( return CInteropGist(
identifier = settings.identifier, identifier = settings.identifier,
konanTarget = konanTarget, konanTarget = konanTarget,
sourceSets = project.provider { settings.compilation.kotlinSourceSetsIncludingDefault }, // FIXME support cinterop with PM20
sourceSets = project.provider { (settings.compilation as? KotlinCompilation<*>)?.kotlinSourceSetsIncludingDefault },
libraryFile = outputFileProvider, libraryFile = outputFileProvider,
/** /**
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.gradle.targets.native.internal package org.jetbrains.kotlin.gradle.targets.native.internal
import org.gradle.api.tasks.Input import org.gradle.api.tasks.Input
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.utils.UnsafeApi import org.jetbrains.kotlin.gradle.utils.UnsafeApi
import java.io.Serializable import java.io.Serializable
@@ -20,7 +20,7 @@ internal data class CInteropIdentifier internal constructor(
class Scope @UnsafeApi internal constructor(val name: String) : Serializable { class Scope @UnsafeApi internal constructor(val name: String) : Serializable {
companion object { companion object {
@OptIn(UnsafeApi::class) @OptIn(UnsafeApi::class)
fun create(compilation: KotlinCompilation<*>): Scope { fun create(compilation: KotlinCompilationData<*>): Scope {
return Scope("compilation/${compilation.compileKotlinTaskName}") return Scope("compilation/${compilation.compileKotlinTaskName}")
} }
} }
@@ -26,6 +26,9 @@ import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer
import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.getValue
@@ -113,7 +116,7 @@ private fun Collection<File>.filterKlibsPassedToCompiler(project: Project) = fil
} }
// endregion // endregion
abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : AbstractKotlinNativeCompilation> : AbstractCompile() { abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : KotlinNativeCompilationData<*>> : AbstractCompile() {
@get:Internal @get:Internal
abstract val compilation: K abstract val compilation: K
@@ -139,7 +142,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : Abst
} }
private val isSharedCompilation by project.provider { private val isSharedCompilation by project.provider {
compilation is KotlinSharedNativeCompilation compilation is KotlinNativeFragmentMetadataCompilationData
} }
// Inputs and outputs // Inputs and outputs
@@ -178,7 +181,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : Abst
@get:Internal @get:Internal
val languageSettings: LanguageSettingsBuilder by project.provider { val languageSettings: LanguageSettingsBuilder by project.provider {
compilation.defaultSourceSet.languageSettings compilation.languageSettings
} }
@get:Input @get:Input
@@ -233,7 +236,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : Abst
get() = buildCommonArgs(true) get() = buildCommonArgs(true)
private val languageSettingsBuilder by project.provider { private val languageSettingsBuilder by project.provider {
compilation.defaultSourceSet.languageSettings compilation.languageSettings
} }
// Args used by both the compiler and IDEA. // Args used by both the compiler and IDEA.
@@ -343,8 +346,8 @@ open class KotlinNativeCompile
constructor( constructor(
@Internal @Internal
@Transient // can't be serialized for Gradle configuration cache @Transient // can't be serialized for Gradle configuration cache
final override val compilation: AbstractKotlinNativeCompilation final override val compilation: KotlinNativeCompilationData<*>
) : AbstractKotlinNativeCompile<KotlinCommonOptions, AbstractKotlinNativeCompilation>(), ) : AbstractKotlinNativeCompile<KotlinCommonOptions, KotlinNativeCompilationData<*>>(),
KotlinCompile<KotlinCommonOptions> { KotlinCompile<KotlinCommonOptions> {
@get:Input @get:Input
@@ -357,7 +360,11 @@ constructor(
override val debuggable = true override val debuggable = true
@get:Internal @get:Internal
override val baseName: String by project.provider { if (compilation.isMain()) project.name else "${project.name}_${compilation.name}" } override val baseName: String by project.provider {
if (compilation.isMainCompilationData())
project.name
else "${project.name}_${compilation.compilationPurpose}"
}
// Store as an explicit provider in order to allow Gradle Instant Execution to capture the state // Store as an explicit provider in order to allow Gradle Instant Execution to capture the state
// private val allSourceProvider = compilation.map { project.files(it.allSources).asFileTree } // private val allSourceProvider = compilation.map { project.files(it.allSources).asFileTree }
@@ -390,10 +397,7 @@ constructor(
private val friendModule: FileCollection by project.provider { private val friendModule: FileCollection by project.provider {
project.files( project.files(compilation.friendPaths)
compilation.associateWithTransitiveClosure.map { it.output.allOutputs },
compilation.friendArtifacts
)
} }
// endregion. // endregion.
@@ -934,7 +938,7 @@ open class CInteropProcess @Inject constructor(@get:Internal val settings: Defau
val baseKlibName: String val baseKlibName: String
@Input get() { @Input get() {
val compilationPrefix = settings.compilation.let { val compilationPrefix = settings.compilation.let {
if (it.isMain()) project.name else it.name if (it.isMainCompilationData()) project.name else it.compilationPurpose
} }
return "$compilationPrefix-cinterop-$interopName" return "$compilationPrefix-cinterop-$interopName"
} }
@@ -24,8 +24,7 @@ import org.gradle.api.tasks.PathSensitivity
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompile import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
@@ -34,7 +33,8 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinFragmentMetadataCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.AbstractKotlinFragmentMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinMetadataCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.refinesClosure import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.refinesClosure
import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
@@ -63,7 +63,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
args.moduleName = this@KotlinCompileCommon.moduleName args.moduleName = this@KotlinCompileCommon.moduleName
if ((taskData.compilation as? KotlinCommonCompilation)?.isKlibCompilation == true || if ((taskData.compilation as? KotlinCommonCompilation)?.isKlibCompilation == true ||
taskData.compilation is KotlinFragmentMetadataCompilationData taskData.compilation is KotlinMetadataCompilationData
) { ) {
args.expectActualLinker = true args.expectActualLinker = true
} }
@@ -84,13 +84,10 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
} }
private fun outputPathsFromMetadataCompilationsOf(sourceSets: Iterable<KotlinSourceSet>): List<File> { private fun outputPathsFromMetadataCompilationsOf(sourceSets: Iterable<KotlinSourceSet>): List<File> {
val target = taskData.compilation.owner val metadataTarget = taskData.compilation.owner as KotlinTarget
return when (target) { return sourceSets
is KotlinTarget -> sourceSets .mapNotNull { sourceSet -> metadataTarget.compilations.findByName(sourceSet.name)?.output?.classesDirs }
.mapNotNull { sourceSet -> target.compilations.findByName(sourceSet.name)?.output?.classesDirs } .flatten()
.flatten()
else -> error("unexpected compilation owner") // FIXME support PM20 variant
}
} }
@get:PathSensitive(PathSensitivity.RELATIVE) @get:PathSensitive(PathSensitivity.RELATIVE)
@@ -101,7 +98,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet
outputPathsFromMetadataCompilationsOf(defaultKotlinSourceSet.resolveAllDependsOnSourceSets()) outputPathsFromMetadataCompilationsOf(defaultKotlinSourceSet.resolveAllDependsOnSourceSets())
} }
is KotlinFragmentMetadataCompilationData -> { is AbstractKotlinFragmentMetadataCompilationData -> {
val fragment = compilation.fragment val fragment = compilation.fragment
project.files( project.files(
fragment.refinesClosure.minus(fragment).map { fragment.refinesClosure.minus(fragment).map {
@@ -109,7 +106,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
} }
) )
} }
else -> error("unexpected compilation type") // FIXME support PM20 variant else -> error("unexpected compilation type")
} }
} }
@@ -25,15 +25,15 @@ interface KotlinDependencyGraphResolver {
fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution
} }
sealed class DependencyGraphResolution(val requestingModule: KotlinModule) { sealed class DependencyGraphResolution(open val requestingModule: KotlinModule) {
class Unknown(requestingModule: KotlinModule) : DependencyGraphResolution(requestingModule) class Unknown(requestingModule: KotlinModule) : DependencyGraphResolution(requestingModule)
class DependencyGraph(requestingModule: KotlinModule, val root: DependencyGraphNode): DependencyGraphResolution(requestingModule) open class DependencyGraph(requestingModule: KotlinModule, open val root: DependencyGraphNode): DependencyGraphResolution(requestingModule)
} }
// TODO: should this be a single graph for all dependency scopes as well, not just for all fragments? // TODO: should this be a single graph for all dependency scopes as well, not just for all fragments?
class DependencyGraphNode( open class DependencyGraphNode(
val module: KotlinModule, open val module: KotlinModule,
val dependenciesByFragment: Map<KotlinModuleFragment, Iterable<DependencyGraphNode>> open val dependenciesByFragment: Map<KotlinModuleFragment, Iterable<DependencyGraphNode>>
) { ) {
override fun toString(): String = "node ${module}" override fun toString(): String = "node ${module}"
} }