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 fun getName(): String = compilationName
override val relatedConfigurationNames: List<String>
get() = super.relatedConfigurationNames + compileDependencyConfigurationName
val moduleName: String val moduleName: String
val disambiguatedName val disambiguatedName
@@ -100,4 +97,4 @@ val <T : KotlinCommonOptions> KotlinCompilation<T>.runtimeDependencyConfiguratio
interface KotlinCompilationWithResources<T : KotlinCommonOptions> : KotlinCompilation<T> { interface KotlinCompilationWithResources<T : KotlinCommonOptions> : KotlinCompilation<T> {
val processResourcesTaskName: String 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( class KotlinCommonCompilation(
target: KotlinTarget, target: KotlinTarget,
name: String name: String
) : AbstractKotlinCompilation<KotlinMultiplatformCommonOptions>(target, name), KotlinMetadataCompilation<KotlinMultiplatformCommonOptions> { ) : AbstractKotlinCompilation<KotlinMultiplatformCommonOptions>(
MetadataCompilationDetails(target, name)
override val kotlinOptions: KotlinMultiplatformCommonOptions = KotlinMultiplatformCommonOptionsImpl() ), KotlinMetadataCompilation<KotlinMultiplatformCommonOptions> {
override val compileKotlinTask: KotlinCompileCommon override val compileKotlinTask: KotlinCompileCommon
get() = super.compileKotlinTask as KotlinCompileCommon get() = super.compileKotlinTask as KotlinCompileCommon
@@ -32,11 +32,4 @@ class KotlinCommonCompilation(
get() = target.project.isKotlinGranularMetadataEnabled && !forceCompilationToKotlinMetadata get() = target.project.isKotlinGranularMetadataEnabled && !forceCompilationToKotlinMetadata
internal var forceCompilationToKotlinMetadata: Boolean = false 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.gradle.api.plugins.ExtraPropertiesExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain 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 /** 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 * 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. * TODO: once the compiler is able to correctly generate calls to internals in other modules, remove this logic.
*/ */
internal class KotlinCompilationsModuleGroups { internal class KotlinCompilationsModuleGroups {
private val moduleLeaderCompilationMap: MutableMap<KotlinCompilation<*>, KotlinCompilation<*>> = private val moduleLeaderCompilationMap: MutableMap<KotlinCompilationData<*>, KotlinCompilationData<*>> =
mutableMapOf() mutableMapOf()
fun getModuleLeader(compilation: KotlinCompilation<*>): KotlinCompilation<*> { fun getModuleLeader(compilation: KotlinCompilationData<*>): KotlinCompilationData<*> {
if (compilation !in moduleLeaderCompilationMap) { if (compilation !in moduleLeaderCompilationMap) {
moduleLeaderCompilationMap[compilation] = compilation 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 aLeader = getModuleLeader(compilationA)
val bLeader = getModuleLeader(compilationB) val bLeader = getModuleLeader(compilationB)
@@ -41,10 +43,10 @@ internal class KotlinCompilationsModuleGroups {
listOf(aLeader, bLeader).run { listOf(aLeader, bLeader).run {
/** heuristically choose the new leader: choose `main` when possible, don't choose `*test*` when there's an alternative, /** 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 */ * if that didn't work, choose the first name lexicographically */
val newLeader = singleOrNull { it.isMain() } val newLeader = singleOrNull { it.isMainCompilationData() }
?: singleOrNull { it.name.contains("main", true) } ?: singleOrNull { it.compilationPurpose.contains("main", true) }
?: singleOrNull { !it.name.contains("test", true) } ?: singleOrNull { !it.compilationPurpose.contains("test", true) }
?: minByOrNull { it.name }!! ?: minByOrNull { it.compilationPurpose }!!
forEach { moduleLeaderCompilationMap[it] = newLeader } forEach { moduleLeaderCompilationMap[it] = newLeader }
} }
@@ -53,11 +55,11 @@ internal class KotlinCompilationsModuleGroups {
companion object { companion object {
private const val EXT_NAME = "kotlin.compilations.moduleGroups" private const val EXT_NAME = "kotlin.compilations.moduleGroups"
fun getModuleLeaderCompilation(compilation: KotlinCompilation<*>): KotlinCompilation<*> = fun getModuleLeaderCompilation(compilation: KotlinCompilationData<*>): KotlinCompilationData<*> =
getInstance(compilation.target.project).getModuleLeader(compilation) getInstance(compilation.project).getModuleLeader(compilation)
fun unionModules(compilationA: KotlinCompilation<*>, compilationB: KotlinCompilation<*>) { fun unionModules(compilationA: KotlinCompilationData<*>, compilationB: KotlinCompilationData<*>) {
getInstance(compilationA.target.project).unionModules(compilationA, compilationB) getInstance(compilationA.project).unionModules(compilationA, compilationB)
} }
private fun getInstance(project: Project): KotlinCompilationsModuleGroups { private fun getInstance(project: Project): KotlinCompilationsModuleGroups {
@@ -9,25 +9,16 @@ import groovy.lang.Closure
import org.gradle.api.GradleException import org.gradle.api.GradleException
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task 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.attributes.AttributeContainer
import org.gradle.api.execution.TaskExecutionListener import org.gradle.api.execution.TaskExecutionListener
import org.gradle.api.file.FileCollection 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.plugins.ExtraPropertiesExtension
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.TaskState 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.dsl.*
import org.jetbrains.kotlin.gradle.plugin.* 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.KotlinCompilationData
import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
import org.jetbrains.kotlin.gradle.plugin.sources.withAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.locateTask 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 internal val KotlinCompilation<*>.kotlinSourceSetsIncludingDefault: Set<KotlinSourceSet> get() = kotlinSourceSets + defaultSourceSet
abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>( abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
target: KotlinTarget, internal open val compilationDetails: CompilationDetails<T>
override val compilationPurpose: String ) : KotlinCompilation<T>,
) : KotlinCompilation<T>, HasKotlinDependencies, KotlinCompilationData<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 override val target: KotlinTarget get() = compilationDetails.target
get() = compilationPurpose
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) = override fun kotlinOptions(configure: T.() -> Unit) =
configure(kotlinOptions) configure(kotlinOptions)
@@ -72,242 +80,27 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val compileKotlinTaskProvider: TaskProvider<out KotlinCompile<T>> override val compileKotlinTaskProvider: TaskProvider<out KotlinCompile<T>>
get() = target.project.locateTask(compileKotlinTaskName) ?: throw GradleException("Couldn't locate task $compileKotlinTaskName") get() = target.project.locateTask(compileKotlinTaskName) ?: throw GradleException("Couldn't locate task $compileKotlinTaskName")
// Don't declare this property in the constructor to avoid NPE private val attributeContainer by lazy { HierarchyAttributeContainer(target.attributes) }
// when an overriding property of a subclass is accessed instead.
@Suppress("CanBePrimaryConstructorProperty")
override val target: KotlinTarget = target
private val attributeContainer = HierarchyAttributeContainer(target.attributes)
override fun getAttributes(): AttributeContainer = attributeContainer 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 override val defaultSourceSet: KotlinSourceSet
get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName) get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName)
override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) = defaultSourceSet.configure() 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) { override fun source(sourceSet: KotlinSourceSet) {
if (kotlinSourceSets.add(sourceSet)) { compilationDetails.source(sourceSet)
target.project.whenEvaluated {
addExactSourceSetsEagerly(sourceSet.withAllDependsOnSourceSets())
}
}
} }
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)" 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<*>) { override fun associateWith(other: KotlinCompilation<*>) {
require(other.target == target) { "Only associations between compilations of a single target are supported" } compilationDetails.associateWith((other as AbstractKotlinCompilation<*>).compilationDetails)
other as AbstractKotlinCompilation<*>
_associateWith += other
addAssociateCompilationDependencies(other)
KotlinCompilationsModuleGroups.unionModules(this, other)
} }
/**
* 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<*>> override val associateWith: List<KotlinCompilation<*>>
get() = Collections.unmodifiableList(_associateWith.toList()) get() = Collections.unmodifiableList(compilationDetails.associateCompilations.map { it.compilation })
override val project: Project override val project: Project
get() = target.project get() = target.project
@@ -315,20 +108,12 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
override val owner: KotlinTarget override val owner: KotlinTarget
get() = target get() = target
override val compilationClassifier: String? override val allKotlinSourceSets: Set<KotlinSourceSet>
get() = target.disambiguationClassifier get() = compilationDetails.directlyIncludedKotlinSourceSets +
compilationDetails.directlyIncludedKotlinSourceSets.resolveAllDependsOnSourceSets()
override val kotlinSourceDirectoriesByFragmentName: Map<String, SourceDirectorySet> override val relatedConfigurationNames: List<String>
get() = defaultSourceSet.withAllDependsOnSourceSets().associate { it.name to it.kotlin } get() = compilationDetails.kotlinDependenciesHolder.relatedConfigurationNames + compileDependencyConfigurationName
override val languageSettings: LanguageSettingsBuilder
get() = defaultSourceSet.languageSettings
override val platformType: KotlinPlatformType
get() = target.platformType
override val ownModuleName: String
get() = ownModuleName()
} }
internal fun addCommonSourcesToKotlinCompileTask( 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<*>> internal val KotlinCompilation<*>.associateWithTransitiveClosure: Iterable<KotlinCompilation<*>>
get() = mutableSetOf<KotlinCompilation<*>>().apply { get() = mutableSetOf<KotlinCompilation<*>>().apply {
fun visit(other: KotlinCompilation<*>) { fun visit(other: KotlinCompilation<*>) {
@@ -387,17 +164,19 @@ internal val KotlinCompilation<*>.associateWithTransitiveClosure: Iterable<Kotli
} }
abstract class AbstractKotlinCompilationToRunnableFiles<T : KotlinCommonOptions>( abstract class AbstractKotlinCompilationToRunnableFiles<T : KotlinCommonOptions>(
target: KotlinTarget, override val compilationDetails: CompilationDetailsWithRuntime<T>,
name: String ) : AbstractKotlinCompilation<T>(compilationDetails),
) : AbstractKotlinCompilation<T>(target, name), KotlinCompilationToRunnableFiles<T> { KotlinCompilationToRunnableFiles<T> {
override val runtimeDependencyConfigurationName: String
get() = lowerCamelCaseName(
target.disambiguationClassifier,
compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
"runtimeClasspath"
)
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 { internal fun KotlinCompilation<*>.disambiguateName(simpleName: String): String {
@@ -485,4 +264,4 @@ internal object CompilationSourceSetUtil {
private val invalidModuleNameCharactersRegex = """[\\/\r\n\t]""".toRegex() private val invalidModuleNameCharactersRegex = """[\\/\r\n\t]""".toRegex()
internal fun filterModuleName(moduleName: String): String = 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.file.SourceDirectorySet
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.util.ConfigureUtil 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.KotlinDependencyHandler
import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultKotlinDependencyHandler 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.mpp.toModuleDependency
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.FragmentConsistencyChecker 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 groovy.lang.Closure
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.plugins.BasePluginConvention import org.gradle.api.plugins.BasePluginConvention
import org.gradle.api.GradleException
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.file.FileCollection 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.plugin.sources.kpm.FragmentMappedKotlinSourceSet
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTargetConfigurator 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.gradle.tasks.locateTask
import org.jetbrains.kotlin.project.model.refinesClosure import org.jetbrains.kotlin.project.model.refinesClosure
import java.util.concurrent.Callable import java.util.concurrent.Callable
@@ -68,109 +66,16 @@ internal fun KotlinGradleVariant.ownModuleName(): String {
return filterModuleName("$baseName$suffix") 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( class KotlinMappedJvmCompilationFactory(
target: KotlinJvmTarget target: KotlinJvmTarget
) : KotlinJvmCompilationFactory(target) { ) : KotlinJvmCompilationFactory(target) {
override fun create(name: String): KotlinVariantMappedJvmCompilation { override fun create(name: String): KotlinJvmCompilation {
val module = target.project.kpmModules.maybeCreate(name) val module = target.project.kpmModules.maybeCreate(name)
val variant = module.fragments.create(target.name, KotlinJvmVariant::class.java) 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> = override fun createArchiveTasks(target: KotlinJvmTarget): TaskProvider<out Zip> =
checkNotNull( checkNotNull(
target.project.locateTask<Jar>( 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.ConfigureUtil
import org.gradle.util.WrapUtil import org.gradle.util.WrapUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions 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.KotlinCompilationWithResources
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider 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.dsl.KotlinJsSubTargetContainerDsl
import org.jetbrains.kotlin.gradle.targets.js.dukat.ExternalsOutputFormat 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.JsBinary
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsBinaryContainer import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsBinaryContainer
import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson import org.jetbrains.kotlin.gradle.targets.js.npm.PackageJson
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
import org.jetbrains.kotlin.gradle.utils.*
open class KotlinJsCompilation( open class KotlinJsCompilation internal constructor(
target: KotlinTarget, compilationDetails: JsCompilationDetails
name: String ) : AbstractKotlinCompilationToRunnableFiles<KotlinJsOptions>(compilationDetails),
) : AbstractKotlinCompilationToRunnableFiles<KotlinJsOptions>(target, name), KotlinCompilationWithResources<KotlinJsOptions> { 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) private val kotlinProperties = PropertiesProvider(target.project)
@@ -39,8 +39,6 @@ open class KotlinJsCompilation(
internal open val defaultExternalsOutputFormat: ExternalsOutputFormat = ExternalsOutputFormat.SOURCE internal open val defaultExternalsOutputFormat: ExternalsOutputFormat = ExternalsOutputFormat.SOURCE
override val kotlinOptions: KotlinJsOptions = KotlinJsOptionsImpl()
internal val binaries: KotlinJsBinaryContainer = internal val binaries: KotlinJsBinaryContainer =
target.project.objects.newInstance( target.project.objects.newInstance(
KotlinJsBinaryContainer::class.java, KotlinJsBinaryContainer::class.java,
@@ -77,41 +75,7 @@ open class KotlinJsCompilation(
fun packageJson(handler: Closure<*>) { fun packageJson(handler: Closure<*>) {
packageJson { 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 package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.file.SourceDirectorySet 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.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.JsIrCompilationDetails
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation
import org.jetbrains.kotlin.gradle.targets.js.dukat.ExternalsOutputFormat import org.jetbrains.kotlin.gradle.targets.js.dukat.ExternalsOutputFormat
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
class KotlinJsIrCompilation( class KotlinJsIrCompilation(
target: KotlinTarget, target: KotlinTarget,
name: String name: String
) : KotlinJsCompilation(target, name) { ) : KotlinJsCompilation(JsIrCompilationDetails(target, name)) {
override val externalsOutputFormat: ExternalsOutputFormat = ExternalsOutputFormat.SOURCE override val externalsOutputFormat: ExternalsOutputFormat = ExternalsOutputFormat.SOURCE
internal val allSources: MutableSet<SourceDirectorySet> = mutableSetOf() 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. * 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. * 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.getJavaTaskProvider
import org.jetbrains.kotlin.gradle.plugin.getTestedVariantData import org.jetbrains.kotlin.gradle.plugin.getTestedVariantData
class KotlinJvmAndroidCompilation( class KotlinJvmAndroidCompilation(
target: KotlinAndroidTarget, target: KotlinAndroidTarget,
name: String name: String
) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(target, name) { ) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(AndroidCompilationDetails(target, name)) {
override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl()
lateinit var androidVariant: BaseVariant lateinit var androidVariant: BaseVariant
internal set internal set
override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile @Suppress("UnstableApiUsage")
get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile internal val testedVariantArtifacts: Property<FileCollection> = target.project.objects.property(FileCollection::class.java)
@Suppress("UNCHECKED_CAST") override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
override val compileKotlinTaskProvider: TaskProvider<out org.jetbrains.kotlin.gradle.tasks.KotlinCompile> get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
get() = super.compileKotlinTaskProvider as TaskProvider<out 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") val compileJavaTaskProvider: TaskProvider<out JavaCompile>?
internal val testedVariantArtifacts: Property<FileCollection> = target.project.objects.property(FileCollection::class.java) get() = androidVariant.getJavaTaskProvider()
}
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()
}
@@ -1,4 +1,4 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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. * 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.KotlinJvmOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
open class KotlinJvmCompilation( open class KotlinJvmCompilation(
override val target: KotlinJvmTarget, compilationDetails: CompilationDetailsWithRuntime<KotlinJvmOptions>,
name: String ) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(compilationDetails), KotlinCompilationWithResources<KotlinJvmOptions> {
) : AbstractKotlinCompilationToRunnableFiles<KotlinJvmOptions>(target, name), KotlinCompilationWithResources<KotlinJvmOptions> { override val target: KotlinJvmTarget get() = compilationDetails.target as KotlinJvmTarget
override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl()
override val processResourcesTaskName: String override val processResourcesTaskName: String
get() = disambiguateName("processResources") get() = disambiguateName("processResources")
@@ -6,6 +6,7 @@
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility @file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
package org.jetbrains.kotlin.gradle.plugin.mpp package org.jetbrains.kotlin.gradle.plugin.mpp
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
open class KotlinJvmCompilationFactory( open class KotlinJvmCompilationFactory(
@@ -15,5 +16,7 @@ open class KotlinJvmCompilationFactory(
get() = KotlinJvmCompilation::class.java get() = KotlinJvmCompilation::class.java
override fun create(name: String): KotlinJvmCompilation = 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. * 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. * 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.plugin.KotlinCompilationWithResources
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
class KotlinWithJavaCompilation<KotlinOptionsType : KotlinCommonOptions>( class KotlinWithJavaCompilation<KotlinOptionsType : KotlinCommonOptions>(
target: KotlinWithJavaTarget<KotlinOptionsType>, target: KotlinWithJavaTarget<KotlinOptionsType>,
name: String, name: String,
override val kotlinOptions: KotlinOptionsType kotlinOptions: KotlinOptionsType
) : AbstractKotlinCompilationToRunnableFiles<KotlinOptionsType>(target, name), KotlinCompilationWithResources<KotlinOptionsType> { ) : AbstractKotlinCompilationToRunnableFiles<KotlinOptionsType>(WithJavaCompilationDetails(target, name) { kotlinOptions }),
KotlinCompilationWithResources<KotlinOptionsType> {
lateinit var javaSourceSet: SourceSet lateinit var javaSourceSet: SourceSet
override val output: KotlinCompilationOutput by lazy { KotlinWithJavaCompilationOutput(this) }
override val processResourcesTaskName: String override val processResourcesTaskName: String
get() = javaSourceSet.processResourcesTaskName 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 override val runtimeOnlyConfigurationName: String
get() = javaSourceSet.runtimeOnlyConfigurationName get() = javaSourceSet.runtimeOnlyConfigurationName
@@ -55,18 +42,6 @@ import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
override val compileAllTaskName: String override val compileAllTaskName: String
get() = javaSourceSet.classesTaskName 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) { fun source(javaSourceSet: SourceSet) {
with(target.project) { with(target.project) {
afterEvaluate { afterEvaluate {
@@ -287,6 +287,8 @@ class KotlinMetadataTargetConfigurator :
): AbstractKotlinCompilation<*> { ): AbstractKotlinCompilation<*> {
val project = target.project val project = target.project
check(!project.hasKpmModel) { "KotlinMetadataTargetConfigurator cannot work with KPM!" }
val compilationName = sourceSet.name val compilationName = sourceSet.name
val platformCompilations = compilationsBySourceSets(project) val platformCompilations = compilationsBySourceSets(project)
@@ -304,7 +306,9 @@ class KotlinMetadataTargetConfigurator :
return compilationFactory.create(compilationName).apply { return compilationFactory.create(compilationName).apply {
target.compilations.add(this@apply) target.compilations.add(this@apply)
addExactSourceSetsEagerly(setOf(sourceSet))
(compilationDetails as DefaultCompilationDetails<*>).addExactSourceSetsEagerly(setOf(sourceSet))
configureMetadataDependenciesForCompilation(this@apply) configureMetadataDependenciesForCompilation(this@apply)
if (!isHostSpecific) { if (!isHostSpecific) {
@@ -14,6 +14,7 @@ import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.util.ConfigureUtil import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData
@@ -54,12 +55,12 @@ internal class NativeCompileOptions(languageSettingsProvider: () -> LanguageSett
} }
abstract class AbstractKotlinNativeCompilation( abstract class AbstractKotlinNativeCompilation(
target: KotlinTarget,
override val konanTarget: KonanTarget, override val konanTarget: KonanTarget,
compilationName: String compilationDetails: CompilationDetails<KotlinCommonOptions>
) : AbstractKotlinCompilation<KotlinCommonOptions>(target, compilationName), KotlinNativeCompilationData<KotlinCommonOptions> { ) : AbstractKotlinCompilation<KotlinCommonOptions>(
compilationDetails
override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { defaultSourceSet.languageSettings } ),
KotlinNativeCompilationData<KotlinCommonOptions> {
override val compileKotlinTask: KotlinNativeCompile override val compileKotlinTask: KotlinNativeCompile
get() = super.compileKotlinTask as KotlinNativeCompile get() = super.compileKotlinTask as KotlinNativeCompile
@@ -68,10 +69,6 @@ abstract class AbstractKotlinNativeCompilation(
override val compileKotlinTaskProvider: TaskProvider<out KotlinNativeCompile> override val compileKotlinTaskProvider: TaskProvider<out KotlinNativeCompile>
get() = super.compileKotlinTaskProvider as TaskProvider<out KotlinNativeCompile> get() = super.compileKotlinTaskProvider as TaskProvider<out KotlinNativeCompile>
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy<Boolean>) {
addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources)
}
internal val useGenericPluginArtifact: Boolean internal val useGenericPluginArtifact: Boolean
get() = project.nativeUseEmbeddableCompilerJar get() = project.nativeUseEmbeddableCompilerJar
@@ -96,12 +93,14 @@ internal fun addSourcesToKotlinNativeCompileTask(
} }
class KotlinNativeCompilation( class KotlinNativeCompilation(
override val target: KotlinNativeTarget,
konanTarget: KonanTarget, konanTarget: KonanTarget,
name: String details: CompilationDetails<KotlinCommonOptions>
) : AbstractKotlinNativeCompilation(target, konanTarget, name), ) : AbstractKotlinNativeCompilation(konanTarget, details),
KotlinCompilationWithResources<KotlinCommonOptions> { KotlinCompilationWithResources<KotlinCommonOptions> {
override val target: KotlinNativeTarget
get() = super.target as KotlinNativeTarget
// Interop DSL. // Interop DSL.
val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName -> val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
DefaultCInteropSettings(project, cinteropName, this) DefaultCInteropSettings(project, cinteropName, this)
@@ -114,50 +113,24 @@ class KotlinNativeCompilation(
override val processResourcesTaskName: String override val processResourcesTaskName: String
get() = disambiguateName("processResources") 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 val binariesTaskName: String
get() = lowerCamelCaseName(target.disambiguationClassifier, compilationPurpose, "binaries") 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, KotlinNativeFragmentMetadataCompilationData,
AbstractKotlinNativeCompilation( AbstractKotlinNativeCompilation(
target,
// TODO: this will end up as '-target' argument passed to K2Native, which is wrong. // TODO: this will end up as '-target' argument passed to K2Native, which is wrong.
// Rewrite this when we'll compile native-shared source-sets against commonized platform libs // 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. // 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(), konanTargets.find { it.enabledOnCurrentHost } ?: konanTargets.first(),
name SharedNativeCompilationDetails(target, name) { NativeCompileOptions { defaultSourceSet.languageSettings } }
), ),
KotlinMetadataCompilation<KotlinCommonOptions> { KotlinMetadataCompilation<KotlinCommonOptions> {
override val friendArtifacts: FileCollection override val target: KotlinMetadataTarget get() = super.target as KotlinMetadataTarget
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 isActive: Boolean override val isActive: Boolean
get() = true // old plugin only creates necessary compilations get() = true // old plugin only creates necessary compilations
@@ -17,11 +17,15 @@ class KotlinNativeCompilationFactory(
get() = KotlinNativeCompilation::class.java get() = KotlinNativeCompilation::class.java
override fun create(name: String): KotlinNativeCompilation = override fun create(name: String): KotlinNativeCompilation =
// TODO: Validate compilation free args using the [CompilationFreeArgsValidator] // TODO: Validate compilation free args using the [CompilationFreeArgsValidator]
// when the compilation and the link args are separated (see KT-33717). // when the compilation and the link args are separated (see KT-33717).
// Note: such validation should be done in the whenEvaluate block because // Note: such validation should be done in the whenEvaluate block because
// a user can change args during project configuration. // a user can change args during project configuration.
KotlinNativeCompilation(target, target.konanTarget, name)
KotlinNativeCompilation(
target.konanTarget,
NativeCompilationDetails(target, name) { NativeCompileOptions { defaultSourceSet.languageSettings } }
)
} }
class KotlinSharedNativeCompilationFactory( class KotlinSharedNativeCompilationFactory(
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.mpp.internal package org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation 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.MockKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.sources.MockKotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.sources.MockKotlinSourceSet
import org.junit.Before import org.junit.Before
@@ -28,7 +29,7 @@ class KotlinCompilationsModuleGroupsTest {
assertEquals(a, instance.getModuleLeader(a)) 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) } val leadersForModules = ofCompilations.map { instance.getModuleLeader(it) }
assertEquals(leadersForModules.map { leader }, leadersForModules) assertEquals(leadersForModules.map { leader }, leadersForModules)
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.plugin.sources package org.jetbrains.kotlin.gradle.plugin.sources
import groovy.lang.Closure import groovy.lang.Closure
import org.gradle.api.Project
import org.gradle.api.attributes.AttributeContainer import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet 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.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.gradle.plugin.* 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.Test
import kotlin.test.assertEquals import kotlin.test.assertEquals
import kotlin.test.assertFailsWith import kotlin.test.assertFailsWith
@@ -271,7 +274,7 @@ class MockKotlinSourceSet(private val name: String) : KotlinSourceSet {
class MockKotlinCompilation( class MockKotlinCompilation(
override val compilationName: String, override val compilationName: String,
override val defaultSourceSet: KotlinSourceSet override val defaultSourceSet: KotlinSourceSet
) : KotlinCompilation<KotlinCommonOptions> { ) : KotlinCompilation<KotlinCommonOptions>, KotlinCompilationData<KotlinCommonOptions> {
override val kotlinSourceSets: Set<KotlinSourceSet> = setOf(defaultSourceSet) override val kotlinSourceSets: Set<KotlinSourceSet> = setOf(defaultSourceSet)
override val allKotlinSourceSets: Set<KotlinSourceSet> override val allKotlinSourceSets: Set<KotlinSourceSet>
@@ -297,6 +300,8 @@ class MockKotlinCompilation(
override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) = defaultSourceSet.run(configure) override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) = defaultSourceSet.run(configure)
override val compilationPurpose: String get() = compilationName
//region Not implemented //region Not implemented
override val target: KotlinTarget get() = throw UnsupportedOperationException() override val target: KotlinTarget get() = throw UnsupportedOperationException()
override val compileKotlinTaskProvider: TaskProvider<out KotlinCompile<KotlinCommonOptions>> 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 fun attributes(configure: Closure<*>) = throw UnsupportedOperationException()
override val compileAllTaskName: String get() = throw UnsupportedOperationException() override val compileAllTaskName: String get() = throw UnsupportedOperationException()
override val moduleName: 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 //endregion
override fun toString(): String = "compilation '${name}'"
} }