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

This commit is contained in:
Sergey Igushkin
2021-03-19 18:24:03 +03:00
parent 401fbae8d8
commit f029179fe0
30 changed files with 713 additions and 391 deletions
@@ -10,6 +10,7 @@ import org.gradle.api.Action
import org.gradle.api.Named
import org.gradle.api.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<KotlinCommonOptions>
val compilation: KotlinCompilationData<out KotlinCommonOptions>
val dependencyConfigurationName: String
var dependencyFiles: FileCollection
@@ -36,7 +36,7 @@ import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder
import org.jetbrains.kotlin.gradle.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<Task>(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask)
}
@@ -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")
}
@@ -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
@@ -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
)
}
@@ -288,7 +288,7 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val project: Project
get() = target.project
override val owner: Any?
override val owner: KotlinTarget
get() = target
override val compilationClassifier: String?
@@ -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<ResolvedComponentResult>()
val nodeByModuleId = mutableMapOf<KotlinModuleIdentifier, DependencyGraphNode>()
val nodeByModuleId = mutableMapOf<KotlinModuleIdentifier, GradleDependencyGraphNode>()
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<ResolvedDependencyResult>()
// This filter statement is used to only visit the dependencies of the variant(s) of the requested Kotlin module and not
// other variants. This prevents infinite recursion when visiting multiple Kotlin modules within one Gradle components
.filter { dependency -> dependency.requested.toModuleIdentifiers().any { it in dependenciesRequestedByModule } }
.flatMap { dependency -> dependency.requested.toModuleIdentifiers().map { id -> id to dependency.selected } }
.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)
)
}
}
}
class GradleDependencyGraphNode(
override val module: KotlinModule,
val selectedComponent: ResolvedComponentResult,
val metadataSourceComponent: ResolvedComponentResult?,
override val dependenciesByFragment: Map<KotlinModuleFragment, Iterable<GradleDependencyGraphNode>>
) : DependencyGraphNode(module, dependenciesByFragment)
class GradleDependencyGraph(
override val requestingModule: KotlinGradleModule,
override val root: GradleDependencyGraphNode
) : DependencyGraphResolution.DependencyGraph(requestingModule, root)
@@ -163,7 +163,8 @@ internal class ExternalSyntheticKotlinModule(private val moduleData: BasicKotlin
internal class ExternalImportedKotlinModule(
private val moduleData: BasicKotlinModule,
val projectStructureMetadata: KotlinProjectStructureMetadata
val projectStructureMetadata: KotlinProjectStructureMetadata,
val hostSpecificFragments: Set<KotlinModuleFragment>
) : KotlinModule by moduleData {
val hasLegacyMetadataModule = !projectStructureMetadata.isPublishedAsRoot
@@ -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<DependencyGraphNode>()
val fragmentResolutionQueue = ArrayDeque<DependencyGraphNode>().apply {
addAll(requestedDependencies)
}
val visited = mutableSetOf<GradleDependencyGraphNode>()
val fragmentResolutionQueue = ArrayDeque<GradleDependencyGraphNode>(requestedDependencies)
val results = mutableSetOf<MetadataDependencyResolution>()
@@ -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<ResolvedDependencyResult>().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<VariantResolution.VariantMatch>()
// find some of our variants that resolved a dependency's variant containing the fragment
.find { hostSpecificFragment in it.chosenVariant.refinesClosure }
// resolve the dependencies of that variant getting the host-specific metadata artifact
relevantResolution?.let { resolution ->
val variantResolvingPlatformArtifact =
(resolution.requestingVariant as KotlinGradleVariant).compileDependencyConfiguration
val configuration = variantResolvingPlatformArtifact
val hostSpecificArtifact = ResolvedMppVariantsProvider.get(project)
.getHostSpecificMetadataArtifactByRootModule(
dependencyModule.moduleIdentifier,
configuration
)
hostSpecificArtifact?.let { hostSpecificFragment.fragmentName to it }
}
}
metadataExtractor.metadataArtifactBySourceSet.putAll(hostSpecificFragmentToArtifact)
}
}
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.internal.customizeKotlinDependencies
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
import org.jetbrains.kotlin.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 <T: KotlinNativeVariantInternal> registerNativeVariantFactory(variantClass: KClass<T>) {
module.fragments.registerFactory(
variantClass.java,
KotlinNativeVariantFactory(module, variantClass)
)
}
listOf(
// FIXME codegen, add missing native targets
KotlinLinuxX64Variant::class,
KotlinMacosX64Variant::class,
KotlinMacosArm64Variant::class,
KotlinIosX64Variant::class,
KotlinIosArm64Variant::class
).forEach { variantClass ->
registerNativeVariantFactory(variantClass)
}
}
}
@@ -1,115 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.mpp.filterModuleName
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
import org.jetbrains.kotlin.gradle.targets.metadata.createTransformedMetadataClasspath
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
internal class KotlinFragmentMetadataCompilationData(
override val project: Project,
val fragment: KotlinGradleFragment,
private val module: KotlinGradleModule,
private val compileAllTask: TaskProvider<DefaultTask>,
val metadataCompilationRegistry: MetadataCompilationRegistry,
private val resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : KotlinCompilationData<KotlinMultiplatformCommonOptions> {
override val owner
get() = project.pm20Extension
override val compilationPurpose: String
get() = fragment.fragmentName
override val compilationClassifier: String
get() = lowerCamelCaseName(module.name, "metadata")
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = mapOf(fragment.fragmentName to fragment.kotlinSourceRoots)
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinMetadata")
override val compileAllTaskName: String
get() = compileAllTask.name
override val compileDependencyFiles: FileCollection by project.provider {
createTransformedMetadataClasspath(
project,
resolvableMetadataConfiguration(fragment.containingModule),
lazy { fragment.refinesClosure.minus(fragment).map { metadataCompilationRegistry.byFragment(it).output.classesDirs } },
resolvedMetadataFiles
)
}
override val output: KotlinCompilationOutput = DefaultKotlinCompilationOutput(
project,
project.provider { project.buildDir.resolve("processedResources/${fragment.disambiguateName("metadata")}") }
)
override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() // FIXME apply settings
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.common
override val moduleName: String
get() { // FIXME deduplicate with ownModuleName
val baseName = project.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName
?: project.name
val suffix = if (module.moduleClassifier == null) "" else "_${module.moduleClassifier}"
return filterModuleName("$baseName$suffix")
}
override val ownModuleName: String
get() = moduleName
override val kotlinOptions: KotlinMultiplatformCommonOptions = // FIXME expose for configuration
KotlinMultiplatformCommonOptionsImpl()
override val friendPaths: Iterable<FileCollection>
get() = metadataCompilationRegistry.run {
fragment.refinesClosure.minus(fragment)
.map {
metadataCompilationRegistry.byFragment(it).output.classesDirs
}
}
}
internal class MetadataCompilationRegistry {
private val compilationDataPerFragment = mutableMapOf<KotlinGradleFragment, KotlinFragmentMetadataCompilationData>()
fun register(fragment: KotlinGradleFragment, compilationData: KotlinFragmentMetadataCompilationData) {
compilationDataPerFragment[fragment]?.let { error("compilation data for fragment $fragment already registered") }
compilationDataPerFragment[fragment] = compilationData
withAllCallbacks.forEach { it.invoke(compilationData) }
}
fun byFragment(fragment: KotlinGradleFragment): KotlinFragmentMetadataCompilationData =
compilationDataPerFragment.getValue(fragment)
private val withAllCallbacks = mutableListOf<(KotlinFragmentMetadataCompilationData) -> Unit>()
fun withAll(action: (KotlinFragmentMetadataCompilationData) -> Unit) {
compilationDataPerFragment.forEach { action(it.value) }
withAllCallbacks += action
}
}
@@ -5,19 +5,11 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
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<KotlinJvmOptions> {
override val owner: KotlinJvmVariant get() = variant
override val compilationPurpose: String
get() = variant.containingModule.name
override val compilationClassifier: String
get() = variant.name
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = variant.refinesClosure.filterIsInstance<KotlinGradleVariant>().associate { it.disambiguateName("") to it.kotlinSourceRoots }
override val output: KotlinCompilationOutput
get() = variant.compilationOutputs
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", compilationPurpose.takeIf { it != "main" }, "Kotlin", compilationClassifier)
override val compileAllTaskName: String
get() = variant.disambiguateName("classes")
override val compileDependencyFiles: FileCollection
get() = variant.compileDependencyFiles
override val languageSettings: LanguageSettingsBuilder
get() = variant.languageSettings
override val platformType: KotlinPlatformType
get() = variant.platformType
override val friendPaths: Iterable<FileCollection>
// TODO for now, all output classes of the module are considered friends, even those not on the classpath
get() {
// FIXME support compiling against the JARs
return variant.containingModule.project.pm20Extension.modules.flatMap { it.variants.map { it.compilationOutputs.classesDirs } }
}
override val moduleName: String
get() = // TODO accurate module names that don't rely on all variants having a main counterpart
variant.containingModule.project.pm20Extension.modules
.getByName(KotlinGradleModule.MAIN_MODULE_NAME).variants.findByName(variant.name)?.ownModuleName() ?: ownModuleName
override val ownModuleName: String
get() = variant.ownModuleName()
// TODO pull out to the variant
override val kotlinOptions: KotlinJvmOptions
get() = KotlinJvmOptionsImpl()
@@ -0,0 +1,206 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.dsl.pm20Extension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.targets.metadata.ResolvedMetadataFilesProvider
import org.jetbrains.kotlin.gradle.targets.metadata.createTransformedMetadataClasspath
import org.jetbrains.kotlin.gradle.utils.getValue
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
interface KotlinMetadataCompilationData<T : KotlinCommonOptions> : KotlinCompilationData<T> {
val isActive: Boolean
}
interface KotlinCommonFragmentMetadataCompilationData : KotlinMetadataCompilationData<KotlinMultiplatformCommonOptions>
internal abstract class AbstractKotlinFragmentMetadataCompilationData<T : KotlinCommonOptions>(
final override val project: Project,
val fragment: KotlinGradleFragment,
private val module: KotlinGradleModule,
private val compileAllTask: TaskProvider<DefaultTask>,
val metadataCompilationRegistry: MetadataCompilationRegistry,
private val resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : KotlinMetadataCompilationData<T> {
override val owner
get() = project.pm20Extension
override val compilationPurpose: String
get() = fragment.fragmentName
override val compilationClassifier: String
get() = lowerCamelCaseName(module.name, "metadata")
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = mapOf(fragment.fragmentName to fragment.kotlinSourceRoots)
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinMetadata")
override val compileAllTaskName: String
get() = compileAllTask.name
override val compileDependencyFiles: FileCollection by project.provider {
createTransformedMetadataClasspath(
project,
resolvableMetadataConfiguration(fragment.containingModule),
lazy { fragment.refinesClosure.minus(fragment).map { metadataCompilationRegistry.byFragment(it).output.classesDirs } },
resolvedMetadataFiles
)
}
override val output: KotlinCompilationOutput = DefaultKotlinCompilationOutput(
project,
project.provider { project.buildDir.resolve("processedResources/${fragment.disambiguateName("metadata")}") }
)
override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() // FIXME apply settings
override val platformType: KotlinPlatformType
get() = KotlinPlatformType.common
override val moduleName: String
get() { // FIXME deduplicate with ownModuleName
val baseName = project.convention.findPlugin(BasePluginConvention::class.java)?.archivesBaseName
?: project.name
val suffix = if (module.moduleClassifier == null) "" else "_${module.moduleClassifier}"
return filterModuleName("$baseName$suffix")
}
override val ownModuleName: String
get() = moduleName
override val friendPaths: Iterable<FileCollection>
get() = metadataCompilationRegistry.run {
fragment.refinesClosure.minus(fragment)
.map {
metadataCompilationRegistry.byFragment(it).output.classesDirs
}
}
}
internal open class KotlinCommonFragmentMetadataCompilationDataImpl(
project: Project,
fragment: KotlinGradleFragment,
module: KotlinGradleModule,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry,
resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : AbstractKotlinFragmentMetadataCompilationData<KotlinMultiplatformCommonOptions>(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
resolvedMetadataFiles), KotlinCommonFragmentMetadataCompilationData {
override val isActive: Boolean
get() = !fragment.isNativeShared()
override val kotlinOptions: KotlinMultiplatformCommonOptions = KotlinMultiplatformCommonOptionsImpl()
}
interface KotlinNativeFragmentMetadataCompilationData :
KotlinMetadataCompilationData<KotlinCommonOptions>,
KotlinNativeCompilationData<KotlinCommonOptions>
internal fun KotlinGradleFragment.isNativeShared(): Boolean =
containingModule.variantsContainingFragment(this).all { it.platformType == KotlinPlatformType.native }
internal fun KotlinGradleFragment.isNativeHostSpecific(): Boolean =
this in getHostSpecificFragments(containingModule)
internal open class KotlinNativeFragmentMetadataCompilationDataImpl(
project: Project,
fragment: KotlinGradleFragment,
module: KotlinGradleModule,
compileAllTask: TaskProvider<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry,
resolvedMetadataFiles: Lazy<Iterable<ResolvedMetadataFilesProvider>>
) : AbstractKotlinFragmentMetadataCompilationData<KotlinCommonOptions>(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
resolvedMetadataFiles
), KotlinNativeFragmentMetadataCompilationData {
override val compileKotlinTaskName: String
get() = lowerCamelCaseName("compile", fragment.disambiguateName(""), "KotlinNativeMetadata")
override val isActive: Boolean
get() = fragment.isNativeShared()
override val kotlinOptions: NativeCompileOptions
get() = NativeCompileOptions { languageSettings }
override val konanTarget: KonanTarget
get() {
val nativeVariants =
fragment.containingModule.variantsContainingFragment(fragment).filterIsInstance<KotlinNativeVariantInternal>()
return nativeVariants.firstOrNull { it.konanTarget.enabledOnCurrentHost }?.konanTarget
?: nativeVariants.firstOrNull()?.konanTarget
?: HostManager.host
}
// FIXME endorsed libs?
override val enableEndorsedLibs: Boolean
get() = false
}
// TODO think about more generic case: a fragment that can be compiled by an arbitrary compiler
// what tasks should we create? should there be a generic task for that?
internal class MetadataCompilationRegistry {
private val commonCompilationDataPerFragment = mutableMapOf<KotlinGradleFragment, KotlinCommonFragmentMetadataCompilationDataImpl>()
private val nativeCompilationDataPerFragment = mutableMapOf<KotlinGradleFragment, KotlinNativeFragmentMetadataCompilationDataImpl>()
fun registerCommon(fragment: KotlinGradleFragment, compilationData: KotlinCommonFragmentMetadataCompilationDataImpl) {
commonCompilationDataPerFragment.compute(fragment) { _, existing ->
existing?.let { error("common compilation data for fragment $fragment already registered") }
compilationData
}
withAllCommonCallbacks.forEach { it.invoke(compilationData) }
}
fun registerNative(fragment: KotlinGradleFragment, compilationData: KotlinNativeFragmentMetadataCompilationDataImpl) {
nativeCompilationDataPerFragment.compute(fragment) { _, existing ->
existing?.let { error("native compilation data for fragment $fragment already registered") }
compilationData
}
withAllNativeCallbacks.forEach { it.invoke(compilationData) }
}
fun byFragment(fragment: KotlinGradleFragment): KotlinMetadataCompilationData<*> =
listOf(commonCompilationDataPerFragment.getValue(fragment), nativeCompilationDataPerFragment.getValue(fragment)).single {
it.isActive
}
private val withAllCommonCallbacks = mutableListOf<(AbstractKotlinFragmentMetadataCompilationData<*>) -> Unit>()
private val withAllNativeCallbacks = mutableListOf<(AbstractKotlinFragmentMetadataCompilationData<*>) -> Unit>()
fun withAll(action: (AbstractKotlinFragmentMetadataCompilationData<*>) -> Unit) {
commonCompilationDataPerFragment.forEach { action(it.value) }
nativeCompilationDataPerFragment.forEach { action(it.value) }
withAllCommonCallbacks += action
withAllNativeCallbacks += action
}
}
@@ -0,0 +1,77 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultCInteropSettings
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeCompileOptions
import org.jetbrains.kotlin.gradle.plugin.mpp.publishedConfigurationName
import org.jetbrains.kotlin.konan.target.KonanTarget
import javax.inject.Inject
open class KotlinNativeVariantInternal(
containingModule: KotlinGradleModule,
fragmentName: String,
val konanTarget: KonanTarget
) : KotlinNativeVariant,
KotlinGradleVariantInternal(containingModule, fragmentName),
SingleMavenPublicationHolder by DefaultSingleMavenPublicationHolder(containingModule, fragmentName) {
override var enableEndorsedLibraries: Boolean = false
override val gradleVariantNames: Set<String>
get() = listOf(apiElementsConfigurationName).flatMap { listOf(it, publishedConfigurationName(it)) }.toSet()
val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
DefaultCInteropSettings(project, cinteropName, compilationData)
}
internal val compilationData by lazy { KotlinNativeVariantCompilationData(this) }
}
// FIXME codegen
open class KotlinLinuxX64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.LINUX_X64)
open class KotlinMacosX64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.MACOS_X64)
open class KotlinMacosArm64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.MACOS_ARM64)
open class KotlinIosX64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.IOS_X64)
open class KotlinIosArm64Variant @Inject constructor(containingModule: KotlinGradleModule, fragmentName: String) :
KotlinNativeVariantInternal(containingModule, fragmentName, KonanTarget.IOS_ARM64)
internal val KotlinNativeVariant.hostSpecificMetadataConfigurationName
get() = disambiguateName("MetadataElements")
interface KotlinNativeCompilationData<T : KotlinCommonOptions> : KotlinCompilationData<T> {
val konanTarget: KonanTarget
val enableEndorsedLibs: Boolean
}
internal class KotlinNativeVariantCompilationData(
val variant: KotlinNativeVariantInternal
) : KotlinVariantCompilationDataInternal<KotlinCommonOptions>, KotlinNativeCompilationData<KotlinCommonOptions> {
override val konanTarget: KonanTarget
get() = variant.konanTarget
override val enableEndorsedLibs: Boolean
get() = variant.enableEndorsedLibraries
override val project: Project
get() = variant.containingModule.project
override val owner: KotlinNativeVariant
get() = variant
override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { languageSettings }
}
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION
import org.jetbrains.kotlin.project.model.refinesClosure
import org.jetbrains.kotlin.project.model.utils.variantsContainingFragment
import java.util.concurrent.Callable
import kotlin.reflect.KClass
open class KotlinNativeVariantFactory<T : KotlinNativeVariantInternal>(
@@ -27,12 +27,13 @@ abstract class AbstractKotlinGradleVariantFactory<T : KotlinGradleVariant>(
module: KotlinGradleModule
) : AbstractKotlinGradleFragmentFactory<T>(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)
@@ -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?
@@ -32,7 +32,7 @@ abstract class AbstractKotlinGradleFragmentFactory<T : KotlinGradleFragment>(
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
}
@@ -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<Jar>().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<DefaultTask>(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<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry
): KotlinCompilationData<out KotlinMultiplatformCommonOptions> {
) {
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<TransformKotlinGranularMetadataForFragment>()
.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<DefaultTask>,
metadataCompilationRegistry: MetadataCompilationRegistry
) {
val module = fragment.containingModule
val project = module.project
val metadataCompilationData =
KotlinNativeFragmentMetadataCompilationDataImpl(
project,
fragment,
module,
compileAllTask,
metadataCompilationRegistry,
lazy { resolvedMetadataProviders(fragment) }
)
NativeSharedCompilationProcessor(metadataCompilationData).run()
addSourcesToMetadataCompileTask(metadataCompilationData)
metadataCompilationRegistry.registerNative(fragment, metadataCompilationData)
}
private fun addSourcesToMetadataCompileTask(compilationData: AbstractKotlinFragmentMetadataCompilationData<*>) {
val sources = { compilationData.fragment.kotlinSourceRoots }
when (compilationData) {
// Note: this call is invalid for compilations that use Kotlin/Native compile tasks!
is KotlinCommonFragmentMetadataCompilationData -> addSourcesToKotlinCompileTask(
compilationData.project,
compilationData.compileKotlinTaskName,
/*FIXME*/ emptyList(),
sources,
lazyOf(true)
)
is KotlinNativeFragmentMetadataCompilationData -> addSourcesToKotlinNativeCompileTask(
compilationData.project,
compilationData.compileKotlinTaskName,
sources,
lazyOf(true)
)
else -> error("unexpected compilation data $compilationData")
}
}
private fun resolvedMetadataProviders(fragment: KotlinGradleFragment) =
fragment.refinesClosure.map {
FragmentResolvedMetadataProvider(
fragment.project.tasks.withType<TransformKotlinGranularMetadataForFragment>()
.named(transformFragmentMetadataTaskName(it))
)
}
private fun createExtractMetadataTask(
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()
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
fun <T> publishVariantWithSinglePublication(
variant: T
) where T : SingleMavenPublicationHolder, T : KotlinGradleVariant {
}
@@ -21,6 +21,8 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.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<KotlinNativeCompile>(kotlinCompilation) {
private val nativeTargetConfigurator = KotlinNativeTargetConfigurator<KotlinNativeTarget>(kotlinPluginVersion)
override val kotlinTask: TaskProvider<out KotlinNativeCompile> =
with(nativeTargetConfigurator) {
project.createKlibCompilationTask(kotlinCompilation)
}
override fun run() = Unit
}
override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider<out Zip> {
if (!target.project.isKotlinGranularMetadataEnabled)
return super.createArchiveTasks(target)
@@ -486,8 +474,28 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
}
}
internal fun Project.createGenerateProjectStructureMetadataTask(moduleClassifier: String? = null): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generate", moduleClassifier, "ProjectStructureMetadata")) { task ->
internal class NativeSharedCompilationProcessor(
override val kotlinCompilation: KotlinNativeFragmentMetadataCompilationData
) : KotlinCompilationProcessor<KotlinNativeCompile>(kotlinCompilation) {
private val nativeTargetConfigurator =
KotlinNativeTargetConfigurator<KotlinNativeTarget>(kotlinCompilation.project.getKotlinPluginVersion() ?: "" /*FIXME*/)
override val kotlinTask: TaskProvider<out KotlinNativeCompile> =
with(nativeTargetConfigurator) {
project.createKlibCompilationTask(kotlinCompilation)
}
override fun run() = Unit
}
internal fun Project.createGenerateProjectStructureMetadataTask(module: KotlinGradleModule): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generate", module.moduleClassifier, "ProjectStructureMetadata")) { task ->
task.lazyKotlinProjectStructureMetadata = lazy { buildProjectStructureMetadata(module) }
}
internal fun Project.createGenerateProjectStructureMetadataTask(): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generateProjectStructureMetadata")) { task ->
task.lazyKotlinProjectStructureMetadata = lazy { checkNotNull(buildKotlinProjectStructureMetadata(project)) }
}
@@ -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<File> = 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
)
}
@@ -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<String> = listOf()
}
abstract class AbstractKotlinNativeCompilation(
target: KotlinTarget,
val konanTarget: KonanTarget,
override val konanTarget: KonanTarget,
compilationName: String
) : AbstractKotlinCompilation<KotlinCommonOptions>(target, compilationName) {
) : AbstractKotlinCompilation<KotlinCommonOptions>(target, compilationName), KotlinNativeCompilationData<KotlinCommonOptions> {
override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { defaultSourceSet.languageSettings }
private class NativeCompileOptions(languageSettingsProvider: () -> LanguageSettingsBuilder) : KotlinCommonOptions {
private val languageSettings: LanguageSettingsBuilder by lazy(languageSettingsProvider)
override var apiVersion: String?
get() = languageSettings.apiVersion
set(value) { languageSettings.apiVersion = value }
override var languageVersion: String?
get() = languageSettings.languageVersion
set(value) { languageSettings.languageVersion = value }
override var useFir: Boolean
get() = false
set(@Suppress("UNUSED_PARAMETER") value) {}
override var allWarningsAsErrors: Boolean = false
override var suppressWarnings: Boolean = false
override var verbose: Boolean = false
override var freeCompilerArgs: List<String> = listOf()
}
override val compileKotlinTask: KotlinNativeCompile
get() = super.compileKotlinTask as KotlinNativeCompile
@@ -59,14 +68,25 @@ abstract class AbstractKotlinNativeCompilation(
override val compileKotlinTaskProvider: TaskProvider<out KotlinNativeCompile>
get() = super.compileKotlinTaskProvider as TaskProvider<out KotlinNativeCompile>
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) =
compileKotlinTaskProvider.configure { task ->
task.source(sourceSet.kotlin)
task.commonSources.from(target.project.files(Callable { if (addAsCommonSources.value) sourceSet.kotlin else emptyList<Any>() }))
}
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
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<File>,
addAsCommonSources: Lazy<Boolean>
) {
project.tasks.withType(KotlinNativeCompile::class.java).matching { it.name == taskName }.configureEach { task ->
task.source(sourceFiles)
task.commonSources.from(project.files(Callable { if (addAsCommonSources.value) sourceFiles() else emptyList() }))
}
}
class KotlinNativeCompilation(
@@ -117,6 +137,7 @@ class KotlinNativeCompilation(
}
class KotlinSharedNativeCompilation(override val target: KotlinMetadataTarget, val konanTargets: List<KonanTarget>, 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
}
@@ -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<KotlinSourceSet> {
val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project)
private val hostManager by lazy { HostManager() }
val enabledByHost = HostManager().enabledByHost
private fun isHostSpecificKonanTargetsSet(konanTargets: Iterable<KonanTarget>): 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 <T> getHostSpecificElements(
fragments: Iterable<T>,
isNativeShared: (T) -> Boolean,
getKonanTargets: (T) -> Set<KonanTarget>
): Set<T> = fragments.filterTo(mutableSetOf()) { isNativeShared(it) && isHostSpecificKonanTargetsSet(getKonanTargets(it)) }
// If the source set participates in compilations such that some host can't run either of them, then on that host,
// 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<KotlinNativeCompilation>()
val nativeEnabledOn = nativeCompilations.flatMapTo(mutableSetOf()) { compilation -> canBeBuiltOnHosts(compilation.konanTarget) }
platformCompilations == nativeCompilations && allHosts != nativeEnabledOn
internal fun getHostSpecificFragments(
module: KotlinGradleModule
): Set<KotlinGradleFragment> = getHostSpecificElements<KotlinGradleFragment>(
module.fragments,
isNativeShared = { it.isNativeShared() },
getKonanTargets = {
val nativeVariants = module.variantsContainingFragment(it).filterIsInstance<KotlinNativeVariantInternal>()
nativeVariants.mapTo(mutableSetOf()) { it.konanTarget }
}
)
internal fun getHostSpecificSourceSets(project: Project): Set<KotlinSourceSet> {
val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project).mapValues { (_, compilations) ->
compilations.filter { it !is KotlinMetadataCompilation<*> }
}
return getHostSpecificElements(
project.kotlinExtension.sourceSets,
isNativeShared = { sourceSet ->
val compilations = compilationsBySourceSet[sourceSet].orEmpty()
compilations.isNotEmpty() && compilations.all { it.platformType == KotlinPlatformType.native }
},
getKonanTargets = { sourceSet ->
compilationsBySourceSet[sourceSet].orEmpty()
.filterIsInstance<KotlinNativeCompilation>()
.mapTo(mutableSetOf()) { it.konanTarget }
}
)
}
abstract class KotlinNativeTargetWithTests<T : KotlinNativeBinaryTestRun>(
@@ -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<T : KotlinNativeTarget>(
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<T : KotlinNativeTarget>(
}
}
// region Artifact creation.
private val KotlinNativeCompilationData<*>.apiElementsConfigurationName: String
get() = when (val dataOwner = owner) {
is KotlinGradleVariant -> dataOwner.apiElementsConfigurationName
is KotlinTarget -> dataOwner.apiElementsConfigurationName
else -> error("unexpected owner of $this")
}
internal fun Project.createRegularKlibArtifact(
compilation: KotlinNativeCompilationData<*>,
compileTask: TaskProvider<out KotlinNativeCompile>
) = createKlibArtifact(compilation, compileTask.map { it.outputFile.get() }, null, compileTask)
internal fun Project.createCInteropKlibArtifact(
interop: DefaultCInteropSettings,
interopTask: TaskProvider<out CInteropProcess>
) = createKlibArtifact(interop.compilation, interopTask.map { it.outputFile }, "cinterop-${interop.name}", interopTask, copy = true)
private fun Project.createKlibArtifact(
compilation: KotlinNativeCompilation,
compilation: KotlinNativeCompilationData<*>,
artifactFile: Provider<File>,
classifier: String?,
producingTask: TaskProvider<*>,
@@ -85,14 +103,14 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
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>("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<T : KotlinNativeTarget>(
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<T : KotlinNativeTarget>(
attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
}
}
private fun Project.createRegularKlibArtifact(
compilation: KotlinNativeCompilation,
compileTask: TaskProvider<out KotlinNativeCompile>
) = createKlibArtifact(compilation, compileTask.map { it.outputFile.get() }, null, compileTask)
private fun Project.createCInteropKlibArtifact(
interop: DefaultCInteropSettings,
interopTask: TaskProvider<out CInteropProcess>
) = createKlibArtifact(interop.compilation, interopTask.map { it.outputFile }, "cinterop-${interop.name}", interopTask, copy = true)
// endregion.
// region Task creation.
private fun Project.createLinkTask(binary: NativeBinary) {
val result = registerTask<KotlinNativeLink>(
@@ -258,12 +264,12 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
}
}
internal fun Project.createKlibCompilationTask(compilation: AbstractKotlinNativeCompilation): TaskProvider<KotlinNativeCompile> {
internal fun Project.createKlibCompilationTask(compilation: KotlinNativeCompilationData<*>): TaskProvider<KotlinNativeCompile> {
val compileTaskProvider = registerTask<KotlinNativeCompile>(
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<T : KotlinNativeTarget>(
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<DefaultCInteropSettings>
) {
cinterops.all { interop ->
val interopTask = registerTask<CInteropProcess>(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<T : KotlinNativeTarget>(
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)
}
@@ -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,
/**
@@ -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}")
}
}
@@ -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<File>.filterKlibsPassedToCompiler(project: Project) = fil
}
// endregion
abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : AbstractKotlinNativeCompilation> : AbstractCompile() {
abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : KotlinNativeCompilationData<*>> : AbstractCompile() {
@get:Internal
abstract val compilation: K
@@ -139,7 +142,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : Abst
}
private val isSharedCompilation by project.provider {
compilation is KotlinSharedNativeCompilation
compilation is KotlinNativeFragmentMetadataCompilationData
}
// Inputs and outputs
@@ -178,7 +181,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : Abst
@get:Internal
val languageSettings: LanguageSettingsBuilder by project.provider {
compilation.defaultSourceSet.languageSettings
compilation.languageSettings
}
@get:Input
@@ -233,7 +236,7 @@ abstract class AbstractKotlinNativeCompile<T : KotlinCommonToolOptions, K : Abst
get() = buildCommonArgs(true)
private val languageSettingsBuilder by project.provider {
compilation.defaultSourceSet.languageSettings
compilation.languageSettings
}
// Args used by both the compiler and IDEA.
@@ -343,8 +346,8 @@ open class KotlinNativeCompile
constructor(
@Internal
@Transient // can't be serialized for Gradle configuration cache
final override val compilation: AbstractKotlinNativeCompilation
) : AbstractKotlinNativeCompile<KotlinCommonOptions, AbstractKotlinNativeCompilation>(),
final override val compilation: KotlinNativeCompilationData<*>
) : AbstractKotlinNativeCompile<KotlinCommonOptions, KotlinNativeCompilationData<*>>(),
KotlinCompile<KotlinCommonOptions> {
@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"
}
@@ -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<K2MetadataCompilerArgumen
args.moduleName = this@KotlinCompileCommon.moduleName
if ((taskData.compilation as? KotlinCommonCompilation)?.isKlibCompilation == true ||
taskData.compilation is KotlinFragmentMetadataCompilationData
taskData.compilation is KotlinMetadataCompilationData
) {
args.expectActualLinker = true
}
@@ -84,13 +84,10 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
}
private fun outputPathsFromMetadataCompilationsOf(sourceSets: Iterable<KotlinSourceSet>): List<File> {
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<K2MetadataCompilerArgumen
val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet
outputPathsFromMetadataCompilationsOf(defaultKotlinSourceSet.resolveAllDependsOnSourceSets())
}
is KotlinFragmentMetadataCompilationData -> {
is AbstractKotlinFragmentMetadataCompilationData -> {
val fragment = compilation.fragment
project.files(
fragment.refinesClosure.minus(fragment).map {
@@ -109,7 +106,7 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
}
)
}
else -> error("unexpected compilation type") // FIXME support PM20 variant
else -> error("unexpected compilation type")
}
}
@@ -25,15 +25,15 @@ interface KotlinDependencyGraphResolver {
fun resolveDependencyGraph(requestingModule: KotlinModule): DependencyGraphResolution
}
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<KotlinModuleFragment, Iterable<DependencyGraphNode>>
open class DependencyGraphNode(
open val module: KotlinModule,
open val dependenciesByFragment: Map<KotlinModuleFragment, Iterable<DependencyGraphNode>>
) {
override fun toString(): String = "node ${module}"
}