From 3f49217cc9cb18ffe5c9730d5c9f52ee14f9064a Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Tue, 1 Feb 2022 17:48:53 +0400 Subject: [PATCH] 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" --- .../kotlin/gradle/plugin/KotlinCompilation.kt | 5 +- .../gradle/plugin/mpp/CompilationDetails.kt | 636 ++++++++++++++++++ .../plugin/mpp/KotlinCommonCompilation.kt | 13 +- .../KotlinCompilationsModuleGroups.kt | 24 +- .../gradle/plugin/mpp/kotlinCompilations.kt | 311 ++------- .../plugin/mpp/pm20/KotlinGradleFragment.kt | 2 + .../plugin/mpp/pm20/KotlinJvmVariant.kt | 112 +-- .../mpp/pm20/util/DependencyFilesHolder.kt | 44 ++ .../gradle/targets/js/KotlinJsCompilation.kt | 54 +- .../targets/js/ir/KotlinJsIrCompilation.kt | 25 +- .../jvm/KotlinJvmAndroidCompilation.kt | 49 +- .../targets/jvm/KotlinJvmCompilation.kt | 11 +- .../jvm/KotlinJvmCompilationFactory.kt | 5 +- .../targets/jvm/KotlinWithJavaCompilation.kt | 35 +- .../KotlinMetadataTargetConfigurator.kt | 6 +- .../targets/native/KotlinNativeCompilation.kt | 59 +- .../native/KotlinNativeCompilationFactory.kt | 12 +- .../KotlinCompilationsModuleGroupsTest.kt | 3 +- .../SourceSetVisibilityInferenceTest.kt | 17 +- 19 files changed, 840 insertions(+), 583 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/util/DependencyFilesHolder.kt diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt index 14c6545ab8a..61ec4933d19 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt @@ -77,9 +77,6 @@ interface KotlinCompilation : Named, HasAttributes, override fun getName(): String = compilationName - override val relatedConfigurationNames: List - get() = super.relatedConfigurationNames + compileDependencyConfigurationName - val moduleName: String val disambiguatedName @@ -100,4 +97,4 @@ val KotlinCompilation.runtimeDependencyConfiguratio interface KotlinCompilationWithResources : KotlinCompilation { val processResourcesTaskName: String -} +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompilationDetails.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompilationDetails.kt index e69de29bb2d..5b91118c42f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompilationDetails.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/CompilationDetails.kt @@ -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 { + val target: KotlinTarget + + val compileDependencyFilesHolder: DependencyFilesHolder + + val kotlinDependenciesHolder: HasKotlinDependencies + + val compilationData: KotlinCompilationData + + fun associateWith(other: CompilationDetails<*>) + val associateCompilations: Set> + + fun source(sourceSet: KotlinSourceSet) + + val directlyIncludedKotlinSourceSets: MutableSet + val defaultSourceSetName: String + + @Suppress("UNCHECKED_CAST") + val compilation: KotlinCompilation + get() = target.compilations.getByName(compilationData.compilationPurpose) as KotlinCompilation + + val defaultSourceSet: KotlinSourceSet + get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName) +} + +interface CompilationDetailsWithRuntime : CompilationDetails { + val runtimeDependencyFilesHolder: DependencyFilesHolder +} + +internal val CompilationDetails<*>.associateWithTransitiveClosure: Iterable> + get() = mutableSetOf>().apply { + fun visit(other: CompilationDetails<*>) { + if (add(other)) { + other.associateCompilations.forEach(::visit) + } + } + associateCompilations.forEach(::visit) + } + +open class DefaultCompilationDetails( + final override val target: KotlinTarget, + final override val compilationPurpose: String, + createKotlinOptions: DefaultCompilationDetails<*>.() -> T +) : CompilationDetails, KotlinCompilationData { + + 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 + 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 = 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 + 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 + get() = mutableListOf().also { allCollections -> + associateWithTransitiveClosure.forEach { allCollections.add(it.compilationData.output.classesDirs) } + allCollections.add(friendArtifacts) + } + + private val friendArtifactsTask: TaskProvider? 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> + get() = Collections.unmodifiableSet(_associateCompilations) + + private val _associateCompilations = mutableSetOf>() + + 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) = + addSourcesToKotlinCompileTask( + project, + compileKotlinTaskName, + sourceSet.customSourceFilesExtensions, + addAsCommonSources + ) { sourceSet.kotlin } + + internal fun addExactSourceSetsEagerly(sourceSets: Set) { + 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( + target: KotlinTarget, + compilationPurpose: String, + createKotlinOptions: DefaultCompilationDetails<*>.() -> T +) : DefaultCompilationDetails(target, compilationPurpose, createKotlinOptions), CompilationDetailsWithRuntime { + 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( + 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) { + addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources) + } +} + +internal open class SharedNativeCompilationDetails( + target: KotlinTarget, + compilationPurpose: String, + createKotlinOptions: DefaultCompilationDetails<*>.() -> KotlinCommonOptions +) : + DefaultCompilationDetails( + 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) { + addSourcesToKotlinNativeCompileTask(project, compileKotlinTaskName, { sourceSet.kotlin }, addAsCommonSources) + } +} + +internal open class VariantMappedCompilationDetails( + open val variant: KotlinGradleVariantInternal, + override val target: KotlinTarget +) : CompilationDetails { + + @Suppress("UNCHECKED_CAST") + override val compilationData: KotlinCompilationData + get() = variant.compilationData as KotlinCompilationData + + 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> get() = emptySet() + + override val compileDependencyFilesHolder: DependencyFilesHolder + get() = DependencyFilesHolder.ofVariantCompileDependencies(variant) + + override val kotlinDependenciesHolder: HasKotlinDependencies + get() = variant + + override val directlyIncludedKotlinSourceSets: MutableSet + // FIXME: this effectively ignores the mutation of the set! + get() = compilation.defaultSourceSet.dependsOn.toMutableSet() +} + +internal open class VariantMappedCompilationDetailsWithRuntime( + override val variant: KotlinGradleVariantWithRuntimeInternal, + target: KotlinTarget +) : VariantMappedCompilationDetails(variant, target), + CompilationDetailsWithRuntime { + override val runtimeDependencyFilesHolder: DependencyFilesHolder + get() = DependencyFilesHolder.ofVariantRuntimeDependencies(variant) +} + +internal class WithJavaCompilationDetails( + target: KotlinTarget, + compilationPurpose: String, + createKotlinOptions: DefaultCompilationDetails<*>.() -> T +) : DefaultCompilationDetailsWithRuntime(target, compilationPurpose, createKotlinOptions) { + override val compilation: KotlinWithJavaCompilation + get() = super.compilation as KotlinWithJavaCompilation + + 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( + 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 + get() = super.relatedConfigurationNames + listOf( + "${androidVariant.name}ApiElements", + "${androidVariant.name}RuntimeElements", + androidVariant.compileConfiguration.name, + androidVariant.runtimeConfiguration.name + ) + } +} + +internal class MetadataCompilationDetails(target: KotlinTarget, name: String) : + DefaultCompilationDetails( + 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(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) { + 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) = + dependencies f@{ project.configure(this@f, configureClosure) } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCommonCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCommonCompilation.kt index 8ba8593876b..8ac1af0563a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCommonCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCommonCompilation.kt @@ -21,9 +21,9 @@ interface KotlinMetadataCompilation : KotlinCompilation class KotlinCommonCompilation( target: KotlinTarget, name: String -) : AbstractKotlinCompilation(target, name), KotlinMetadataCompilation { - - override val kotlinOptions: KotlinMultiplatformCommonOptions = KotlinMultiplatformCommonOptionsImpl() +) : AbstractKotlinCompilation( + MetadataCompilationDetails(target, name) +), KotlinMetadataCompilation { 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 }) - }) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroups.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroups.kt index fb61dc922f8..4ed1b6c66dd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroups.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroups.kt @@ -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<*>> = + private val moduleLeaderCompilationMap: MutableMap, 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 { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt index 582715de247..039d8825a8b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt @@ -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 get() = kotlinSourceSets + defaultSourceSet abstract class AbstractKotlinCompilation( - target: KotlinTarget, - override val compilationPurpose: String -) : KotlinCompilation, HasKotlinDependencies, KotlinCompilationData { + internal open val compilationDetails: CompilationDetails +) : KotlinCompilation, + // FIXME: replace with separate `final override`s, which is safer wrt accidental overrides + HasKotlinDependencies by compilationDetails.kotlinDependenciesHolder, + KotlinCompilationData 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 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( override val compileKotlinTaskProvider: TaskProvider> 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 = mutableSetOf() - - override val allKotlinSourceSets: Set - 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) = - addSourcesToKotlinCompileTask( - project, - compileKotlinTaskName, - sourceSet.customSourceFilesExtensions, - addAsCommonSources - ) { sourceSet.kotlin } - - internal fun addExactSourceSetsEagerly(sourceSets: Set) { - 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) = - dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) } - override fun toString(): String = "compilation '$compilationPurpose' ($target)" - internal val friendArtifactsTask: TaskProvider? 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 - get() = mutableListOf().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> = mutableSetOf() - override val associateWith: List> - 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( override val owner: KotlinTarget get() = target - override val compilationClassifier: String? - get() = target.disambiguationClassifier + override val allKotlinSourceSets: Set + get() = compilationDetails.directlyIncludedKotlinSourceSets + + compilationDetails.directlyIncludedKotlinSourceSets.resolveAllDependsOnSourceSets() - override val kotlinSourceDirectoriesByFragmentName: Map - 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 + 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> get() = mutableSetOf>().apply { fun visit(other: KotlinCompilation<*>) { @@ -387,17 +164,19 @@ internal val KotlinCompilation<*>.associateWithTransitiveClosure: Iterable( - target: KotlinTarget, - name: String -) : AbstractKotlinCompilation(target, name), KotlinCompilationToRunnableFiles { - override val runtimeDependencyConfigurationName: String - get() = lowerCamelCaseName( - target.disambiguationClassifier, - compilationPurpose.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }, - "runtimeClasspath" - ) + override val compilationDetails: CompilationDetailsWithRuntime, +) : AbstractKotlinCompilation(compilationDetails), + KotlinCompilationToRunnableFiles { - 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 + get() = super.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, "_") \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleFragment.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleFragment.kt index ab166f53d34..bfff3ae4de7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleFragment.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleFragment.kt @@ -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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt index 23319fb25f4..228cff75e79 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinJvmVariant.kt @@ -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 - get() = super.kotlinSourceSets - - override val allKotlinSourceSets: Set - get() { - val allMappedSourceSets = target.project.kotlinExtension.sourceSets - .filterIsInstance() - .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> 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) { - 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 = checkNotNull( target.project.locateTask( - (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 ) ) -} +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/util/DependencyFilesHolder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/util/DependencyFilesHolder.kt new file mode 100644 index 00000000000..4d825bda547 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/util/DependencyFilesHolder.kt @@ -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()) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt index 5f188d4c96c..d60e08354a9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsCompilation.kt @@ -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(target, name), KotlinCompilationWithResources { +open class KotlinJsCompilation internal constructor( + compilationDetails: JsCompilationDetails +) : AbstractKotlinCompilationToRunnableFiles(compilationDetails), + KotlinCompilationWithResources { + + 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 - ) - } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt index e05e1d08769..d271dae718e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrCompilation.kt @@ -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 = mutableSetOf() - - override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy) { - 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 - ) - } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt index 513ebe2f6cd..ebba65e4db6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt @@ -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(target, name) { - - override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl() +class KotlinJvmAndroidCompilation( + target: KotlinAndroidTarget, + name: String +) : AbstractKotlinCompilationToRunnableFiles(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 = target.project.objects.property(FileCollection::class.java) - @Suppress("UNCHECKED_CAST") - override val compileKotlinTaskProvider: TaskProvider - get() = super.compileKotlinTaskProvider as TaskProvider + 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 + get() = super.compileKotlinTaskProvider as TaskProvider - @Suppress("UnstableApiUsage") - internal val testedVariantArtifacts: Property = 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 - get() = super.relatedConfigurationNames + listOf( - "${androidVariant.name}ApiElements", - "${androidVariant.name}RuntimeElements", - androidVariant.compileConfiguration.name, - androidVariant.runtimeConfiguration.name - ) - - val compileJavaTaskProvider: TaskProvider? - get() = androidVariant.getJavaTaskProvider() - } + val compileJavaTaskProvider: TaskProvider? + get() = androidVariant.getJavaTaskProvider() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilation.kt index 81f1b75c535..838d0e7b15f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilation.kt @@ -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(target, name), KotlinCompilationWithResources { - - override val kotlinOptions: KotlinJvmOptions = KotlinJvmOptionsImpl() + compilationDetails: CompilationDetailsWithRuntime, +) : AbstractKotlinCompilationToRunnableFiles(compilationDetails), KotlinCompilationWithResources { + override val target: KotlinJvmTarget get() = compilationDetails.target as KotlinJvmTarget override val processResourcesTaskName: String get() = disambiguateName("processResources") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilationFactory.kt index 329b5856951..548fbc56bf6 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilationFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmCompilationFactory.kt @@ -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() } + ) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinWithJavaCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinWithJavaCompilation.kt index c74b0f8d1b3..3deadf18029 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinWithJavaCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinWithJavaCompilation.kt @@ -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( +class KotlinWithJavaCompilation( target: KotlinWithJavaTarget, name: String, - override val kotlinOptions: KotlinOptionsType -) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources { + kotlinOptions: KotlinOptionsType +) : AbstractKotlinCompilationToRunnableFiles(WithJavaCompilationDetails(target, name) { kotlinOptions }), + KotlinCompilationWithResources { 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 { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index bbe6ef9bc75..3bd73d38b7e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -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) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt index fb3c549faf7..c09d77fc311 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt @@ -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(target, compilationName), KotlinNativeCompilationData { - - override val kotlinOptions: KotlinCommonOptions = NativeCompileOptions { defaultSourceSet.languageSettings } + compilationDetails: CompilationDetails +) : AbstractKotlinCompilation( + compilationDetails +), + KotlinNativeCompilationData { override val compileKotlinTask: KotlinNativeCompile get() = super.compileKotlinTask as KotlinNativeCompile @@ -68,10 +69,6 @@ abstract class AbstractKotlinNativeCompilation( override val compileKotlinTaskProvider: TaskProvider get() = super.compileKotlinTaskProvider as TaskProvider - override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy) { - 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 +) : AbstractKotlinNativeCompilation(konanTarget, details), KotlinCompilationWithResources { + 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, name: String) : +class KotlinSharedNativeCompilation( + target: KotlinMetadataTarget, + val konanTargets: List, 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 { - 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 diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt index 38ef1dfd23b..b4936686984 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt @@ -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( diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroupsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroupsTest.kt index 69b8bdaa016..471a478802e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroupsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/internal/KotlinCompilationsModuleGroupsTest.kt @@ -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) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/SourceSetVisibilityInferenceTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/SourceSetVisibilityInferenceTest.kt index da4e190b0f8..e032ab620ce 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/SourceSetVisibilityInferenceTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/SourceSetVisibilityInferenceTest.kt @@ -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 { +) : KotlinCompilation, KotlinCompilationData { override val kotlinSourceSets: Set = setOf(defaultSourceSet) override val allKotlinSourceSets: Set @@ -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> 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 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 get() = throw UnsupportedOperationException() //endregion - override fun toString(): String = "compilation '${name}'" }