From f029179fe07e9db56b02f9ae806234db24c51d5d Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Fri, 19 Mar 2021 18:24:03 +0300 Subject: [PATCH] Add basic support for Kotlin/Native variants to the PM20 Gradle plugin --- .../kotlin/gradle/plugin/CinteropSettings.kt | 3 +- .../kotlin/gradle/plugin/KotlinPlugin.kt | 6 +- .../plugin/mpp/GradleProjectModuleBuilder.kt | 8 +- .../mpp/GranularMetadataTransformation.kt | 4 +- .../mpp/KotlinProjectStructureMetadata.kt | 13 +- .../gradle/plugin/mpp/kotlinCompilations.kt | 2 +- .../mpp/pm20/DependencyGraphResolver.kt | 44 +++- .../plugin/mpp/pm20/DependencyResolution.kt | 3 +- .../pm20/FragmentGranularMetadataResolver.kt | 68 ++++-- .../gradle/plugin/mpp/pm20/GradlePlugin.kt | 24 +- .../KotlinFragmentMetadataCompilationData.kt | 115 ---------- .../plugin/mpp/pm20/KotlinJvmVariant.kt | 52 +---- .../mpp/pm20/KotlinMetadataCompilationData.kt | 206 ++++++++++++++++++ .../plugin/mpp/pm20/KotlinNativeVariant.kt | 77 +++++++ .../mpp/pm20/KotlinNativeVariantFactory.kt | 1 + .../mpp/pm20/abstractVariantFactories.kt | 13 +- .../plugin/mpp/pm20/abstractVariants.kt | 3 + .../plugin/mpp/pm20/fragmentFactories.kt | 2 +- .../mpp/pm20/fragmentsMetadataCompilation.kt | 96 +++++--- .../plugin/mpp/pm20/variantPublishing.kt | 12 + .../KotlinMetadataTargetConfigurator.kt | 40 ++-- .../targets/native/DefaultCInteropSettings.kt | 22 +- .../targets/native/KotlinNativeCompilation.kt | 84 ++++--- .../targets/native/KotlinNativeTarget.kt | 56 +++-- .../native/KotlinNativeTargetConfigurator.kt | 82 ++++--- .../native/internal/CInteropCommonizerTask.kt | 3 +- .../native/internal/CInteropIdentifier.kt | 4 +- .../targets/native/tasks/KotlinNativeTasks.kt | 28 ++- .../gradle/tasks/KotlinCompileCommon.kt | 23 +- .../src/main/kotlin/DependencyResolution.kt | 10 +- 30 files changed, 713 insertions(+), 391 deletions(-) delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinFragmentMetadataCompilationData.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/variantPublishing.kt diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/CinteropSettings.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/CinteropSettings.kt index f997c36a57e..83b21abd081 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/CinteropSettings.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/CinteropSettings.kt @@ -10,6 +10,7 @@ import org.gradle.api.Action import org.gradle.api.Named import org.gradle.api.file.FileCollection import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData interface CInteropSettings : Named { @@ -22,7 +23,7 @@ interface CInteropSettings : Named { } // TODO: Provide an interface for native compilations. - val compilation: KotlinCompilation + val compilation: KotlinCompilationData val dependencyConfigurationName: String var dependencyFiles: FileCollection diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 2ca47d9ae62..f18e5f7d07e 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -36,7 +36,7 @@ import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder import org.jetbrains.kotlin.gradle.plugin.mpp.* 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.targets.js.dsl.KotlinJsBinaryMode import org.jetbrains.kotlin.gradle.targets.js.ir.* @@ -281,7 +281,7 @@ internal class Kotlin2JsSourceSetProcessor( kotlinOptions.freeCompilerArgs.contains(PRODUCE_ZIPPED_KLIB) ) { // 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 } else { "${project.name}_${kotlinCompilation.compilationPurpose}" @@ -366,7 +366,7 @@ internal class KotlinCommonSourceSetProcessor( override fun doTargetSpecificProcessing() { project.tasks.named(kotlinCompilation.compileAllTaskName).dependsOn(kotlinTask) // can be missing (e.g. in case of tests) - if ((kotlinCompilation as? AbstractKotlinCompilation<*>)?.isMain() == true) { + if ((kotlinCompilation as? AbstractKotlinCompilation<*>)?.isMainCompilationData() == true) { project.locateTask(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt index 852a1da7784..c5f9a2c0632 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt @@ -281,11 +281,7 @@ class GradleModuleVariantResolver(val project: Project) : ModuleVariantResolver val compileClasspath = getCompileDependenciesConfigurationForVariant(project, requestingVariant) - // TODO optimize O(n) search, store the mapping - val component = compileClasspath.incoming.resolutionResult.allComponents.find { it.id.matchesModule(dependencyModule) } - ?: return VariantResolution.NotRequested(requestingVariant, dependencyModule) - - val dependencyModuleId = ModuleIds.fromComponent(project, component) + val dependencyModuleId = dependencyModule.moduleIdentifier // FIXME check composite builds, it's likely that resolvedVariantProvider fails on them? val resolvedGradleVariantName = resolvedVariantProvider.getResolvedVariantName(dependencyModuleId, compileClasspath) val kotlinVariantName = when (dependencyModule) { @@ -323,7 +319,7 @@ class GradleModuleVariantResolver(val project: Project) : ModuleVariantResolver project.configurations.getByName(compilation.compileDependencyConfigurationName) } 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") } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index 4aee438be87..9fd84c1d637 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -427,7 +427,7 @@ private class IncludedBuildMetadataExtractor( GlobalProjectStructureMetadataStorage.getProjectStructureMetadata(project, id.build.name, id.projectPath) } -private open class JarArtifactMppDependencyMetadataExtractor( +internal open class JarArtifactMppDependencyMetadataExtractor( project: Project, dependency: ResolvedComponentResult, val primaryArtifact: File @@ -602,7 +602,7 @@ private fun mppDependencyMetadataExtractor( return when { moduleId is ProjectComponentIdentifier -> when { moduleId.build.isCurrentBuild -> - ProjectMppDependencyMetadataExtractor(project, actualComponent, project.project(moduleId.projectPath)) + ProjectMppDependencyMetadataExtractor(project, actualComponent, moduleIdentifier, project.project(moduleId.projectPath)) metadataArtifact != null -> IncludedBuildMetadataExtractor(project, actualComponent, metadataArtifact) else -> null diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt index 480ad4ef1f8..81ae2c203ce 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt @@ -10,18 +10,16 @@ import com.google.gson.JsonObject import com.google.gson.JsonParser import com.google.gson.stream.JsonWriter import org.gradle.api.Project -import org.gradle.api.provider.Provider import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal 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.topLevelExtension import org.jetbrains.kotlin.gradle.dsl.topLevelExtensionOrNull 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.refinesClosure 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.targets.metadata.dependsOnClosureWithInterCompilationDependencies import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations @@ -133,10 +131,7 @@ data class KotlinProjectStructureMetadata( internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjectStructureMetadata? { val topLevelExtensionOrNull = project.topLevelExtensionOrNull - if (topLevelExtensionOrNull is KotlinPm20ProjectExtension) { - // FIXME: get module by ID, don't just take the main module - return buildProjectStructureMetadata(topLevelExtensionOrNull.main) - } + require(topLevelExtensionOrNull is KotlinMultiplatformExtension) { "this function only works with the stable plugin" } val sourceSetsWithMetadataCompilations = project.multiplatformExtensionOrNull?.targets?.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME)?.compilations?.associate { @@ -195,7 +190,7 @@ internal fun buildProjectStructureMetadata(module: KotlinGradleModule): KotlinPr val kotlinFragmentsPerKotlinVariant = module.variants.associate { variant -> variant.name to variant.refinesClosure.map { it.name }.toSet() } 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 dependencies on auxiliary modules @@ -211,7 +206,7 @@ internal fun buildProjectStructureMetadata(module: KotlinGradleModule): KotlinPr fragmentRefinesRelation, module.fragments.associate { it.name to SourceSetMetadataLayout.KLIB }, fragmentDependencies, - emptySet(), + getHostSpecificFragments(module).mapTo(mutableSetOf()) { it.name }, isPublishedAsRoot = true ) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt index ece42ea2b50..6d4a407c416 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt @@ -288,7 +288,7 @@ abstract class AbstractKotlinCompilation( override val project: Project get() = target.project - override val owner: Any? + override val owner: KotlinTarget get() = target override val compilationClassifier: String? diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt index dfbf6364e4b..c8f92cdc01a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyGraphResolver.kt @@ -39,15 +39,18 @@ class GradleKotlinDependencyGraphResolver( configurationToResolveMetadataDependencies(project, requestingModule) override fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution { - if (!requestingModule.representsProject(project)) + if (requestingModule !is KotlinGradleModule) return DependencyGraphResolution.Unknown(requestingModule) + return resolveAsGraph(requestingModule) + } + private fun resolveAsGraph(requestingModule: KotlinGradleModule): GradleDependencyGraph { val excludeLegacyMetadataModulesFromResult = mutableSetOf() - val nodeByModuleId = mutableMapOf() + val nodeByModuleId = mutableMapOf() - fun nodeFromComponent(component: ResolvedComponentResult, isRoot: Boolean /*refactor*/): DependencyGraphNode { - val id = component.toModuleIdentifier() + fun nodeFromComponent(component: ResolvedComponentResult, isRoot: Boolean /*refactor me*/): GradleDependencyGraphNode { + val id = component.toSingleModuleIdentifier() return nodeByModuleId.getOrPut(id) { val module = if (isRoot) requestingModule @@ -55,14 +58,20 @@ class GradleKotlinDependencyGraphResolver( .takeIf { component !in excludeLegacyMetadataModulesFromResult } ?: buildSyntheticModule(component, component.variants.singleOrNull()?.displayName ?: "default") - val componentContainingTransitiveDependencies = + val metadataSourceComponent = (module as? ExternalImportedKotlinModule) ?.takeIf { it.hasLegacyMetadataModule } ?.let { (component.dependencies.singleOrNull() as? ResolvedDependencyResult)?.selected } ?: component - val resolvedComponentDependencies = componentContainingTransitiveDependencies.dependencies + val dependenciesRequestedByModule = + module.fragments.flatMap { fragment -> fragment.declaredModuleDependencies.map { it.moduleIdentifier } }.toSet() + + val resolvedComponentDependencies = metadataSourceComponent.dependencies .filterIsInstance() + // 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 } } .toMap() @@ -72,13 +81,30 @@ class GradleKotlinDependencyGraphResolver( deps.mapNotNull { resolvedComponentDependencies[it.moduleIdentifier] }.map { nodeFromComponent(it, isRoot = false) } } - DependencyGraphNode(module, nodeDependenciesMap) + GradleDependencyGraphNode( + module, + component, + metadataSourceComponent, + nodeDependenciesMap + ) } } - return DependencyGraphResolution.DependencyGraph( + return GradleDependencyGraph( requestingModule, nodeFromComponent(configurationToResolve(requestingModule).incoming.resolutionResult.root, isRoot = true) ) } -} \ No newline at end of file +} + +class GradleDependencyGraphNode( + override val module: KotlinModule, + val selectedComponent: ResolvedComponentResult, + val metadataSourceComponent: ResolvedComponentResult?, + override val dependenciesByFragment: Map> +) : DependencyGraphNode(module, dependenciesByFragment) + +class GradleDependencyGraph( + override val requestingModule: KotlinGradleModule, + override val root: GradleDependencyGraphNode +) : DependencyGraphResolution.DependencyGraph(requestingModule, root) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyResolution.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyResolution.kt index c2f14557d73..451667e8f60 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyResolution.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/DependencyResolution.kt @@ -163,7 +163,8 @@ internal class ExternalSyntheticKotlinModule(private val moduleData: BasicKotlin internal class ExternalImportedKotlinModule( private val moduleData: BasicKotlinModule, - val projectStructureMetadata: KotlinProjectStructureMetadata + val projectStructureMetadata: KotlinProjectStructureMetadata, + val hostSpecificFragments: Set ) : KotlinModule by moduleData { val hasLegacyMetadataModule = !projectStructureMetadata.isPublishedAsRoot diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/FragmentGranularMetadataResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/FragmentGranularMetadataResolver.kt index c6f4ee33edc..e3d8b8b93a9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/FragmentGranularMetadataResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/FragmentGranularMetadataResolver.kt @@ -51,14 +51,12 @@ internal class FragmentGranularMetadataResolver( if (dependencyGraph is DependencyGraphResolution.Unknown) 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 requestedDependencies = dependencyGraph.root.dependenciesByFragment.filterKeys { it in fragmentsToInclude }.values.flatten() - val visited = mutableSetOf() - val fragmentResolutionQueue = ArrayDeque().apply { - addAll(requestedDependencies) - } + val visited = mutableSetOf() + val fragmentResolutionQueue = ArrayDeque(requestedDependencies) val results = mutableSetOf() @@ -69,18 +67,15 @@ internal class FragmentGranularMetadataResolver( val dependencyModule = dependencyNode.module val fragmentVisibility = fragmentResolver.getChosenFragments(requestingFragment, dependencyModule) - val visibleFragments = (fragmentVisibility as? FragmentResolution.ChosenFragments)?.visibleFragments?.toList().orEmpty() - val variantResolutions = - (fragmentVisibility as? FragmentResolution.ChosenFragments)?.variantResolutions?.associateBy { it.requestingVariant } + val chosenFragments = fragmentVisibility as? FragmentResolution.ChosenFragments + val visibleFragments = chosenFragments?.visibleFragments?.toList().orEmpty() val visibleTransitiveDependencies = dependencyNode.dependenciesByFragment.filterKeys { it in visibleFragments }.values.flattenTo(mutableSetOf()) - //FIXME host-specific fragments - fragmentResolutionQueue.addAll(visibleTransitiveDependencies.filter { it !in visited }) - val resolvedComponentResult = resolvedComponentsByModuleId.getValue(dependencyModule.moduleIdentifier) + val resolvedComponentResult = dependencyNode.selectedComponent val isResolvedAsProject = resolvedComponentResult.toProjectOrNull(project) val result = when (dependencyModule) { is ExternalSyntheticKotlinModule -> { @@ -90,14 +85,7 @@ internal class FragmentGranularMetadataResolver( val projectStructureMetadata = (dependencyModule as? ExternalImportedKotlinModule)?.projectStructureMetadata ?: checkNotNull(getProjectStructureMetadata(project, resolvedComponentResult, configurationToResolve)) - // FIXME host-specific metadata!!! - - val metadataSourceComponent = when { - dependencyModule is ExternalImportedKotlinModule && dependencyModule.hasLegacyMetadataModule -> - resolvedComponentResult.dependencies.filterIsInstance().singleOrNull()?.selected - ?: resolvedComponentResult - else -> resolvedComponentResult - } + val metadataSourceComponent = dependencyNode.run { metadataSourceComponent ?: selectedComponent } val parentResolutionsForDependency = parentResultsByModuleIdentifier[metadataSourceComponent.toSingleModuleIdentifier()].orEmpty() @@ -106,6 +94,15 @@ internal class FragmentGranularMetadataResolver( .flatMapTo(mutableSetOf()) { it.allVisibleSourceSetNames } 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( metadataSourceComponent, isResolvedAsProject, @@ -113,14 +110,14 @@ internal class FragmentGranularMetadataResolver( visibleFragmentNames, visibleFragmentNames.minus(fragmentsVisibleByParents), visibleTransitiveDependencies.map { resolvedDependenciesByModuleId.getValue(it.module.moduleIdentifier) }.toSet(), - checkNotNull(getMetadataExtractor(project, resolvedComponentResult, configurationToResolve, true)) + checkNotNull(metadataExtractor) ) } } 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 } resolvedComponentsByModuleId.values.minus(resultSourceComponents).forEach { results.add(MetadataDependencyResolution.ExcludeAsUnrequested(it, it.toProjectOrNull(project))) @@ -128,4 +125,33 @@ internal class FragmentGranularMetadataResolver( 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() + // 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) + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt index 89da77ff979..63461a760eb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradlePlugin.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier import javax.inject.Inject +import kotlin.reflect.KClass abstract class KotlinPm20GradlePlugin @Inject constructor( @Inject private val softwareComponentFactory: SoftwareComponentFactory @@ -35,11 +36,28 @@ abstract class KotlinPm20GradlePlugin @Inject constructor( } private fun registerDefaultVariantFactories(project: Project) { - project.pm20Extension.modules.configureEach { - it.fragments.registerFactory( + project.pm20Extension.modules.configureEach { module -> + module.fragments.registerFactory( KotlinJvmVariant::class.java, - KotlinJvmVariantFactory(it) + KotlinJvmVariantFactory(module) ) + + fun registerNativeVariantFactory(variantClass: KClass) { + 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) + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinFragmentMetadataCompilationData.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinFragmentMetadataCompilationData.kt deleted file mode 100644 index 622b63eb78c..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinFragmentMetadataCompilationData.kt +++ /dev/null @@ -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, - val metadataCompilationRegistry: MetadataCompilationRegistry, - private val resolvedMetadataFiles: Lazy> -) : KotlinCompilationData { - - 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 - 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 - get() = metadataCompilationRegistry.run { - fragment.refinesClosure.minus(fragment) - .map { - metadataCompilationRegistry.byFragment(it).output.classesDirs - } - } -} - -internal class MetadataCompilationRegistry { - private val compilationDataPerFragment = mutableMapOf() - - 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 - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt index c87b3989d7e..9b776094eb0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt @@ -5,19 +5,11 @@ 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.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl -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.* 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) : KotlinGradlePublishedVariantWithRuntime(containingModule, fragmentName) { @@ -29,48 +21,6 @@ open class KotlinJvmVariant(containingModule: KotlinGradleModule, fragmentName: class KotlinJvmVariantCompilationData(val variant: KotlinJvmVariant) : KotlinVariantCompilationDataInternal { 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 - get() = variant.refinesClosure.filterIsInstance().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 - // 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 override val kotlinOptions: KotlinJvmOptions get() = KotlinJvmOptionsImpl() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt new file mode 100644 index 00000000000..01b5a095213 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinMetadataCompilationData.kt @@ -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 : KotlinCompilationData { + val isActive: Boolean +} + +interface KotlinCommonFragmentMetadataCompilationData : KotlinMetadataCompilationData + +internal abstract class AbstractKotlinFragmentMetadataCompilationData( + final override val project: Project, + val fragment: KotlinGradleFragment, + private val module: KotlinGradleModule, + private val compileAllTask: TaskProvider, + val metadataCompilationRegistry: MetadataCompilationRegistry, + private val resolvedMetadataFiles: Lazy> +) : KotlinMetadataCompilationData { + + 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 + 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 + 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, + metadataCompilationRegistry: MetadataCompilationRegistry, + resolvedMetadataFiles: Lazy> +) : AbstractKotlinFragmentMetadataCompilationData( + project, + fragment, + module, + compileAllTask, + metadataCompilationRegistry, + resolvedMetadataFiles), KotlinCommonFragmentMetadataCompilationData { + + override val isActive: Boolean + get() = !fragment.isNativeShared() + + override val kotlinOptions: KotlinMultiplatformCommonOptions = KotlinMultiplatformCommonOptionsImpl() +} + +interface KotlinNativeFragmentMetadataCompilationData : + KotlinMetadataCompilationData, + KotlinNativeCompilationData + +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, + metadataCompilationRegistry: MetadataCompilationRegistry, + resolvedMetadataFiles: Lazy> +) : AbstractKotlinFragmentMetadataCompilationData( + 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() + 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() + private val nativeCompilationDataPerFragment = mutableMapOf() + + 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 + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt new file mode 100644 index 00000000000..e59ef51a4be --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariant.kt @@ -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 + 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 : KotlinCompilationData { + val konanTarget: KonanTarget + val enableEndorsedLibs: Boolean +} + +internal class KotlinNativeVariantCompilationData( + val variant: KotlinNativeVariantInternal +) : KotlinVariantCompilationDataInternal, KotlinNativeCompilationData { + 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 } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt index 89d50417a26..4a9feffd6b8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinNativeVariantFactory.kt @@ -30,6 +30,7 @@ import org.jetbrains.kotlin.gradle.utils.dashSeparatedName import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION import org.jetbrains.kotlin.project.model.refinesClosure import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment +import java.util.concurrent.Callable import kotlin.reflect.KClass open class KotlinNativeVariantFactory( diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt index 44570f1b4e9..b99d8b2d04b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariantFactories.kt @@ -27,12 +27,13 @@ abstract class AbstractKotlinGradleVariantFactory( module: KotlinGradleModule ) : AbstractKotlinGradleFragmentFactory(module) { - override fun create(name: String): T = super.create(name).also { fragment -> - createSourcesArchiveTask(fragment) - configureKotlinCompilation(fragment) - createElementsConfigurations(fragment) - // TODO configure resources processing - } + override fun create(name: String): T = + super.create(name).also { fragment -> + createSourcesArchiveTask(fragment) + createElementsConfigurations(fragment) + configureKotlinCompilation(fragment) + // TODO configure resources processing + } protected open fun setPlatformAttributesInConfiguration(fragment: T, configuration: Configuration) { configuration.attributes.attribute(KotlinPlatformType.attribute, fragment.platformType) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariants.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariants.kt index ee480149b83..795e016ae18 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariants.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/abstractVariants.kt @@ -57,6 +57,9 @@ abstract class KotlinGradleVariantInternal( override fun toString(): String = "variant $fragmentName in $containingModule" } +internal val KotlinGradleVariant.compileDependencyConfiguration: Configuration + get() = containingModule.project.configurations.getByName(compileDependencyConfigurationName) + class DefaultSingleMavenPublicationHolder( private var module: KotlinGradleModule, override val defaultPublishedModuleSuffix: String? diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentFactories.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentFactories.kt index 886a47f29da..476cfef5c0d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentFactories.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentFactories.kt @@ -32,7 +32,7 @@ abstract class AbstractKotlinGradleFragmentFactory( with(project.configurations) { fragment.relatedConfigurationNames.forEach { configurationName -> maybeCreate(configurationName).apply { - // FIXME add metadata configurations? + // FIXME add metadata configurations or API for IDE import? if (!configurationName.endsWith(METADATA_CONFIGURATION_NAME_SUFFIX)) { isCanBeResolved = false } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt index a90d6d3f7fb..b155fb50246 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt @@ -10,7 +10,6 @@ import org.gradle.api.Project import org.gradle.api.attributes.Usage import org.gradle.api.tasks.TaskProvider 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.plugin.* 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.utils.addExtendsFromRelation import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION import org.jetbrains.kotlin.project.model.KotlinModuleFragment import java.util.concurrent.Callable @@ -66,7 +66,7 @@ private fun generateAndExportProjectStructureMetadata( module: KotlinGradleModule ) { val project = module.project - val projectStructureMetadata = project.createGenerateProjectStructureMetadataTask(module.moduleClassifier) + val projectStructureMetadata = project.createGenerateProjectStructureMetadataTask(module) project.tasks.withType().named(metadataJarName(module)).configure { jar -> jar.from(projectStructureMetadata.map { it.resultFile }) { spec -> spec.into("META-INF") @@ -74,7 +74,7 @@ private fun generateAndExportProjectStructureMetadata( } } GlobalProjectStructureMetadataStorage.registerProjectStructureMetadata(project) { - checkNotNull(buildKotlinProjectStructureMetadata(project)) + buildProjectStructureMetadata(module) } } @@ -108,7 +108,13 @@ private fun configureMetadataCompilationsAndCreateRegistry( } val compileAllTask = project.registerTask(lowerCamelCaseName(module.moduleClassifier, "metadataClasses")) 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) = lowerCamelCaseName(module.moduleClassifier, "metadataJar") -private fun createMetadataCompilation( +private fun createCommonMetadataCompilation( fragment: KotlinGradleFragment, compileAllTask: TaskProvider, metadataCompilationRegistry: MetadataCompilationRegistry -): KotlinCompilationData { +) { val module = fragment.containingModule val project = module.project val metadataCompilationData = - KotlinFragmentMetadataCompilationData( + KotlinCommonFragmentMetadataCompilationDataImpl( project, fragment, module, compileAllTask, metadataCompilationRegistry, - lazy { - fragment.refinesClosure.map { - FragmentResolvedMetadataProvider( - project.tasks.withType() - .named(transformFragmentMetadataTaskName(it)) - ) - } - } + lazy { resolvedMetadataProviders(fragment) } ) - metadataCompilationRegistry.register(fragment, metadataCompilationData) - - addSourcesToKotlinCompileTask( - project, - metadataCompilationData.compileKotlinTaskName, - /*FIXME*/ emptyList(), - { fragment.kotlinSourceRoots }, - lazyOf(true) - ) - KotlinCommonSourceSetProcessor( metadataCompilationData, KotlinTasksProvider(), project.getKotlinPluginVersion() ?: "undefined" ).run() - - return metadataCompilationData + addSourcesToMetadataCompileTask(metadataCompilationData) + metadataCompilationRegistry.registerCommon(fragment, metadataCompilationData) } +private fun createNativeMetadataCompilation( + fragment: KotlinGradleFragment, + compileAllTask: TaskProvider, + 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() + .named(transformFragmentMetadataTaskName(it)) + ) + } + private fun createExtractMetadataTask( project: Project, fragment: KotlinGradleFragment, @@ -206,7 +246,7 @@ private fun createExtractMetadataTask( // FIXME: use this function once more than one platform is supported private fun disableMetadataCompilationIfNotYetSupported( - metadataCompilationData: KotlinFragmentMetadataCompilationData + metadataCompilationData: AbstractKotlinFragmentMetadataCompilationData<*> ) { val fragment = metadataCompilationData.fragment val platforms = fragment.containingModule.variantsContainingFragment(fragment).map { it.platformType }.toSet() diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/variantPublishing.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/variantPublishing.kt new file mode 100644 index 00000000000..3e5065cc9a0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/variantPublishing.kt @@ -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 publishVariantWithSinglePublication( + variant: T +) where T : SingleMavenPublicationHolder, T : KotlinGradleVariant { + +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index f2350a90b6f..5defce6ca75 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -21,6 +21,8 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.* 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.sources.* import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService @@ -119,20 +121,6 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : else -> error("unsupported compilation type ${compilation::class.qualifiedName}") } - private inner class NativeSharedCompilationProcessor( - override val kotlinCompilation: KotlinSharedNativeCompilation - ) : KotlinCompilationProcessor(kotlinCompilation) { - - private val nativeTargetConfigurator = KotlinNativeTargetConfigurator(kotlinPluginVersion) - - override val kotlinTask: TaskProvider = - with(nativeTargetConfigurator) { - project.createKlibCompilationTask(kotlinCompilation) - } - - override fun run() = Unit - } - override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider { if (!target.project.isKotlinGranularMetadataEnabled) return super.createArchiveTasks(target) @@ -486,8 +474,28 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : } } -internal fun Project.createGenerateProjectStructureMetadataTask(moduleClassifier: String? = null): TaskProvider = - project.registerTask(lowerCamelCaseName("generate", moduleClassifier, "ProjectStructureMetadata")) { task -> +internal class NativeSharedCompilationProcessor( + override val kotlinCompilation: KotlinNativeFragmentMetadataCompilationData +) : KotlinCompilationProcessor(kotlinCompilation) { + + private val nativeTargetConfigurator = + KotlinNativeTargetConfigurator(kotlinCompilation.project.getKotlinPluginVersion() ?: "" /*FIXME*/) + + override val kotlinTask: TaskProvider = + with(nativeTargetConfigurator) { + project.createKlibCompilationTask(kotlinCompilation) + } + + override fun run() = Unit +} + +internal fun Project.createGenerateProjectStructureMetadataTask(module: KotlinGradleModule): TaskProvider = + project.registerTask(lowerCamelCaseName("generate", module.moduleClassifier, "ProjectStructureMetadata")) { task -> + task.lazyKotlinProjectStructureMetadata = lazy { buildProjectStructureMetadata(module) } + } + +internal fun Project.createGenerateProjectStructureMetadataTask(): TaskProvider = + project.registerTask(lowerCamelCaseName("generateProjectStructureMetadata")) { task -> task.lazyKotlinProjectStructureMetadata = lazy { checkNotNull(buildKotlinProjectStructureMetadata(project)) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/DefaultCInteropSettings.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/DefaultCInteropSettings.kt index dddbb32e56b..4e1d608ed5d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/DefaultCInteropSettings.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/DefaultCInteropSettings.kt @@ -15,6 +15,10 @@ import org.gradle.api.provider.Property import org.gradle.util.ConfigureUtil import org.jetbrains.kotlin.gradle.plugin.CInteropSettings 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.utils.lowerCamelCaseName import java.io.File @@ -23,7 +27,7 @@ import javax.inject.Inject open class DefaultCInteropSettings @Inject constructor( private val project: Project, private val name: String, - override val compilation: KotlinNativeCompilation + override val compilation: KotlinNativeCompilationData<*> ) : CInteropSettings { inner class DefaultIncludeDirectories : CInteropSettings.IncludeDirectories { @@ -46,8 +50,8 @@ open class DefaultCInteropSettings @Inject constructor( internal val identifier: CInteropIdentifier get() = CInteropIdentifier(CInteropIdentifier.Scope.create(compilation), name) - val target: KotlinNativeTarget - get() = compilation.target + val target: KotlinNativeTarget? + get() = (compilation as? KotlinNativeCompilation?)?.target override val dependencyConfigurationName: String get() = compilation.disambiguateName("${name.capitalize()}CInterop") @@ -59,7 +63,7 @@ open class DefaultCInteropSettings @Inject constructor( "cinterop", compilation.compilationPurpose.takeIf { it != "main" }.orEmpty(), name, - target.disambiguationClassifier + target?.disambiguationClassifier ?: compilation.compilationClassifier ) val defFileProperty: Property = project.objects.property(File::class.java) @@ -129,3 +133,13 @@ open class DefaultCInteropSettings @Inject constructor( _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 + ) +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt index 689bc843757..639be84c8e1 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt @@ -9,49 +9,58 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import groovy.lang.Closure import org.gradle.api.Action import org.gradle.api.NamedDomainObjectContainer +import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.gradle.api.tasks.TaskProvider import org.gradle.util.ConfigureUtil import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions 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.resolveAllDependsOnSourceSets 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.utils.lowerCamelCaseName import org.jetbrains.kotlin.konan.target.KonanTarget +import java.io.File 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 = listOf() +} + abstract class AbstractKotlinNativeCompilation( target: KotlinTarget, - val konanTarget: KonanTarget, + override val konanTarget: KonanTarget, compilationName: String -) : AbstractKotlinCompilation(target, compilationName) { +) : AbstractKotlinCompilation(target, compilationName), KotlinNativeCompilationData { 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 = listOf() - } - override val compileKotlinTask: KotlinNativeCompile get() = super.compileKotlinTask as KotlinNativeCompile @@ -59,14 +68,25 @@ abstract class AbstractKotlinNativeCompilation( override val compileKotlinTaskProvider: TaskProvider get() = super.compileKotlinTaskProvider as TaskProvider - override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy) = - compileKotlinTaskProvider.configure { task -> - task.source(sourceSet.kotlin) - task.commonSources.from(target.project.files(Callable { if (addAsCommonSources.value) sourceSet.kotlin else emptyList() })) - } + override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy) { + addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources) + } // Endorsed library controller. - var enableEndorsedLibs: Boolean = false + override var enableEndorsedLibs: Boolean = false +} + +internal fun addSourcesToKotlinNativeCompileTask( + project: Project, + taskName: String, + sourceFiles: () -> Iterable, + addAsCommonSources: Lazy +) { + 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( @@ -117,6 +137,7 @@ class KotlinNativeCompilation( } class KotlinSharedNativeCompilation(override val target: KotlinMetadataTarget, val konanTargets: List, name: String) : + KotlinNativeFragmentMetadataCompilationData, AbstractKotlinNativeCompilation( target, // 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 }) }) + + override val isActive: Boolean + get() = true // old plugin only creates necessary compilations } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt index 0ec743272be..c6a0e3f0f13 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt @@ -10,13 +10,14 @@ import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.Project import org.gradle.api.artifacts.Dependency import org.gradle.api.attributes.Attribute -import org.gradle.api.attributes.Usage import org.gradle.jvm.tasks.Jar import org.gradle.util.WrapUtil import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer 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.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.filesWithUnpackedArchives import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled @@ -136,26 +137,49 @@ open class KotlinNativeTarget @Inject constructor( } } -internal fun getHostSpecificSourceSets(project: Project): List { - val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project) +private val hostManager by lazy { HostManager() } - val enabledByHost = HostManager().enabledByHost +private fun isHostSpecificKonanTargetsSet(konanTargets: Iterable): Boolean { + val enabledByHost = hostManager.enabledByHost val allHosts = enabledByHost.keys - fun canBeBuiltOnHosts(konanTarget: KonanTarget) = enabledByHost.filterValues { konanTarget in it }.keys + return konanTargets.flatMapTo(mutableSetOf(), ::canBeBuiltOnHosts) != allHosts +} - return project.kotlinExtension.sourceSets.filter { sourceSet -> - if (sourceSet !in compilationsBySourceSet) return@filter false +private fun getHostSpecificElements( + fragments: Iterable, + isNativeShared: (T) -> Boolean, + getKonanTargets: (T) -> Set +): Set = 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, - // we can't analyze the source set, so the source set's metadata can't be published from that host, and therefore - // we consider it platform-specific and publish as a part of the Native targets where the source set takes part, - // not the common metadata artifact; - val platformCompilations = compilationsBySourceSet.getValue(sourceSet).filter { it !is KotlinMetadataCompilation } - val nativeCompilations = platformCompilations.filterIsInstance() - val nativeEnabledOn = nativeCompilations.flatMapTo(mutableSetOf()) { compilation -> canBeBuiltOnHosts(compilation.konanTarget) } - platformCompilations == nativeCompilations && allHosts != nativeEnabledOn +internal fun getHostSpecificFragments( + module: KotlinGradleModule +): Set = getHostSpecificElements( + module.fragments, + isNativeShared = { it.isNativeShared() }, + getKonanTargets = { + val nativeVariants = module.variantsContainingFragment(it).filterIsInstance() + nativeVariants.mapTo(mutableSetOf()) { it.konanTarget } } +) + +internal fun getHostSpecificSourceSets(project: Project): Set { + 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() + .mapTo(mutableSetOf()) { it.konanTarget } + } + ) } abstract class KotlinNativeTargetWithTests( diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index 4d9436ec2a1..c74357e27b0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.DefaultTask +import org.gradle.api.NamedDomainObjectCollection import org.gradle.api.Project import org.gradle.api.Task 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.mpp.* 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.native.* import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask @@ -51,10 +53,10 @@ open class KotlinNativeTargetConfigurator( createTestCompilation = true ) { private fun Project.klibOutputDirectory( - compilation: AbstractKotlinNativeCompilation + compilation: KotlinCompilationData<*> ): File { - val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() - return buildDir.resolve("classes/kotlin/$targetSubDirectory${compilation.name}") + val targetSubDirectory = compilation.compilationClassifier?.let { "$it/" }.orEmpty() + return buildDir.resolve("classes/kotlin/$targetSubDirectory${compilation.compilationPurpose}") } private fun addCompilerPlugins(compilation: AbstractKotlinNativeCompilation) { @@ -73,9 +75,25 @@ open class KotlinNativeTargetConfigurator( } } - // 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 + ) = createKlibArtifact(compilation, compileTask.map { it.outputFile.get() }, null, compileTask) + + internal fun Project.createCInteropKlibArtifact( + interop: DefaultCInteropSettings, + interopTask: TaskProvider + ) = createKlibArtifact(interop.compilation, interopTask.map { it.outputFile }, "cinterop-${interop.name}", interopTask, copy = true) + private fun Project.createKlibArtifact( - compilation: KotlinNativeCompilation, + compilation: KotlinNativeCompilationData<*>, artifactFile: Provider, classifier: String?, producingTask: TaskProvider<*>, @@ -85,14 +103,14 @@ open class KotlinNativeTargetConfigurator( return } - val apiElements = configurations.getByName(compilation.target.apiElementsConfigurationName) + val apiElements = configurations.getByName(compilation.apiElementsConfigurationName) val realProducingTask: TaskProvider<*> // TODO: Someone remove this HACK PLEASE! val realArtifactFile = if (copy) { realProducingTask = project.registerTask("copy${producingTask.name.capitalize()}") { - val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() - it.destinationDir = project.buildDir.resolve("libs/$targetSubDirectory${compilation.name}") + val targetSubDirectory = compilation.compilationClassifier?.let { "$it/" }.orEmpty() + it.destinationDir = project.buildDir.resolve("libs/$targetSubDirectory${compilation.compilationPurpose}") it.from(artifactFile) it.dependsOn(producingTask) } @@ -104,7 +122,7 @@ open class KotlinNativeTargetConfigurator( with(apiElements) { val klibArtifact = project.artifacts.add(apiElements.name, realArtifactFile) { artifact -> - artifact.name = compilation.name + artifact.name = compilation.compilationPurpose artifact.extension = "klib" artifact.type = "klib" artifact.classifier = classifier @@ -115,18 +133,6 @@ open class KotlinNativeTargetConfigurator( attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB) } } - - private fun Project.createRegularKlibArtifact( - compilation: KotlinNativeCompilation, - compileTask: TaskProvider - ) = createKlibArtifact(compilation, compileTask.map { it.outputFile.get() }, null, compileTask) - - private fun Project.createCInteropKlibArtifact( - interop: DefaultCInteropSettings, - interopTask: TaskProvider - ) = createKlibArtifact(interop.compilation, interopTask.map { it.outputFile }, "cinterop-${interop.name}", interopTask, copy = true) - // endregion. - // region Task creation. private fun Project.createLinkTask(binary: NativeBinary) { val result = registerTask( @@ -258,12 +264,12 @@ open class KotlinNativeTargetConfigurator( } } - internal fun Project.createKlibCompilationTask(compilation: AbstractKotlinNativeCompilation): TaskProvider { + internal fun Project.createKlibCompilationTask(compilation: KotlinNativeCompilationData<*>): TaskProvider { val compileTaskProvider = registerTask( compilation.compileKotlinTaskName, listOf(compilation) ) { 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}'." it.enabled = compilation.konanTarget.enabledOnCurrentHost @@ -275,33 +281,39 @@ open class KotlinNativeTargetConfigurator( project.files(compileTaskProvider.map { it.outputFile }) } - project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTaskProvider) - if (compilation.isMain()) { - compilation as? KotlinNativeCompilation ?: error("Main shared-Native compilation is not yet supported!") - - project.tasks.getByName(compilation.target.artifactsTaskName).apply { - dependsOn(compileTaskProvider) + if (compilation.isMainCompilationData()) { + if (compilation is KotlinNativeCompilation) { + project.tasks.getByName(compilation.target.artifactsTaskName).apply { + dependsOn(compileTaskProvider) + } } + project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply { dependsOn(compileTaskProvider) } createRegularKlibArtifact(compilation, compileTaskProvider) } - addCompilerPlugins(compilation) - + if (compilation is AbstractKotlinNativeCompilation) { + // FIXME: support compiler plugins for PM20 + addCompilerPlugins(compilation) + } return compileTaskProvider } - private fun Project.createCInteropTasks(compilation: KotlinNativeCompilation) { - compilation.cinterops.all { interop -> + // FIXME support creating interop tasks for PM20 + private fun Project.createCInteropTasks( + compilation: KotlinNativeCompilation, + cinterops: NamedDomainObjectCollection + ) { + cinterops.all { interop -> val interopTask = registerTask(interop.interopProcessingTaskName, listOf(interop)) { it.destinationDir = provider { klibOutputDirectory(compilation).resolve("cinterop") } it.group = INTEROP_GROUP it.description = "Generates Kotlin/Native interop library '${interop.name}' " + - "for compilation '${compilation.name}'" + + "for compilation '${compilation.compilationPurpose}'" + "of target '${it.konanTarget.name}'." it.enabled = compilation.konanTarget.enabledOnCurrentHost } @@ -377,7 +389,7 @@ open class KotlinNativeTargetConfigurator( protected fun configureCInterops(target: KotlinNativeTarget): Unit = with(target.project) { target.compilations.all { compilation -> - createCInteropTasks(compilation) + createCInteropTasks(compilation, compilation.cinterops) compilation.cinterops.all { defineConfigurationsForCInterop(compilation, it, target, configurations) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt index 21b9bf3875b..e79135cfdbe 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt @@ -172,7 +172,8 @@ private fun CInteropProcess.toGist(): CInteropGist { return CInteropGist( identifier = settings.identifier, konanTarget = konanTarget, - sourceSets = project.provider { settings.compilation.kotlinSourceSetsIncludingDefault }, + // FIXME support cinterop with PM20 + sourceSets = project.provider { (settings.compilation as? KotlinCompilation<*>)?.kotlinSourceSetsIncludingDefault }, libraryFile = outputFileProvider, /** diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropIdentifier.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropIdentifier.kt index cd200e44a3b..5174babbef7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropIdentifier.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropIdentifier.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.gradle.targets.native.internal 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 java.io.Serializable @@ -20,7 +20,7 @@ internal data class CInteropIdentifier internal constructor( class Scope @UnsafeApi internal constructor(val name: String) : Serializable { companion object { @OptIn(UnsafeApi::class) - fun create(compilation: KotlinCompilation<*>): Scope { + fun create(compilation: KotlinCompilationData<*>): Scope { return Scope("compilation/${compilation.compileKotlinTaskName}") } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 6bcd436426e..75041131230 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -26,6 +26,9 @@ import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName 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.targets.native.internal.isAllowCommonizer import org.jetbrains.kotlin.gradle.utils.getValue @@ -113,7 +116,7 @@ private fun Collection.filterKlibsPassedToCompiler(project: Project) = fil } // endregion -abstract class AbstractKotlinNativeCompile : AbstractCompile() { +abstract class AbstractKotlinNativeCompile> : AbstractCompile() { @get:Internal abstract val compilation: K @@ -139,7 +142,7 @@ abstract class AbstractKotlinNativeCompile(), + final override val compilation: KotlinNativeCompilationData<*> +) : AbstractKotlinNativeCompile>(), KotlinCompile { @get:Input @@ -357,7 +360,11 @@ constructor( override val debuggable = true @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 // private val allSourceProvider = compilation.map { project.files(it.allSources).asFileTree } @@ -390,10 +397,7 @@ constructor( private val friendModule: FileCollection by project.provider { - project.files( - compilation.associateWithTransitiveClosure.map { it.output.allOutputs }, - compilation.friendArtifacts - ) + project.files(compilation.friendPaths) } // endregion. @@ -934,7 +938,7 @@ open class CInteropProcess @Inject constructor(@get:Internal val settings: Defau val baseKlibName: String @Input get() { 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" } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index 89c4e609bee..a9a8df75471 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -24,8 +24,7 @@ import org.gradle.api.tasks.PathSensitivity import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl -import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompile -import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions +import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues 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.KotlinTarget 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.utils.getValue import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets @@ -63,7 +63,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile): List { - val target = taskData.compilation.owner - return when (target) { - is KotlinTarget -> sourceSets - .mapNotNull { sourceSet -> target.compilations.findByName(sourceSet.name)?.output?.classesDirs } - .flatten() - else -> error("unexpected compilation owner") // FIXME support PM20 variant - } + val metadataTarget = taskData.compilation.owner as KotlinTarget + return sourceSets + .mapNotNull { sourceSet -> metadataTarget.compilations.findByName(sourceSet.name)?.output?.classesDirs } + .flatten() } @get:PathSensitive(PathSensitivity.RELATIVE) @@ -101,7 +98,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile { + is AbstractKotlinFragmentMetadataCompilationData -> { val fragment = compilation.fragment project.files( fragment.refinesClosure.minus(fragment).map { @@ -109,7 +106,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile error("unexpected compilation type") // FIXME support PM20 variant + else -> error("unexpected compilation type") } } diff --git a/libraries/tools/kotlin-project-model/src/main/kotlin/DependencyResolution.kt b/libraries/tools/kotlin-project-model/src/main/kotlin/DependencyResolution.kt index b076510e626..8746f3db724 100644 --- a/libraries/tools/kotlin-project-model/src/main/kotlin/DependencyResolution.kt +++ b/libraries/tools/kotlin-project-model/src/main/kotlin/DependencyResolution.kt @@ -25,15 +25,15 @@ interface KotlinDependencyGraphResolver { 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 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? -class DependencyGraphNode( - val module: KotlinModule, - val dependenciesByFragment: Map> +open class DependencyGraphNode( + open val module: KotlinModule, + open val dependenciesByFragment: Map> ) { override fun toString(): String = "node ${module}" } \ No newline at end of file