Prepare intermediate layer of model mapping in Kotlin compilations

Extract all logic and internal model that may be different in different
modes to a separate entity called "compilation details"
This commit is contained in:
Sergey Igushkin
2022-02-01 17:48:53 +04:00
committed by Space
parent 8753ea592f
commit 3f49217cc9
19 changed files with 840 additions and 583 deletions
@@ -77,9 +77,6 @@ interface KotlinCompilation<out T : KotlinCommonOptions> : Named, HasAttributes,
override fun getName(): String = compilationName
override val relatedConfigurationNames: List<String>
get() = super.relatedConfigurationNames + compileDependencyConfigurationName
val moduleName: String
val disambiguatedName
@@ -100,4 +97,4 @@ val <T : KotlinCommonOptions> KotlinCompilation<T>.runtimeDependencyConfiguratio
interface KotlinCompilationWithResources<T : KotlinCommonOptions> : KotlinCompilation<T> {
val processResourcesTaskName: String
}
}
@@ -0,0 +1,636 @@
/*
* 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
import groovy.lang.Closure
import org.gradle.api.Project
import org.gradle.api.UnknownTaskException
import org.gradle.api.artifacts.Dependency
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginExtension
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.KotlinCompilationsModuleGroups
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.newDependencyFilesHolder
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ofVariantCompileDependencies
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.unambiguousNameInProject
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssociateCompilations
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.plugin.sources.withAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.targets.metadata.getMetadataCompilationForSourceSet
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.project.model.LanguageSettings
import java.util.*
import java.util.concurrent.Callable
interface CompilationDetails<T : KotlinCommonOptions> {
val target: KotlinTarget
val compileDependencyFilesHolder: DependencyFilesHolder
val kotlinDependenciesHolder: HasKotlinDependencies
val compilationData: KotlinCompilationData<T>
fun associateWith(other: CompilationDetails<*>)
val associateCompilations: Set<CompilationDetails<*>>
fun source(sourceSet: KotlinSourceSet)
val directlyIncludedKotlinSourceSets: MutableSet<KotlinSourceSet>
val defaultSourceSetName: String
@Suppress("UNCHECKED_CAST")
val compilation: KotlinCompilation<T>
get() = target.compilations.getByName(compilationData.compilationPurpose) as KotlinCompilation<T>
val defaultSourceSet: KotlinSourceSet
get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName)
}
interface CompilationDetailsWithRuntime<T : KotlinCommonOptions> : CompilationDetails<T> {
val runtimeDependencyFilesHolder: DependencyFilesHolder
}
internal val CompilationDetails<*>.associateWithTransitiveClosure: Iterable<CompilationDetails<*>>
get() = mutableSetOf<CompilationDetails<*>>().apply {
fun visit(other: CompilationDetails<*>) {
if (add(other)) {
other.associateCompilations.forEach(::visit)
}
}
associateCompilations.forEach(::visit)
}
open class DefaultCompilationDetails<T : KotlinCommonOptions>(
final override val target: KotlinTarget,
final override val compilationPurpose: String,
createKotlinOptions: DefaultCompilationDetails<*>.() -> T
) : CompilationDetails<T>, KotlinCompilationData<T> {
override val kotlinOptions: T by lazy { createKotlinOptions() }
final override val project: Project
get() = target.project
override val owner: KotlinTarget
get() = target
override val compilationData: KotlinCompilationData<T>
get() = this
override val kotlinDependenciesHolder: HasKotlinDependencies
get() = KotlinDependencyConfigurationsHolder(
project,
lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
)
)
override val compileDependencyFilesHolder: DependencyFilesHolder = project.newDependencyFilesHolder(
lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
"compileClasspath"
)
)
override val directlyIncludedKotlinSourceSets: MutableSet<KotlinSourceSet> = mutableSetOf()
override val defaultSourceSetName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier.takeIf { target !is KotlinMetadataTarget },
when {
isMainCompilationData() && target is KotlinMetadataTarget ->
KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME // corner case: main compilation of the metadata target compiles commonMain
else -> compilationPurpose
}
)
override val compilationClassifier: String?
get() = target.disambiguationClassifier
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = directlyIncludedKotlinSourceSets.plus(directlyIncludedKotlinSourceSets.resolveAllDependsOnSourceSets())
.associate { it.name to it.kotlin }
override val compileKotlinTaskName: String
get() = lowerCamelCaseName(
"compile",
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
"Kotlin",
target.targetName
)
override val compileAllTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "classes")
override val compileDependencyFiles: FileCollection
get() = compileDependencyFilesHolder.dependencyFiles
override val output: KotlinCompilationOutput = DefaultKotlinCompilationOutput(
target.project,
Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$compilationPurpose") }
)
override val languageSettings: LanguageSettings
get() = project.kotlinExtension.sourceSets.getByName(defaultSourceSetName).languageSettings
override val platformType: KotlinPlatformType
get() = target.platformType
override val moduleName: String
get() = KotlinCompilationsModuleGroups.getModuleLeaderCompilation(this).takeIf { it != this }?.ownModuleName ?: ownModuleName
override val ownModuleName: String
get() {
val baseName = project.extensions.getByType(BasePluginExtension::class.java)?.archivesName
?: project.name
val suffix = if (isMainCompilationData()) "" else "_$compilationPurpose"
return filterModuleName("$baseName$suffix")
}
override val friendPaths: Iterable<FileCollection>
get() = mutableListOf<FileCollection>().also { allCollections ->
associateWithTransitiveClosure.forEach { allCollections.add(it.compilationData.output.classesDirs) }
allCollections.add(friendArtifacts)
}
private val friendArtifactsTask: TaskProvider<AbstractArchiveTask>? by lazy {
if (associateWithTransitiveClosure.any { it.compilationData.isMainCompilationData() }) {
val archiveTasks = target.project.tasks.withType(AbstractArchiveTask::class.java)
if (!archiveTasks.isEmpty()) {
try {
archiveTasks.named(target.artifactsTaskName)
} catch (e: UnknownTaskException) {
// Native tasks does not extend AbstractArchiveTask
null
}
} else {
null
}
} else {
null
}
}
/**
* If a compilation is aware of its associate compilations' outputs being added to the classpath in a transformed or packaged way,
* it should point to those friend artifact files via this property.
*/
internal open val friendArtifacts: FileCollection
get() = with(target.project) {
val friendArtifactsTaskProvider = friendArtifactsTask
if (friendArtifactsTaskProvider != null) {
// In case the main artifact is transitively added to the test classpath via a test dependency on another module
// that depends on this module's production part, include the main artifact in the friend artifacts, lazily:
files(
Callable {
friendArtifactsTaskProvider.flatMap { it.archiveFile }
}
)
} else files()
}
override val associateCompilations: Set<CompilationDetails<*>>
get() = Collections.unmodifiableSet(_associateCompilations)
private val _associateCompilations = mutableSetOf<CompilationDetails<*>>()
override fun associateWith(other: CompilationDetails<*>) {
require(other.target == target) { "Only associations between compilations of a single target are supported" }
_associateCompilations += other
addAssociateCompilationDependencies(other.compilation)
KotlinCompilationsModuleGroups.unionModules(this, other.compilationData)
_associateCompilations.add(other)
}
@OptIn(ExperimentalStdlibApi::class)
protected open fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) = with(compilationData) {
/*
we add dependencies to compileDependencyConfiguration ('compileClasspath' usually) and runtimeDependency
('runtimeClasspath') instead of modifying respective api/implementation/compileOnly/runtimeOnly configs
This is needed because api/implementation/compileOnly/runtimeOnly are used in IDE Import and will leak
to dependencies of IDE modules. But they are not needed here, because IDE resolution works inherently
transitively and symbols from associated compilation will be resolved from source sets of associated
compilation itself (moreover, direct dependencies are not equivalent to transitive ones because of
resolution order - e.g. in case of FQNs clash, so it's even harmful)
*/
project.dependencies.add(compilation.compileOnlyConfigurationName, project.files(Callable { other.output.classesDirs }))
project.dependencies.add(compilation.runtimeOnlyConfigurationName, project.files(Callable { other.output.allOutputs }))
compilation.compileDependencyConfigurationName.addAllDependenciesFromOtherConfigurations(
project,
other.apiConfigurationName,
other.implementationConfigurationName,
other.compileOnlyConfigurationName
)
compilation.runtimeDependencyConfigurationName?.addAllDependenciesFromOtherConfigurations(
project,
other.apiConfigurationName,
other.implementationConfigurationName,
other.runtimeOnlyConfigurationName
)
}
/**
* Adds `allDependencies` of configurations mentioned in `configurationNames` to configuration named [this] in
* a lazy manner
*/
private fun String.addAllDependenciesFromOtherConfigurations(project: Project, vararg configurationNames: String) {
project.configurations.named(this).configure { receiverConfiguration ->
receiverConfiguration.dependencies.addAllLater(
project.objects.listProperty(Dependency::class.java).apply {
set(
project.provider {
configurationNames
.map { project.configurations.getByName(it) }
.flatMap { it.allDependencies }
}
)
}
)
}
}
override fun source(sourceSet: KotlinSourceSet) {
if (directlyIncludedKotlinSourceSets.add(sourceSet)) {
target.project.whenEvaluated {
addExactSourceSetsEagerly(sourceSet.withAllDependsOnSourceSets())
}
}
}
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) =
addSourcesToKotlinCompileTask(
project,
compileKotlinTaskName,
sourceSet.customSourceFilesExtensions,
addAsCommonSources
) { sourceSet.kotlin }
internal fun addExactSourceSetsEagerly(sourceSets: Set<KotlinSourceSet>) {
with(target.project) {
//TODO possibly issue with forced instantiation
sourceSets.forEach { sourceSet ->
addSourcesToCompileTask(
sourceSet,
addAsCommonSources = lazy {
CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project).contains(sourceSet.name)
}
)
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
// old Java & Android projects:
addExtendsFromRelation(compilation.apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
addExtendsFromRelation(
compilation.implementationConfigurationName,
sourceSet.implementationConfigurationName,
forced = false
)
addExtendsFromRelation(compilation.compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
if (compilation is KotlinCompilationToRunnableFiles<*>) {
addExtendsFromRelation(compilation.runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
}
if (sourceSet.name != defaultSourceSetName) {
kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
// Temporary solution for checking consistency across source sets participating in a compilation that may
// not be interconnected with the dependsOn relation: check the settings as if the default source set of
// the compilation depends on the one added to the compilation:
defaultSourceSetLanguageSettingsChecker.runAllChecks(
defaultSourceSet,
sourceSet
)
}
}
}
}
}
}
internal open class DefaultCompilationDetailsWithRuntime<T : KotlinCommonOptions>(
target: KotlinTarget,
compilationPurpose: String,
createKotlinOptions: DefaultCompilationDetails<*>.() -> T
) : DefaultCompilationDetails<T>(target, compilationPurpose, createKotlinOptions), CompilationDetailsWithRuntime<T> {
override val runtimeDependencyFilesHolder: DependencyFilesHolder = project.newDependencyFilesHolder(
lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
"runtimeClasspath"
)
)
}
open class NativeCompilationDetails(
target: KotlinTarget,
compilationPurpose: String,
createKotlinOptions: DefaultCompilationDetails<*>.() -> KotlinCommonOptions
) : DefaultCompilationDetails<KotlinCommonOptions>(
target,
compilationPurpose,
createKotlinOptions
) {
override val compileDependencyFilesHolder: DependencyFilesHolder = project.newDependencyFilesHolder(
lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
"compileKlibraries"
)
)
override val compileAllTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "klibrary")
override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
compileDependencyFilesHolder.dependencyFiles +=
other.output.classesDirs + project.filesProvider { other.compileDependencyFiles }
target.project.configurations.named(compilation.implementationConfigurationName).configure { configuration ->
configuration.extendsFrom(target.project.configurations.findByName(other.implementationConfigurationName))
}
}
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources)
}
}
internal open class SharedNativeCompilationDetails(
target: KotlinTarget,
compilationPurpose: String,
createKotlinOptions: DefaultCompilationDetails<*>.() -> KotlinCommonOptions
) :
DefaultCompilationDetails<KotlinCommonOptions>(
target,
compilationPurpose,
createKotlinOptions
) {
override val friendArtifacts: FileCollection
get() = super.friendArtifacts.plus(run {
val project = target.project
val friendSourceSets = getVisibleSourceSetsFromAssociateCompilations(project, defaultSourceSet).toMutableSet().apply {
// TODO: implement proper dependsOn/refines compiler args for Kotlin/Native and pass the dependsOn klibs separately;
// But for now, those dependencies don't have any special semantics, so passing all them as friends works, too
addAll(defaultSourceSet.resolveAllDependsOnSourceSets())
}
project.files(friendSourceSets.mapNotNull { project.getMetadataCompilationForSourceSet(it)?.output?.classesDirs })
})
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources)
}
}
internal open class VariantMappedCompilationDetails<T : KotlinCommonOptions>(
open val variant: KotlinGradleVariantInternal,
override val target: KotlinTarget
) : CompilationDetails<T> {
@Suppress("UNCHECKED_CAST")
override val compilationData: KotlinCompilationData<T>
get() = variant.compilationData as KotlinCompilationData<T>
override val defaultSourceSetName: String
get() = variant.unambiguousNameInProject
override fun source(sourceSet: KotlinSourceSet) {
compilation.defaultSourceSet.dependsOn(sourceSet)
}
override fun associateWith(other: CompilationDetails<*>) {
throw UnsupportedOperationException("not supported in the mapped model")
}
override val associateCompilations: Set<CompilationDetails<*>> get() = emptySet()
override val compileDependencyFilesHolder: DependencyFilesHolder
get() = DependencyFilesHolder.ofVariantCompileDependencies(variant)
override val kotlinDependenciesHolder: HasKotlinDependencies
get() = variant
override val directlyIncludedKotlinSourceSets: MutableSet<KotlinSourceSet>
// FIXME: this effectively ignores the mutation of the set!
get() = compilation.defaultSourceSet.dependsOn.toMutableSet()
}
internal open class VariantMappedCompilationDetailsWithRuntime<T : KotlinCommonOptions>(
override val variant: KotlinGradleVariantWithRuntimeInternal,
target: KotlinTarget
) : VariantMappedCompilationDetails<T>(variant, target),
CompilationDetailsWithRuntime<T> {
override val runtimeDependencyFilesHolder: DependencyFilesHolder
get() = DependencyFilesHolder.ofVariantRuntimeDependencies(variant)
}
internal class WithJavaCompilationDetails<T : KotlinCommonOptions>(
target: KotlinTarget,
compilationPurpose: String,
createKotlinOptions: DefaultCompilationDetails<*>.() -> T
) : DefaultCompilationDetailsWithRuntime<T>(target, compilationPurpose, createKotlinOptions) {
override val compilation: KotlinWithJavaCompilation<T>
get() = super.compilation as KotlinWithJavaCompilation<T>
val javaSourceSet: SourceSet
get() = compilation.javaSourceSet
override val output: KotlinCompilationOutput by lazy { KotlinWithJavaCompilationOutput(compilation) }
override val compileDependencyFilesHolder: DependencyFilesHolder
get() = object : DependencyFilesHolder {
override val dependencyConfigurationName: String by javaSourceSet::compileClasspathConfigurationName
override var dependencyFiles: FileCollection by javaSourceSet::compileClasspath
}
override val runtimeDependencyFilesHolder: DependencyFilesHolder
get() = object : DependencyFilesHolder {
override val dependencyConfigurationName: String by javaSourceSet::runtimeClasspathConfigurationName
override var dependencyFiles: FileCollection by javaSourceSet::runtimeClasspath
}
override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
if (compilationPurpose != SourceSet.TEST_SOURCE_SET_NAME || other.name != SourceSet.MAIN_SOURCE_SET_NAME) {
super.addAssociateCompilationDependencies(other)
} // otherwise, do nothing: the Java Gradle plugin adds these dependencies for us, we don't need to add them to the classpath
}
}
internal class AndroidCompilationDetails(
target: KotlinTarget,
compilationPurpose: String,
) : DefaultCompilationDetailsWithRuntime<KotlinJvmOptions>(
target,
compilationPurpose,
{ KotlinJvmOptionsImpl() }
) {
override val compilation: KotlinJvmAndroidCompilation
get() = super.compilation as KotlinJvmAndroidCompilation
val androidVariant = compilation.androidVariant
override val friendArtifacts: FileCollection
get() = target.project.files(super.friendArtifacts, compilation.testedVariantArtifacts)
override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
if ((other as? KotlinJvmAndroidCompilation)?.androidVariant != getTestedVariantData(androidVariant)) {
super.addAssociateCompilationDependencies(other)
} // otherwise, do nothing: the Android Gradle plugin adds these dependencies for us, we don't need to add them to the classpath
}
override val kotlinDependenciesHolder: HasKotlinDependencies
get() = object : HasKotlinDependencies by super.kotlinDependenciesHolder {
override val relatedConfigurationNames: List<String>
get() = super.relatedConfigurationNames + listOf(
"${androidVariant.name}ApiElements",
"${androidVariant.name}RuntimeElements",
androidVariant.compileConfiguration.name,
androidVariant.runtimeConfiguration.name
)
}
}
internal class MetadataCompilationDetails(target: KotlinTarget, name: String) :
DefaultCompilationDetails<KotlinMultiplatformCommonOptions>(
target,
name,
{ KotlinMultiplatformCommonOptionsImpl() }
) {
override val friendArtifacts: FileCollection
get() = super.friendArtifacts.plus(run {
val project = target.project
val friendSourceSets = getVisibleSourceSetsFromAssociateCompilations(target.project, defaultSourceSet)
project.files(friendSourceSets.mapNotNull { target.compilations.findByName(it.name)?.output?.classesDirs })
})
}
internal open class JsCompilationDetails(
target: KotlinTarget,
compilationPurpose: String,
) : DefaultCompilationDetailsWithRuntime<KotlinJsOptions>(target, compilationPurpose, { KotlinJsOptionsImpl() }) {
protected open class JsCompilationDependenciesHolder(
val target: KotlinTarget,
val compilationPurpose: String,
val parent: HasKotlinDependencies
) : HasKotlinDependencies by parent {
override val apiConfigurationName: String
get() = disambiguateNameInPlatform(API)
override val implementationConfigurationName: String
get() = disambiguateNameInPlatform(IMPLEMENTATION)
override val compileOnlyConfigurationName: String
get() = disambiguateNameInPlatform(COMPILE_ONLY)
override val runtimeOnlyConfigurationName: String
get() = disambiguateNameInPlatform(RUNTIME_ONLY)
protected open val disambiguationClassifierInPlatform: String?
get() = when (target) {
is KotlinJsTarget -> target.disambiguationClassifierInPlatform
is KotlinJsIrTarget -> target.disambiguationClassifierInPlatform
else -> error("Unexpected target type of $target")
}
private fun disambiguateNameInPlatform(simpleName: String): String {
return lowerCamelCaseName(
disambiguationClassifierInPlatform,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
simpleName
)
}
}
override val kotlinDependenciesHolder: HasKotlinDependencies
get() = JsCompilationDependenciesHolder(target, compilationPurpose, super.kotlinDependenciesHolder)
override val defaultSourceSetName: String
get() {
val classifier = if (target is KotlinJsTarget && target.irTarget != null)
target.disambiguationClassifierInPlatform
else target.disambiguationClassifier
return lowerCamelCaseName(
classifier,
compilationPurpose
)
}
}
internal class JsIrCompilationDetails(target: KotlinTarget, compilationPurpose: String) :
JsCompilationDetails(target, compilationPurpose) {
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
super.addSourcesToCompileTask(sourceSet, addAsCommonSources)
(compilation as KotlinJsIrCompilation).allSources.add(sourceSet.kotlin)
}
override val defaultSourceSetName: String
get() {
val target = target as KotlinJsIrTarget
return lowerCamelCaseName(
if (target.mixedMode)
target.disambiguationClassifierInPlatform
else
target.disambiguationClassifier,
compilationPurpose
)
}
private class JsIrCompilationDependencyHolder(target: KotlinTarget, compilationPurpose: String, parent: HasKotlinDependencies) :
JsCompilationDependenciesHolder(target, compilationPurpose, parent) {
override val disambiguationClassifierInPlatform: String?
get() = (target as KotlinJsIrTarget).disambiguationClassifierInPlatform
}
override val kotlinDependenciesHolder: HasKotlinDependencies
get() = JsIrCompilationDependencyHolder(target, compilationPurpose, super.kotlinDependenciesHolder)
}
internal class KotlinDependencyConfigurationsHolder(
val project: Project,
private val configurationNamesPrefix: String?,
) : HasKotlinDependencies {
override val apiConfigurationName: String
get() = lowerCamelCaseName(configurationNamesPrefix, API)
override val implementationConfigurationName: String
get() = lowerCamelCaseName(configurationNamesPrefix, IMPLEMENTATION)
override val compileOnlyConfigurationName: String
get() = lowerCamelCaseName(configurationNamesPrefix, COMPILE_ONLY)
override val runtimeOnlyConfigurationName: String
get() = lowerCamelCaseName(configurationNamesPrefix, RUNTIME_ONLY)
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
DefaultKotlinDependencyHandler(this, project).run(configure)
override fun dependencies(configureClosure: Closure<Any?>) =
dependencies f@{ project.configure(this@f, configureClosure) }
}
@@ -21,9 +21,9 @@ interface KotlinMetadataCompilation<T : KotlinCommonOptions> : KotlinCompilation
class KotlinCommonCompilation(
target: KotlinTarget,
name: String
) : AbstractKotlinCompilation<KotlinMultiplatformCommonOptions>(target, name), KotlinMetadataCompilation<KotlinMultiplatformCommonOptions> {
override val kotlinOptions: KotlinMultiplatformCommonOptions = KotlinMultiplatformCommonOptionsImpl()
) : AbstractKotlinCompilation<KotlinMultiplatformCommonOptions>(
MetadataCompilationDetails(target, name)
), KotlinMetadataCompilation<KotlinMultiplatformCommonOptions> {
override val compileKotlinTask: KotlinCompileCommon
get() = super.compileKotlinTask as KotlinCompileCommon
@@ -32,11 +32,4 @@ class KotlinCommonCompilation(
get() = target.project.isKotlinGranularMetadataEnabled && !forceCompilationToKotlinMetadata
internal var forceCompilationToKotlinMetadata: Boolean = false
override val friendArtifacts: FileCollection
get() = super.friendArtifacts.plus(run {
val project = target.project
val friendSourceSets = getVisibleSourceSetsFromAssociateCompilations(target.project, defaultSourceSet)
project.files(friendSourceSets.mapNotNull { target.compilations.findByName(it.name)?.output?.classesDirs })
})
}
@@ -9,6 +9,8 @@ import org.gradle.api.Project
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData
/** This is a disjoint-set union-like approach to having a module name that is equal across associated compilations, as the compiler
* now requires that to properly compile internal calls to friend classes. Associating a compilation with another one leads to their
@@ -17,10 +19,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
* TODO: once the compiler is able to correctly generate calls to internals in other modules, remove this logic.
*/
internal class KotlinCompilationsModuleGroups {
private val moduleLeaderCompilationMap: MutableMap<KotlinCompilation<*>, KotlinCompilation<*>> =
private val moduleLeaderCompilationMap: MutableMap<KotlinCompilationData<*>, KotlinCompilationData<*>> =
mutableMapOf()
fun getModuleLeader(compilation: KotlinCompilation<*>): KotlinCompilation<*> {
fun getModuleLeader(compilation: KotlinCompilationData<*>): KotlinCompilationData<*> {
if (compilation !in moduleLeaderCompilationMap) {
moduleLeaderCompilationMap[compilation] = compilation
}
@@ -31,7 +33,7 @@ internal class KotlinCompilationsModuleGroups {
}
}
fun unionModules(compilationA: KotlinCompilation<*>, compilationB: KotlinCompilation<*>) {
fun unionModules(compilationA: KotlinCompilationData<*>, compilationB: KotlinCompilationData<*>) {
val aLeader = getModuleLeader(compilationA)
val bLeader = getModuleLeader(compilationB)
@@ -41,10 +43,10 @@ internal class KotlinCompilationsModuleGroups {
listOf(aLeader, bLeader).run {
/** heuristically choose the new leader: choose `main` when possible, don't choose `*test*` when there's an alternative,
* if that didn't work, choose the first name lexicographically */
val newLeader = singleOrNull { it.isMain() }
?: singleOrNull { it.name.contains("main", true) }
?: singleOrNull { !it.name.contains("test", true) }
?: minByOrNull { it.name }!!
val newLeader = singleOrNull { it.isMainCompilationData() }
?: singleOrNull { it.compilationPurpose.contains("main", true) }
?: singleOrNull { !it.compilationPurpose.contains("test", true) }
?: minByOrNull { it.compilationPurpose }!!
forEach { moduleLeaderCompilationMap[it] = newLeader }
}
@@ -53,11 +55,11 @@ internal class KotlinCompilationsModuleGroups {
companion object {
private const val EXT_NAME = "kotlin.compilations.moduleGroups"
fun getModuleLeaderCompilation(compilation: KotlinCompilation<*>): KotlinCompilation<*> =
getInstance(compilation.target.project).getModuleLeader(compilation)
fun getModuleLeaderCompilation(compilation: KotlinCompilationData<*>): KotlinCompilationData<*> =
getInstance(compilation.project).getModuleLeader(compilation)
fun unionModules(compilationA: KotlinCompilation<*>, compilationB: KotlinCompilation<*>) {
getInstance(compilationA.target.project).unionModules(compilationA, compilationB)
fun unionModules(compilationA: KotlinCompilationData<*>, compilationB: KotlinCompilationData<*>) {
getInstance(compilationA.project).unionModules(compilationA, compilationB)
}
private fun getInstance(project: Project): KotlinCompilationsModuleGroups {
@@ -9,25 +9,16 @@ import groovy.lang.Closure
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.UnknownTaskException
import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.plugins.BasePluginExtension
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.provider.Property
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.TaskState
import org.gradle.api.tasks.bundling.AbstractArchiveTask
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.internal.KotlinCompilationsModuleGroups
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
import org.jetbrains.kotlin.gradle.plugin.sources.withAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.*
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.locateTask
@@ -54,12 +45,29 @@ internal fun KotlinCompilation<*>.isMain(): Boolean =
internal val KotlinCompilation<*>.kotlinSourceSetsIncludingDefault: Set<KotlinSourceSet> get() = kotlinSourceSets + defaultSourceSet
abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
target: KotlinTarget,
override val compilationPurpose: String
) : KotlinCompilation<T>, HasKotlinDependencies, KotlinCompilationData<T> {
internal open val compilationDetails: CompilationDetails<T>
) : KotlinCompilation<T>,
// FIXME: replace with separate `final override`s, which is safer wrt accidental overrides
HasKotlinDependencies by compilationDetails.kotlinDependenciesHolder,
KotlinCompilationData<T> by compilationDetails.compilationData {
override val compilationName: String
get() = compilationPurpose
override val target: KotlinTarget get() = compilationDetails.target
final override val compileDependencyConfigurationName: String
get() = compilationDetails.compileDependencyFilesHolder.dependencyConfigurationName
// FIXME: use delegation to callable reference once KT-50019 is fixed
final override var compileDependencyFiles: FileCollection
get() = compilationDetails.compileDependencyFilesHolder.dependencyFiles
set(value) {
compilationDetails.compileDependencyFilesHolder.dependencyFiles = value
}
override val platformType: KotlinPlatformType get() = compilationDetails.compilationData.platformType
final override val kotlinSourceSets: MutableSet<KotlinSourceSet> get() = compilationDetails.directlyIncludedKotlinSourceSets
final override val defaultSourceSetName: String get() = compilationDetails.defaultSourceSetName
final override val compilationName: String get() = compilationDetails.compilationData.compilationPurpose
override fun kotlinOptions(configure: T.() -> Unit) =
configure(kotlinOptions)
@@ -72,242 +80,27 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val compileKotlinTaskProvider: TaskProvider<out KotlinCompile<T>>
get() = target.project.locateTask(compileKotlinTaskName) ?: throw GradleException("Couldn't locate task $compileKotlinTaskName")
// Don't declare this property in the constructor to avoid NPE
// when an overriding property of a subclass is accessed instead.
@Suppress("CanBePrimaryConstructorProperty")
override val target: KotlinTarget = target
private val attributeContainer = HierarchyAttributeContainer(target.attributes)
private val attributeContainer by lazy { HierarchyAttributeContainer(target.attributes) }
override fun getAttributes(): AttributeContainer = attributeContainer
override val kotlinSourceSets: MutableSet<KotlinSourceSet> = mutableSetOf()
override val allKotlinSourceSets: Set<KotlinSourceSet>
get() = kotlinSourceSets + kotlinSourceSets.resolveAllDependsOnSourceSets()
override val defaultSourceSetName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier.takeIf { target !is KotlinMetadataTarget },
when {
isMain() && target is KotlinMetadataTarget ->
KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME // corner case: main compilation of the metadata target compiles commonMain
else -> compilationPurpose
}
)
override val defaultSourceSet: KotlinSourceSet
get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName)
override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) = defaultSourceSet.configure()
override val output: KotlinCompilationOutput by lazy {
DefaultKotlinCompilationOutput(
target.project,
Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
}
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) =
addSourcesToKotlinCompileTask(
project,
compileKotlinTaskName,
sourceSet.customSourceFilesExtensions,
addAsCommonSources
) { sourceSet.kotlin }
internal fun addExactSourceSetsEagerly(sourceSets: Set<KotlinSourceSet>) {
with(target.project) {
//TODO possibly issue with forced instantiation
sourceSets.forEach { sourceSet ->
addSourcesToCompileTask(
sourceSet,
addAsCommonSources = lazy {
CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project).contains(sourceSet.name)
}
)
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
// old Java & Android projects:
addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
}
if (sourceSet.name != defaultSourceSetName) {
kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
// Temporary solution for checking consistency across source sets participating in a compilation that may
// not be interconnected with the dependsOn relation: check the settings as if the default source set of
// the compilation depends on the one added to the compilation:
defaultSourceSetLanguageSettingsChecker.runAllChecks(
defaultSourceSet,
sourceSet
)
}
}
}
}
}
override fun source(sourceSet: KotlinSourceSet) {
if (kotlinSourceSets.add(sourceSet)) {
target.project.whenEvaluated {
addExactSourceSetsEagerly(sourceSet.withAllDependsOnSourceSets())
}
}
compilationDetails.source(sourceSet)
}
override val compileDependencyConfigurationName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
"compileClasspath"
)
override val compileKotlinTaskName: String
get() = lowerCamelCaseName(
"compile",
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
"Kotlin",
target.targetName
)
override val compileAllTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "classes")
override lateinit var compileDependencyFiles: FileCollection
override val apiConfigurationName: String
get() = disambiguateName(API)
override val implementationConfigurationName: String
get() = disambiguateName(IMPLEMENTATION)
override val compileOnlyConfigurationName: String
get() = disambiguateName(COMPILE_ONLY)
override val runtimeOnlyConfigurationName: String
get() = disambiguateName(RUNTIME_ONLY)
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
DefaultKotlinDependencyHandler(this, target.project).run(configure)
override fun dependencies(configureClosure: Closure<Any?>) =
dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
override fun toString(): String = "compilation '$compilationPurpose' ($target)"
internal val friendArtifactsTask: TaskProvider<AbstractArchiveTask>? by lazy {
if (associateWithTransitiveClosure.any { it.isMain() }) {
val archiveTasks = target.project.tasks.withType(AbstractArchiveTask::class.java)
if (!archiveTasks.isEmpty()) {
try {
archiveTasks.named(target.artifactsTaskName)
} catch (e: UnknownTaskException) {
// Native tasks does not extend AbstractArchiveTask
null
}
} else {
null
}
} else {
null
}
}
/**
* If a compilation is aware of its associate compilations' outputs being added to the classpath in a transformed or packaged way,
* it should point to those friend artifact files via this property.
*/
internal open val friendArtifacts: FileCollection
get() = with(target.project) {
val friendArtifactsTaskProvider = friendArtifactsTask
if (friendArtifactsTaskProvider != null) {
// In case the main artifact is transitively added to the test classpath via a test dependency on another module
// that depends on this module's production part, include the main artifact in the friend artifacts, lazily:
files(
Callable {
friendArtifactsTaskProvider.flatMap { it.archiveFile }
}
)
} else files()
}
override val friendPaths: Iterable<FileCollection>
get() = mutableListOf<FileCollection>().also { allCollections ->
associateWithTransitiveClosure.forEach { allCollections.add(it.output.classesDirs) }
allCollections.add(friendArtifacts)
}
override val moduleName: String
get() = KotlinCompilationsModuleGroups.getModuleLeaderCompilation(this).takeIf { it != this }?.ownModuleName() ?: ownModuleName
override fun associateWith(other: KotlinCompilation<*>) {
require(other.target == target) { "Only associations between compilations of a single target are supported" }
other as AbstractKotlinCompilation<*>
_associateWith += other
addAssociateCompilationDependencies(other)
KotlinCompilationsModuleGroups.unionModules(this, other)
compilationDetails.associateWith((other as AbstractKotlinCompilation<*>).compilationDetails)
}
/**
* Adds `allDependencies` of configurations mentioned in `configurationNames` to configuration named [this] in
* a lazy manner
*/
private fun String.addAllDependenciesFromOtherConfigurations(project: Project, vararg configurationNames: String) {
project.configurations.named(this).configure { receiverConfiguration ->
receiverConfiguration.dependencies.addAllLater(
project.objects.listProperty(Dependency::class.java).apply {
set(
project.provider {
configurationNames
.map { project.configurations.getByName(it) }
.flatMap { it.allDependencies }
}
)
}
)
}
}
@OptIn(ExperimentalStdlibApi::class)
protected open fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
/*
we add dependencies to compileDependencyConfiguration ('compileClasspath' usually) and runtimeDependency
('runtimeClasspath') instead of modifying respective api/implementation/compileOnly/runtimeOnly configs
This is needed because api/implementation/compileOnly/runtimeOnly are used in IDE Import and will leak
to dependencies of IDE modules. But they are not needed here, because IDE resolution works inherently
transitively and symbols from associated compilation will be resolved from source sets of associated
compilation itself (moreover, direct dependencies are not equivalent to transitive ones because of
resolution order - e.g. in case of FQNs clash, so it's even harmful)
*/
project.dependencies.add(compileOnlyConfigurationName, project.files(Callable { other.output.classesDirs }))
project.dependencies.add(runtimeOnlyConfigurationName, project.files(Callable { other.output.allOutputs }))
compileDependencyConfigurationName.addAllDependenciesFromOtherConfigurations(
project,
other.apiConfigurationName,
other.implementationConfigurationName,
other.compileOnlyConfigurationName
)
runtimeDependencyConfigurationName?.addAllDependenciesFromOtherConfigurations(
project,
other.apiConfigurationName,
other.implementationConfigurationName,
other.runtimeOnlyConfigurationName
)
}
private val _associateWith: MutableSet<AbstractKotlinCompilation<*>> = mutableSetOf()
override val associateWith: List<KotlinCompilation<*>>
get() = Collections.unmodifiableList(_associateWith.toList())
get() = Collections.unmodifiableList(compilationDetails.associateCompilations.map { it.compilation })
override val project: Project
get() = target.project
@@ -315,20 +108,12 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val owner: KotlinTarget
get() = target
override val compilationClassifier: String?
get() = target.disambiguationClassifier
override val allKotlinSourceSets: Set<KotlinSourceSet>
get() = compilationDetails.directlyIncludedKotlinSourceSets +
compilationDetails.directlyIncludedKotlinSourceSets.resolveAllDependsOnSourceSets()
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet>
get() = defaultSourceSet.withAllDependsOnSourceSets().associate { it.name to it.kotlin }
override val languageSettings: LanguageSettingsBuilder
get() = defaultSourceSet.languageSettings
override val platformType: KotlinPlatformType
get() = target.platformType
override val ownModuleName: String
get() = ownModuleName()
override val relatedConfigurationNames: List<String>
get() = compilationDetails.kotlinDependenciesHolder.relatedConfigurationNames + compileDependencyConfigurationName
}
internal fun addCommonSourcesToKotlinCompileTask(
@@ -368,14 +153,6 @@ internal fun addSourcesToKotlinCompileTask(
}
}
private fun KotlinCompilation<*>.ownModuleName(): String {
val project = target.project
val baseName = project.extensions.getByType(BasePluginExtension::class.java).archivesName.orNull
?: project.name
val suffix = if (isMain()) "" else "_$compilationName"
return filterModuleName("$baseName$suffix")
}
internal val KotlinCompilation<*>.associateWithTransitiveClosure: Iterable<KotlinCompilation<*>>
get() = mutableSetOf<KotlinCompilation<*>>().apply {
fun visit(other: KotlinCompilation<*>) {
@@ -387,17 +164,19 @@ internal val KotlinCompilation<*>.associateWithTransitiveClosure: Iterable<Kotli
}
abstract class AbstractKotlinCompilationToRunnableFiles<T : KotlinCommonOptions>(
target: KotlinTarget,
name: String
) : AbstractKotlinCompilation<T>(target, name), KotlinCompilationToRunnableFiles<T> {
override val runtimeDependencyConfigurationName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
"runtimeClasspath"
)
override val compilationDetails: CompilationDetailsWithRuntime<T>,
) : AbstractKotlinCompilation<T>(compilationDetails),
KotlinCompilationToRunnableFiles<T> {
override lateinit var runtimeDependencyFiles: FileCollection
final override val runtimeDependencyConfigurationName: String get() = compilationDetails.runtimeDependencyFilesHolder.dependencyConfigurationName
final override var runtimeDependencyFiles: FileCollection
get() = compilationDetails.runtimeDependencyFilesHolder.dependencyFiles
set(value) {
compilationDetails.runtimeDependencyFilesHolder.dependencyFiles = value
}
override val relatedConfigurationNames: List<String>
get() = super<AbstractKotlinCompilation>.relatedConfigurationNames + runtimeDependencyConfigurationName
}
internal fun KotlinCompilation<*>.disambiguateName(simpleName: String): String {
@@ -485,4 +264,4 @@ internal object CompilationSourceSetUtil {
private val invalidModuleNameCharactersRegex = """[\\/\r\n\t]""".toRegex()
internal fun filterModuleName(moduleName: String): String =
moduleName.replace(invalidModuleNameCharactersRegex, "_")
moduleName.replace(invalidModuleNameCharactersRegex, "_")
@@ -11,9 +11,11 @@ import org.gradle.api.Project
import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.provider.Provider
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies
import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinDependencyConfigurationsHolder
import org.jetbrains.kotlin.gradle.plugin.mpp.toModuleDependency
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.FragmentConsistencyChecker
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.pm20
import groovy.lang.Closure
import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.GradleException
import org.gradle.api.Project
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.file.FileCollection
@@ -25,7 +24,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.unambiguousNameInProject
import org.jetbrains.kotlin.gradle.plugin.sources.kpm.FragmentMappedKotlinSourceSet
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTargetConfigurator
import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.project.model.refinesClosure
import java.util.concurrent.Callable
@@ -68,109 +66,16 @@ internal fun KotlinGradleVariant.ownModuleName(): String {
return filterModuleName("$baseName$suffix")
}
open class KotlinVariantMappedJvmCompilation(
override val target: KotlinJvmTarget,
internal val variant: KotlinJvmVariant,
) : KotlinJvmCompilation(target, variant.containingModule.name) {
// TODO: in the legacy model, it used to be a KotlinCompilationWithResources
override val runtimeDependencyConfigurationName: String
get() = variant.runtimeDependenciesConfiguration.name
override var runtimeDependencyFiles: FileCollection
get() = variant.runtimeDependencyFiles
set(value) {
variant.runtimeDependencyFiles = value
}
// TODO: compilation data implements compileDependencyFiles as a val, not var, fix this?
override val compileDependencyConfigurationName: String
get() = variant.compileDependenciesConfiguration.name
override var compileDependencyFiles: FileCollection
get() = compilationData.compileDependencyFiles
set(value) {
variant.compileDependencyFiles = value
}
private val compilationData: KotlinJvmVariantCompilationData
get() = variant.compilationData
override val kotlinOptions: KotlinJvmOptions = compilationData.kotlinOptions
override val compilationName: String
get() = compilationData.compilationPurpose
// FIXME: mutating this set should not be allowed
override val kotlinSourceSets: MutableSet<KotlinSourceSet>
get() = super.kotlinSourceSets
override val allKotlinSourceSets: Set<KotlinSourceSet>
get() {
val allMappedSourceSets = target.project.kotlinExtension.sourceSets
.filterIsInstance<FragmentMappedKotlinSourceSet>()
.associateBy { it.underlyingFragment }
return variant.refinesClosure.mapNotNull { allMappedSourceSets[it] }.toSet()
}
override val defaultSourceSetName: String
get() = variant.unambiguousNameInProject
override fun source(sourceSet: KotlinSourceSet) {
defaultSourceSet.dependsOn(sourceSet)
}
override fun associateWith(other: KotlinCompilation<*>) {
throw UnsupportedOperationException("not supported in the mapped model")
}
override val associateWith: List<KotlinCompilation<*>> get() = emptyList()
override fun getAttributes(): AttributeContainer {
// TODO: not implemented?
return HierarchyAttributeContainer(target.attributes)
}
override fun dependencies(configure: KotlinDependencyHandler.() -> Unit) {
variant.dependencies(configure)
}
override fun dependencies(configureClosure: Closure<Any?>) {
variant.dependencies(configureClosure)
}
override val apiConfigurationName: String
get() = variant.apiConfigurationName
override val implementationConfigurationName: String
get() = variant.implementationConfigurationName
override val compileOnlyConfigurationName: String
get() = variant.compileOnlyConfigurationName
override val runtimeOnlyConfigurationName: String
get() = variant.runtimeOnlyConfigurationName
override val project: Project
get() = variant.project
override val output: KotlinCompilationOutput
get() = variant.compilationOutputs
override val compileKotlinTaskName: String
get() = compilationData.compileKotlinTaskName
override val compileAllTaskName: String
get() = compilationData.compileAllTaskName
override val moduleName: String
get() = compilationData.moduleName
}
class KotlinMappedJvmCompilationFactory(
target: KotlinJvmTarget
) : KotlinJvmCompilationFactory(target) {
override fun create(name: String): KotlinVariantMappedJvmCompilation {
override fun create(name: String): KotlinJvmCompilation {
val module = target.project.kpmModules.maybeCreate(name)
val variant = module.fragments.create(target.name, KotlinJvmVariant::class.java)
return KotlinVariantMappedJvmCompilation(target, variant)
return KotlinJvmCompilation(
VariantMappedCompilationDetailsWithRuntime(variant, target),
)
}
}
@@ -196,7 +101,10 @@ class KotlinMappedJvmTargetConfigurator : KotlinJvmTargetConfigurator() {
override fun createArchiveTasks(target: KotlinJvmTarget): TaskProvider<out Zip> =
checkNotNull(
target.project.locateTask<Jar>(
(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) as KotlinVariantMappedJvmCompilation).variant.outputsJarTaskName
target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
.compilationDetails.let { it as VariantMappedCompilationDetails<*> }
.variant.let { it as KotlinJvmVariant }
.outputsJarTaskName
)
)
}
}
@@ -0,0 +1,44 @@
/*
* 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.util
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleVariant
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinGradleVariantWithRuntime
interface DependencyFilesHolder {
val dependencyConfigurationName: String
var dependencyFiles: FileCollection
companion object
}
internal fun DependencyFilesHolder.Companion.ofVariantCompileDependencies(variant: KotlinGradleVariant): DependencyFilesHolder =
object : DependencyFilesHolder {
override val dependencyConfigurationName: String
get() = variant.compileDependenciesConfiguration.name
override var dependencyFiles: FileCollection
get() = variant.compileDependencyFiles
set(value) { variant.compileDependencyFiles = value }
}
internal fun DependencyFilesHolder.Companion.ofVariantRuntimeDependencies(variant: KotlinGradleVariantWithRuntime): DependencyFilesHolder =
object : DependencyFilesHolder {
override val dependencyConfigurationName: String
get() = variant.runtimeDependenciesConfiguration.name
override var dependencyFiles: FileCollection
get() = variant.runtimeDependencyFiles
set(value) { variant.runtimeDependencyFiles = value }
}
class SimpleDependencyFilesHolder(
override val dependencyConfigurationName: String,
override var dependencyFiles: FileCollection
) : DependencyFilesHolder
internal fun Project.newDependencyFilesHolder(dependencyConfigurationName: String): DependencyFilesHolder =
SimpleDependencyFilesHolder(dependencyConfigurationName, project.files())
@@ -13,24 +13,24 @@ import org.gradle.api.tasks.TaskProvider
import org.gradle.util.ConfigureUtil
import org.gradle.util.WrapUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsSubTargetContainerDsl
import org.jetbrains.kotlin.gradle.targets.js.dukat.ExternalsOutputFormat
import org.jetbrains.kotlin.gradle.targets.js.ir.JsBinary
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsBinaryContainer
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.utils.*
open class KotlinJsCompilation(
target: KotlinTarget,
name: String
) : AbstractKotlinCompilationToRunnableFiles<KotlinJsOptions>(target, name), KotlinCompilationWithResources<KotlinJsOptions> {
open class KotlinJsCompilation internal constructor(
compilationDetails: JsCompilationDetails
) : AbstractKotlinCompilationToRunnableFiles<KotlinJsOptions>(compilationDetails),
KotlinCompilationWithResources<KotlinJsOptions> {
final override val target: KotlinTarget get() = super.target
constructor(target: KotlinTarget, name: String) : this(JsCompilationDetails(target, name))
private val kotlinProperties = PropertiesProvider(target.project)
@@ -39,8 +39,6 @@ open class KotlinJsCompilation(
internal open val defaultExternalsOutputFormat: ExternalsOutputFormat = ExternalsOutputFormat.SOURCE
override val kotlinOptions: KotlinJsOptions = KotlinJsOptionsImpl()
internal val binaries: KotlinJsBinaryContainer =
target.project.objects.newInstance(
KotlinJsBinaryContainer::class.java,
@@ -77,41 +75,7 @@ open class KotlinJsCompilation(
fun packageJson(handler: Closure<*>) {
packageJson {
ConfigureUtil.configure(handler, this)
project.configure(this, handler)
}
}
override val apiConfigurationName: String
get() = disambiguateNameInPlatform(API)
override val implementationConfigurationName: String
get() = disambiguateNameInPlatform(IMPLEMENTATION)
override val compileOnlyConfigurationName: String
get() = disambiguateNameInPlatform(COMPILE_ONLY)
override val runtimeOnlyConfigurationName: String
get() = disambiguateNameInPlatform(RUNTIME_ONLY)
protected open val disambiguationClassifierInPlatform: String?
get() = (target as KotlinJsTarget).disambiguationClassifierInPlatform
private fun disambiguateNameInPlatform(simpleName: String): String {
return lowerCamelCaseName(
disambiguationClassifierInPlatform,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
simpleName
)
}
override val defaultSourceSetName: String
get() {
val target = target as KotlinJsTarget
return lowerCamelCaseName(
target.irTarget?.let {
target.disambiguationClassifierInPlatform
} ?: target.disambiguationClassifier,
compilationPurpose
)
}
}
@@ -6,38 +6,17 @@
package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.file.SourceDirectorySet
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.JsIrCompilationDetails
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.targets.js.dukat.ExternalsOutputFormat
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
class KotlinJsIrCompilation(
target: KotlinTarget,
name: String
) : KotlinJsCompilation(target, name) {
) : KotlinJsCompilation(JsIrCompilationDetails(target, name)) {
override val externalsOutputFormat: ExternalsOutputFormat = ExternalsOutputFormat.SOURCE
internal val allSources: MutableSet<SourceDirectorySet> = mutableSetOf()
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
super.addSourcesToCompileTask(sourceSet, addAsCommonSources)
allSources.add(sourceSet.kotlin)
}
override val disambiguationClassifierInPlatform: String?
get() = (target as KotlinJsIrTarget).disambiguationClassifierInPlatform
override val defaultSourceSetName: String
get() {
val target = target as KotlinJsIrTarget
return lowerCamelCaseName(
if (target.mixedMode)
target.disambiguationClassifierInPlatform
else
target.disambiguationClassifier,
compilationPurpose
)
}
}
@@ -1,4 +1,4 @@
/*
/*
* Copyright 2010-2018 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.
*/
@@ -17,43 +17,24 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.getJavaTaskProvider
import org.jetbrains.kotlin.gradle.plugin.getTestedVariantData
class KotlinJvmAndroidCompilation(
target: KotlinAndroidTarget,
name: String
) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(target, name) {
override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl()
class KotlinJvmAndroidCompilation(
target: KotlinAndroidTarget,
name: String
) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(AndroidCompilationDetails(target, name)) {
lateinit var androidVariant: BaseVariant
internal set
override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@Suppress("UnstableApiUsage")
internal val testedVariantArtifacts: Property<FileCollection> = target.project.objects.property(FileCollection::class.java)
@Suppress("UNCHECKED_CAST")
override val compileKotlinTaskProvider: TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
get() = super.compileKotlinTaskProvider as TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
@Suppress("UNCHECKED_CAST")
override val compileKotlinTaskProvider: TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
get() = super.compileKotlinTaskProvider as TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
@Suppress("UnstableApiUsage")
internal val testedVariantArtifacts: Property<FileCollection> = target.project.objects.property(FileCollection::class.java)
override val friendArtifacts: FileCollection get() = target.project.files(super.friendArtifacts, testedVariantArtifacts)
override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
if ((other as? KotlinJvmAndroidCompilation)?.androidVariant != getTestedVariantData(androidVariant)) {
super.addAssociateCompilationDependencies(other)
} // otherwise, do nothing: the Android Gradle plugin adds these dependencies for us, we don't need to add them to the classpath
}
override val relatedConfigurationNames: List<String>
get() = super.relatedConfigurationNames + listOf(
"${androidVariant.name}ApiElements",
"${androidVariant.name}RuntimeElements",
androidVariant.compileConfiguration.name,
androidVariant.runtimeConfiguration.name
)
val compileJavaTaskProvider: TaskProvider<out JavaCompile>?
get() = androidVariant.getJavaTaskProvider()
}
val compileJavaTaskProvider: TaskProvider<out JavaCompile>?
get() = androidVariant.getJavaTaskProvider()
}
@@ -1,4 +1,4 @@
/*
/*
* Copyright 2010-2018 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.
*/
@@ -12,14 +12,13 @@ import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
open class KotlinJvmCompilation(
override val target: KotlinJvmTarget,
name: String
) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(target, name), KotlinCompilationWithResources<KotlinJvmOptions> {
override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl()
compilationDetails: CompilationDetailsWithRuntime<KotlinJvmOptions>,
) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(compilationDetails), KotlinCompilationWithResources<KotlinJvmOptions> {
override val target: KotlinJvmTarget get() = compilationDetails.target as KotlinJvmTarget
override val processResourcesTaskName: String
get() = disambiguateName("processResources")
@@ -6,6 +6,7 @@
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
open class KotlinJvmCompilationFactory(
@@ -15,5 +16,7 @@ open class KotlinJvmCompilationFactory(
get() = KotlinJvmCompilation::class.java
override fun create(name: String): KotlinJvmCompilation =
KotlinJvmCompilation(target, name)
KotlinJvmCompilation(
DefaultCompilationDetailsWithRuntime(target, name) { KotlinJvmOptionsImpl() }
)
}
@@ -1,4 +1,4 @@
/*
/*
* Copyright 2010-2018 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.
*/
@@ -16,30 +16,17 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationOutput
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
class KotlinWithJavaCompilation<KotlinOptionsType : KotlinCommonOptions>(
class KotlinWithJavaCompilation<KotlinOptionsType : KotlinCommonOptions>(
target: KotlinWithJavaTarget<KotlinOptionsType>,
name: String,
override val kotlinOptions: KotlinOptionsType
) : AbstractKotlinCompilationToRunnableFiles<KotlinOptionsType>(target, name), KotlinCompilationWithResources<KotlinOptionsType> {
kotlinOptions: KotlinOptionsType
) : AbstractKotlinCompilationToRunnableFiles<KotlinOptionsType>(WithJavaCompilationDetails(target, name) { kotlinOptions }),
KotlinCompilationWithResources<KotlinOptionsType> {
lateinit var javaSourceSet: SourceSet
override val output: KotlinCompilationOutput by lazy { KotlinWithJavaCompilationOutput(this) }
override val processResourcesTaskName: String
get() = javaSourceSet.processResourcesTaskName
override var runtimeDependencyFiles: FileCollection
get() = javaSourceSet.runtimeClasspath
set(value) {
javaSourceSet.runtimeClasspath = value
}
override val runtimeDependencyConfigurationName: String
get() = javaSourceSet.runtimeClasspathConfigurationName
override val compileDependencyConfigurationName: String
get() = javaSourceSet.compileClasspathConfigurationName
override val runtimeOnlyConfigurationName: String
get() = javaSourceSet.runtimeOnlyConfigurationName
@@ -55,18 +42,6 @@ import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
override val compileAllTaskName: String
get() = javaSourceSet.classesTaskName
override var compileDependencyFiles: FileCollection
get() = javaSourceSet.compileClasspath
set(value) {
javaSourceSet.compileClasspath = value
}
override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
if (name != SourceSet.TEST_SOURCE_SET_NAME || other.name != SourceSet.MAIN_SOURCE_SET_NAME) {
super.addAssociateCompilationDependencies(other)
} // otherwise, do nothing: the Java Gradle plugin adds these dependencies for us, we don't need to add them to the classpath
}
fun source(javaSourceSet: SourceSet) {
with(target.project) {
afterEvaluate {
@@ -287,6 +287,8 @@ class KotlinMetadataTargetConfigurator :
): AbstractKotlinCompilation<*> {
val project = target.project
check(!project.hasKpmModel) { "KotlinMetadataTargetConfigurator cannot work with KPM!" }
val compilationName = sourceSet.name
val platformCompilations = compilationsBySourceSets(project)
@@ -304,7 +306,9 @@ class KotlinMetadataTargetConfigurator :
return compilationFactory.create(compilationName).apply {
target.compilations.add(this@apply)
addExactSourceSetsEagerly(setOf(sourceSet))
(compilationDetails as DefaultCompilationDetails<*>).addExactSourceSetsEagerly(setOf(sourceSet))
configureMetadataDependenciesForCompilation(this@apply)
if (!isHostSpecific) {
@@ -14,6 +14,7 @@ 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.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData
@@ -54,12 +55,12 @@ internal class NativeCompileOptions(languageSettingsProvider: () -> LanguageSett
}
abstract class AbstractKotlinNativeCompilation(
target: KotlinTarget,
override val konanTarget: KonanTarget,
compilationName: String
) : AbstractKotlinCompilation<KotlinCommonOptions>(target, compilationName), KotlinNativeCompilationData<KotlinCommonOptions> {
override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { defaultSourceSet.languageSettings }
compilationDetails: CompilationDetails<KotlinCommonOptions>
) : AbstractKotlinCompilation<KotlinCommonOptions>(
compilationDetails
),
KotlinNativeCompilationData<KotlinCommonOptions> {
override val compileKotlinTask: KotlinNativeCompile
get() = super.compileKotlinTask as KotlinNativeCompile
@@ -68,10 +69,6 @@ abstract class AbstractKotlinNativeCompilation(
override val compileKotlinTaskProvider: TaskProvider<out KotlinNativeCompile>
get() = super.compileKotlinTaskProvider as TaskProvider<out KotlinNativeCompile>
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources)
}
internal val useGenericPluginArtifact: Boolean
get() = project.nativeUseEmbeddableCompilerJar
@@ -96,12 +93,14 @@ internal fun addSourcesToKotlinNativeCompileTask(
}
class KotlinNativeCompilation(
override val target: KotlinNativeTarget,
konanTarget: KonanTarget,
name: String
) : AbstractKotlinNativeCompilation(target, konanTarget, name),
details: CompilationDetails<KotlinCommonOptions>
) : AbstractKotlinNativeCompilation(konanTarget, details),
KotlinCompilationWithResources<KotlinCommonOptions> {
override val target: KotlinNativeTarget
get() = super.target as KotlinNativeTarget
// Interop DSL.
val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
DefaultCInteropSettings(project, cinteropName, this)
@@ -114,50 +113,24 @@ class KotlinNativeCompilation(
override val processResourcesTaskName: String
get() = disambiguateName("processResources")
override val compileDependencyConfigurationName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
"compileKlibraries"
)
override val compileAllTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "klibrary")
val binariesTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "binaries")
override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) {
compileDependencyFiles += other.output.classesDirs + project.filesProvider { other.compileDependencyFiles }
target.project.configurations.named(implementationConfigurationName).configure { configuration ->
configuration.extendsFrom(target.project.configurations.findByName(other.implementationConfigurationName))
}
}
}
class KotlinSharedNativeCompilation(override val target: KotlinMetadataTarget, val konanTargets: List<KonanTarget>, name: String) :
class KotlinSharedNativeCompilation(
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.
// Rewrite this when we'll compile native-shared source-sets against commonized platform libs
// We find any konan target that is enabled on the current host in order to pass the checks that avoid compiling the code otherwise.
konanTargets.find { it.enabledOnCurrentHost } ?: konanTargets.first(),
name
SharedNativeCompilationDetails(target, name) { NativeCompileOptions { defaultSourceSet.languageSettings } }
),
KotlinMetadataCompilation<KotlinCommonOptions> {
override val friendArtifacts: FileCollection
get() = super.friendArtifacts.plus(run {
val project = target.project
val friendSourceSets = getVisibleSourceSetsFromAssociateCompilations(project, defaultSourceSet).toMutableSet().apply {
// TODO: implement proper dependsOn/refines compiler args for Kotlin/Native and pass the dependsOn klibs separately;
// But for now, those dependencies don't have any special semantics, so passing all them as friends works, too
addAll(defaultSourceSet.resolveAllDependsOnSourceSets())
}
project.files(friendSourceSets.mapNotNull { project.getMetadataCompilationForSourceSet(it)?.output?.classesDirs })
})
override val target: KotlinMetadataTarget get() = super.target as KotlinMetadataTarget
override val isActive: Boolean
get() = true // old plugin only creates necessary compilations
@@ -17,11 +17,15 @@ class KotlinNativeCompilationFactory(
get() = KotlinNativeCompilation::class.java
override fun create(name: String): KotlinNativeCompilation =
// TODO: Validate compilation free args using the [CompilationFreeArgsValidator]
// when the compilation and the link args are separated (see KT-33717).
// Note: such validation should be done in the whenEvaluate block because
// TODO: Validate compilation free args using the [CompilationFreeArgsValidator]
// when the compilation and the link args are separated (see KT-33717).
// Note: such validation should be done in the whenEvaluate block because
// a user can change args during project configuration.
KotlinNativeCompilation(target, target.konanTarget, name)
KotlinNativeCompilation(
target.konanTarget,
NativeCompilationDetails(target, name) { NativeCompileOptions { defaultSourceSet.languageSettings } }
)
}
class KotlinSharedNativeCompilationFactory(
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.MockKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.sources.MockKotlinSourceSet
import org.junit.Before
@@ -28,7 +29,7 @@ class KotlinCompilationsModuleGroupsTest {
assertEquals(a, instance.getModuleLeader(a))
}
private fun assertLeader(leader: KotlinCompilation<*>, vararg ofCompilations: KotlinCompilation<*>) {
private fun assertLeader(leader: KotlinCompilationData<*>, vararg ofCompilations: KotlinCompilationData<*>) {
val leadersForModules = ofCompilations.map { instance.getModuleLeader(it) }
assertEquals(leadersForModules.map { leader }, leadersForModules)
}
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.sources
import groovy.lang.Closure
import org.gradle.api.Project
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet
@@ -13,6 +14,8 @@ import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
import org.jetbrains.kotlin.project.model.LanguageSettings
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertFailsWith
@@ -271,7 +274,7 @@ class MockKotlinSourceSet(private val name: String) : KotlinSourceSet {
class MockKotlinCompilation(
override val compilationName: String,
override val defaultSourceSet: KotlinSourceSet
) : KotlinCompilation<KotlinCommonOptions> {
) : KotlinCompilation<KotlinCommonOptions>, KotlinCompilationData<KotlinCommonOptions> {
override val kotlinSourceSets: Set<KotlinSourceSet> = setOf(defaultSourceSet)
override val allKotlinSourceSets: Set<KotlinSourceSet>
@@ -297,6 +300,8 @@ class MockKotlinCompilation(
override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) = defaultSourceSet.run(configure)
override val compilationPurpose: String get() = compilationName
//region Not implemented
override val target: KotlinTarget get() = throw UnsupportedOperationException()
override val compileKotlinTaskProvider: TaskProvider<out KotlinCompile<KotlinCommonOptions>> get() = throw UnsupportedOperationException()
@@ -322,7 +327,15 @@ class MockKotlinCompilation(
override fun attributes(configure: Closure<*>) = throw UnsupportedOperationException()
override val compileAllTaskName: String get() = throw UnsupportedOperationException()
override val moduleName: String get() = throw UnsupportedOperationException()
override fun toString(): String = "compilation '${name}'"
override val project: Project get() = throw UnsupportedOperationException()
override val owner: Any get() = throw UnsupportedOperationException()
override val compilationClassifier: String get() = throw UnsupportedOperationException()
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet> get() = throw UnsupportedOperationException()
override val languageSettings: LanguageSettings get() = throw UnsupportedOperationException()
override val platformType: KotlinPlatformType get() = throw UnsupportedOperationException()
override val ownModuleName: String get() = throw UnsupportedOperationException()
override val friendPaths: Iterable<FileCollection> get() = throw UnsupportedOperationException()
//endregion
override fun toString(): String = "compilation '${name}'"
}