From 5a58c1c437bfdfe890288b2766286f59c231b773 Mon Sep 17 00:00:00 2001 From: Anton Lakotka Date: Fri, 23 Apr 2021 16:42:45 +0200 Subject: [PATCH] [Kotlin Project Model] Add compiler plugin support --- .../mpp/pm20/GradleKpmCompilerPlugin.kt | 17 +++ .../plugin/mpp/pm20/KotlinGradleModule.kt | 3 + .../mpp/pm20/GradleKpmCompilerPlugin.kt | 63 +++++++++++ .../pm20/KotlinCompilationTaskConfigurator.kt | 21 ++-- .../plugin/mpp/pm20/KotlinGradleModule.kt | 13 ++- .../mpp/pm20/fragmentsMetadataCompilation.kt | 30 +++++- .../targets/native/tasks/KotlinNativeTasks.kt | 19 +++- .../gradle/tasks/CompilerPluginOptions.kt | 9 ++ .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 30 +++++- .../src/main/kotlin/KotlinAttributes.kt | 5 + .../src/main/kotlin/KotlinModule.kt | 4 + .../src/main/kotlin/KotlinModuleFragment.kt | 1 + .../src/main/kotlin/KpmCompilerPlugin.kt | 102 ++++++++++++++++++ 13 files changed, 292 insertions(+), 25 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt create mode 100644 libraries/tools/kotlin-project-model/src/main/kotlin/KpmCompilerPlugin.kt diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt new file mode 100644 index 00000000000..5ec7df7d7a2 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt @@ -0,0 +1,17 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.mpp.pm20 + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.jetbrains.kotlin.project.model.* + +/** + * Gradle plugin that provides [KpmCompilerPlugin] from applied [Project] + */ +interface GradleKpmCompilerPlugin : Plugin { + val kpmCompilerPlugin: KpmCompilerPlugin +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt index 8fd3ea85285..547ad4c77e1 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt @@ -13,6 +13,7 @@ import org.gradle.api.Project import org.jetbrains.kotlin.gradle.plugin.HasKotlinDependencies import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler import org.jetbrains.kotlin.project.model.KotlinModule +import org.jetbrains.kotlin.project.model.KpmCompilerPlugin interface KotlinGradleModule : KotlinModule, Named, HasKotlinDependencies { val project: Project @@ -23,6 +24,8 @@ interface KotlinGradleModule : KotlinModule, Named, HasKotlinDependencies { // TODO DSL & build script model: find a way to create a flexible typed view on fragments? override val variants: NamedDomainObjectSet + override val plugins: Set + val isPublic: Boolean fun ifMadePublic(action: () -> Unit) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt new file mode 100644 index 00000000000..7b59c8c39f6 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmCompilerPlugin.kt @@ -0,0 +1,63 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.plugin.mpp.pm20 + +import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.jetbrains.kotlin.gradle.plugin.SubpluginOption +import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion +import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerPluginData +import org.jetbrains.kotlin.gradle.utils.newProperty +import org.jetbrains.kotlin.project.model.* + +internal fun Project.compilerPluginProviderForMetadata( + fragment: KotlinGradleFragment, + compilationData: KotlinCommonFragmentMetadataCompilationData +) = compilerPluginDataProvider(compilationData, fragment::metadataCompilationPluginData) + +internal fun Project.compilerPluginProviderForNativeMetadata( + fragment: KotlinGradleFragment, + compilationData: KotlinNativeFragmentMetadataCompilationData +) = compilerPluginDataProvider(compilationData, fragment::nativeMetadataCompilationPluginData) + +internal fun Project.compilerPluginProviderForPlatformCompilation( + variant: KotlinGradleVariant, + compilationData: KotlinCompilationData<*> +) = compilerPluginDataProvider(compilationData, variant::platformCompilationPluginData) + +internal fun KotlinCompilationData<*>.pluginClasspathConfigurationName() = "${compileKotlinTaskName}PluginClasspath" + +private fun Project.compilerPluginDataProvider( + compilationData: KotlinCompilationData<*>, + pluginDataList: () -> List +): Provider { + val configurationName = compilationData.pluginClasspathConfigurationName() + val pluginClasspathConfiguration = + configurations.maybeCreate(configurationName).apply { + isCanBeConsumed = false + isCanBeResolved = true + isVisible = false + } + + val pluginOptions = CompilerPluginOptions() + return newProperty { + for (pluginData in pluginDataList()) { + dependencies.add(pluginClasspathConfiguration.name, pluginData.artifact.toGradleCoordinates(project)) + pluginData.options.forEach { (key, value) -> + pluginOptions.addPluginArgument(pluginData.pluginId, SubpluginOption(key, value)) + } + } + + KotlinCompilerPluginData( + classpath = pluginClasspathConfiguration, + options = pluginOptions + ) + }.apply { finalizeValueOnRead() } +} + +private fun PluginData.ArtifactCoordinates.toGradleCoordinates(project: Project): String = + "$group:$artifact:${version ?: project.getKotlinPluginVersion()}" diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationTaskConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationTaskConfigurator.kt index e2d0addb119..315f416f1b5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationTaskConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinCompilationTaskConfigurator.kt @@ -9,13 +9,11 @@ import org.gradle.api.Project import org.gradle.api.tasks.TaskProvider import org.jetbrains.kotlin.gradle.plugin.Kotlin2JvmSourceSetProcessor import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator -import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion import org.jetbrains.kotlin.gradle.plugin.mpp.addCommonSourcesToKotlinCompileTask import org.jetbrains.kotlin.gradle.plugin.mpp.addSourcesToKotlinCompileTask import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider -import org.jetbrains.kotlin.gradle.tasks.withType open class KotlinCompilationTaskConfigurator( protected val project: Project @@ -29,34 +27,37 @@ open class KotlinCompilationTaskConfigurator( fragmentSourcesProvider.getCommonSourcesFromRefinesClosure(fragment) fun createKotlinJvmCompilationTask( - fragment: KotlinGradleFragment, + variant: KotlinGradleVariant, compilationData: KotlinCompilationData<*> ): TaskProvider { Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(), compilationData).run() - val allSources = getSourcesForFragmentCompilation(fragment) - val commonSources = getCommonSourcesForFragmentCompilation(fragment) + val allSources = getSourcesForFragmentCompilation(variant) + val commonSources = getCommonSourcesForFragmentCompilation(variant) // FIXME support custom source file extensions in the two calls below addSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { allSources } addCommonSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { commonSources } - return project.tasks.withType().named(compilationData.compileKotlinTaskName) + return project.tasks.named(compilationData.compileKotlinTaskName, KotlinCompile::class.java) { + it.kotlinPluginData = project.compilerPluginProviderForPlatformCompilation(variant, compilationData) + } } fun createKotlinNativeCompilationTask( - fragment: KotlinGradleFragment, + variant: KotlinGradleVariant, compilationData: KotlinNativeCompilationData<*> ): TaskProvider { val compileTask = KotlinNativeTargetConfigurator.createKlibCompilationTask(compilationData) - val allSources = getSourcesForFragmentCompilation(fragment) - val commonSources = getCommonSourcesForFragmentCompilation(fragment) + val allSources = getSourcesForFragmentCompilation(variant) + val commonSources = getCommonSourcesForFragmentCompilation(variant) compileTask.configure { it.source(allSources) it.commonSources.from(commonSources) - } + it.kotlinPluginData = project.compilerPluginProviderForPlatformCompilation(variant, compilationData) + } return compileTask } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt index 90020f10267..713b8d08e22 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/KotlinGradleModule.kt @@ -9,9 +9,7 @@ import org.gradle.api.ExtensiblePolymorphicDomainObjectContainer import org.gradle.api.NamedDomainObjectSet import org.gradle.api.Project import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName -import org.jetbrains.kotlin.project.model.KotlinModuleFragment -import org.jetbrains.kotlin.project.model.KotlinModuleIdentifier -import org.jetbrains.kotlin.project.model.LocalModuleIdentifier +import org.jetbrains.kotlin.project.model.* import javax.inject.Inject open class KotlinGradleModuleInternal( @@ -36,6 +34,15 @@ open class KotlinGradleModuleInternal( fragments.withType(KotlinGradleVariant::class.java) } + override val plugins: Set by lazy { + mutableSetOf().also { set -> + project + .plugins + .withType(GradleKpmCompilerPlugin::class.java) + .mapTo(set, GradleKpmCompilerPlugin::kpmCompilerPlugin) + } + } + override var isPublic: Boolean = false protected set diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt index a01f4d9d140..b881f8980de 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/fragmentsMetadataCompilation.kt @@ -8,8 +8,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.pm20 import org.gradle.api.DefaultTask import org.gradle.api.Project import org.gradle.api.attributes.Usage -import org.gradle.api.file.FileCollection -import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskProvider import org.gradle.jvm.tasks.Jar import org.jetbrains.kotlin.gradle.dsl.pm20Extension @@ -17,9 +15,9 @@ import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.KotlinCommonSourceSetProcessor import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.ComputedCapability -import org.jetbrains.kotlin.gradle.targets.metadata.NativeSharedCompilationProcessor import org.jetbrains.kotlin.gradle.targets.metadata.createGenerateProjectStructureMetadataTask import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives +import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.tasks.withType @@ -28,7 +26,6 @@ import org.jetbrains.kotlin.gradle.utils.dashSeparatedName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION import org.jetbrains.kotlin.project.model.KotlinModuleFragment -import java.io.File import java.util.concurrent.Callable internal fun configureMetadataResolutionAndBuild(module: KotlinGradleModule) { @@ -204,7 +201,7 @@ private fun createNativeMetadataCompilation( metadataCompilationRegistry, lazy { resolvedMetadataProviders(fragment) } ) - MetadataCompilationTasksConfigurator(project).createKotlinNativeCompilationTask(fragment, metadataCompilationData) + MetadataCompilationTasksConfigurator(project).createKotlinNativeMetadataCompilationTask(fragment, metadataCompilationData) metadataCompilationRegistry.registerNative(fragment, metadataCompilationData) } @@ -222,6 +219,29 @@ private class MetadataCompilationTasksConfigurator(project: Project) : KotlinCom addSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { allSources } addCommonSourcesToKotlinCompileTask(project, compilationData.compileKotlinTaskName, emptyList()) { commonSources } + + project.tasks.named(compilationData.compileKotlinTaskName, AbstractKotlinCompile::class.java).configure { + it.kotlinPluginData = project.compilerPluginProviderForMetadata(fragment, compilationData) + } + } + + fun createKotlinNativeMetadataCompilationTask( + fragment: KotlinGradleFragment, + compilationData: KotlinNativeFragmentMetadataCompilationData + ): TaskProvider { + val compileTask = KotlinNativeTargetConfigurator.createKlibCompilationTask(compilationData) + + val allSources = getSourcesForFragmentCompilation(fragment) + val commonSources = getCommonSourcesForFragmentCompilation(fragment) + + compileTask.configure { + it.source(allSources) + it.commonSources.from(commonSources) + + it.kotlinPluginData = project.compilerPluginProviderForNativeMetadata(fragment, compilationData) + } + + return compileTask } override fun getSourcesForFragmentCompilation(fragment: KotlinGradleFragment): MultipleSourceRootsProvider { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index f8ff81c8adf..c84d6da0ef5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -23,7 +23,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated -import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData @@ -227,6 +226,13 @@ abstract class AbstractKotlinNativeCompile? = null + // Used by IDE via reflection. @get:Internal val serializedCompilerArguments: List @@ -249,17 +255,20 @@ abstract class AbstractKotlinNativeCompile - pluginClasspath.map { it.canonicalPath }.sorted().forEach { path -> + fun addPluginOptions(classpath: FileCollection, options: CompilerPluginOptions) { + classpath.map { it.canonicalPath }.sorted().forEach { path -> add("-Xplugin=$path") } - compilerPluginOptions.arguments.forEach { + options.arguments.forEach { add("-P") add(it) } } + // Compiler plugins. + compilerPluginClasspath?.let { addPluginOptions(it, compilerPluginOptions) } + kotlinPluginData?.orNull?.let { addPluginOptions(it.classpath, it.options) } + // kotlin options addKey("-Werror", kotlinOptions.allWarningsAsErrors) addKey("-nowarn", kotlinOptions.suppressWarnings) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt index f5d32fca392..f6db9546a07 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt @@ -32,4 +32,13 @@ class CompilerPluginOptions { fun addPluginArgument(pluginId: String, option: SubpluginOption) { subpluginOptionsByPluginId.getOrPut(pluginId) { mutableListOf() }.add(option) } + + operator fun plus(options: CompilerPluginOptions?): CompilerPluginOptions { + if (options == null) return this + val newOptions = CompilerPluginOptions() + newOptions.subpluginOptionsByPluginId += subpluginOptionsByPluginId + newOptions.subpluginOptionsByPluginId += options.subpluginOptionsByPluginId + + return newOptions + } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 3b783a8ccf1..0776b89f787 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -210,6 +210,15 @@ abstract class AbstractKotlinCompile : AbstractKotl protected val multiModuleICSettings: MultiModuleICSettings get() = MultiModuleICSettings(buildHistoryFile.get().asFile, useModuleDetection.get()) + + /* + @get:InputFiles + @get:Classpath + open val pluginClasspath: FileCollection by project.provider { + (taskData.compilation as? KotlinCompilation<*>?)?.pluginConfigurationName?.let(project.configurations::getByName) + ?: project.files() + } + */ @get:InputFiles @get:Classpath open val pluginClasspath: ConfigurableFileCollection = objects.fileCollection() @@ -220,6 +229,13 @@ abstract class AbstractKotlinCompile : AbstractKotl @get:Input val sourceFilesExtensions: ListProperty = objects.listProperty(String::class.java).value(DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS) + /** + * Plugin Data provided by [KpmCompilerPlugin] + */ + @get:Optional + @get:Nested + internal var kotlinPluginData: Provider? = null + // Input is needed to force rebuild even if source files are not changed @get:Input internal val coroutines: Property = objects.property(Coroutines::class.java) @@ -369,8 +385,9 @@ open class KotlinCompileArgumentsProvider = taskProvider.coroutines val logger: Logger = taskProvider.logger val isMultiplatform: Boolean = taskProvider.multiPlatformEnabled.get() - val pluginClasspath: FileCollection = taskProvider.pluginClasspath - val pluginOptions: CompilerPluginOptions = taskProvider.pluginOptions + val pluginData = taskProvider.kotlinPluginData?.orNull + val pluginClasspath: FileCollection = taskProvider.pluginClasspath // TODO: Add pluginData + val pluginOptions: CompilerPluginOptions = taskProvider.pluginOptions // TODO: Add pluginData } class KotlinJvmCompilerArgumentsProvider @@ -767,3 +784,12 @@ abstract class Kotlin2JsCompile @Inject constructor( compilerRunner.runJsCompilerAsync(sourceRoots.kotlinSourceFiles, commonSourceSet.toList(), args, environment) } } + +data class KotlinCompilerPluginData( + @get:InputFiles + @get:Classpath + val classpath: FileCollection, + + @get:Internal + val options: CompilerPluginOptions +) diff --git a/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinAttributes.kt b/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinAttributes.kt index e52c5018034..91017596764 100644 --- a/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinAttributes.kt +++ b/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinAttributes.kt @@ -5,6 +5,10 @@ package org.jetbrains.kotlin.project.model +// TODO: Add better Kotlin Variant Attributes management +// Ideally we should respect the nature of Attributes and express values in form of Complete Lattice +// Moreover we can add support for default and most used Value Types (eg. Enums) + open class KotlinAttributeKey( val uniqueName: String ) { @@ -15,6 +19,7 @@ open class KotlinAttributeKey( uniqueName.hashCode() } +// TODO: Introduce ENUM object KotlinPlatformTypeAttribute : KotlinAttributeKey("org.jetbrains.kotlin.platform.type") { const val JVM = "jvm" const val ANDROID_JVM = "androidJvm" diff --git a/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModule.kt b/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModule.kt index 77e02d58ba8..97071e58bce 100644 --- a/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModule.kt +++ b/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModule.kt @@ -42,6 +42,8 @@ interface KotlinModule { val variants: Iterable get() = fragments.filterIsInstance() + val plugins: Iterable + // TODO: isSynthetic? } @@ -50,5 +52,7 @@ open class BasicKotlinModule( ) : KotlinModule { override val fragments = mutableListOf() + override val plugins = mutableListOf() + override fun toString(): String = "module $moduleIdentifier" } \ No newline at end of file diff --git a/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModuleFragment.kt b/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModuleFragment.kt index 8c3d8a86ffb..219506a8997 100644 --- a/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModuleFragment.kt +++ b/libraries/tools/kotlin-project-model/src/main/kotlin/KotlinModuleFragment.kt @@ -45,6 +45,7 @@ val KotlinModuleFragment.refinesClosure: Set visit(this@refinesClosure) } +val KotlinModuleVariant.platform get() = variantAttributes[KotlinPlatformTypeAttribute] open class BasicKotlinModuleFragment( override val containingModule: KotlinModule, diff --git a/libraries/tools/kotlin-project-model/src/main/kotlin/KpmCompilerPlugin.kt b/libraries/tools/kotlin-project-model/src/main/kotlin/KpmCompilerPlugin.kt new file mode 100644 index 00000000000..f0dd7816025 --- /dev/null +++ b/libraries/tools/kotlin-project-model/src/main/kotlin/KpmCompilerPlugin.kt @@ -0,0 +1,102 @@ +/* + * 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.project.model + +/** + * Adapts Kotlin Compiler Plugin for Multiplatform Kotlin Project Model + * Build System uses this interface to identify applicable plugin artifacts and its options + * before executing actual Kotlin Compilation + */ +interface KpmCompilerPlugin { + + /** + * Returns [PluginData] when applicable for [fragment] compilation + * Returns [null] if not applicable + */ + fun forMetadataCompilation(fragment: KotlinModuleFragment): PluginData? + + /** + * Returns [PluginData] when applicable for [fragment] compilation + * Returns [null] if not applicable + */ + fun forNativeMetadataCompilation(fragment: KotlinModuleFragment): PluginData? + + /** + * Returns [PluginData] when applicable for [variant] compilation + * Returns [null] if not applicable + */ + fun forPlatformCompilation(variant: KotlinModuleVariant): PluginData? +} + +/** + * Plugin data can be used for changing some compilation request + */ +data class PluginData( + val pluginId: String, + val artifact: ArtifactCoordinates, + val options: List +) { + // FIXME: (?) Is it common thing or gradle/maven centric? + data class ArtifactCoordinates( + val group: String, + val artifact: String, + val version: String? = null + ) + + data class PluginOption( + val key: String, + val value: String + ) +} + +// TODO: It should be part of "Compilation Process": KotlinModule.compilationRequestFor(METADATA | PLATFORM) -> CompilationRequest +// But there is no such thing at the moment :) +fun KotlinModuleFragment.metadataCompilationPluginData(): List = + containingModule + .plugins + .mapNotNull { plugin -> plugin.forMetadataCompilation(this) } + +fun KotlinModuleFragment.nativeMetadataCompilationPluginData(): List = + containingModule + .plugins + .mapNotNull { plugin -> plugin.forNativeMetadataCompilation(this) } + +fun KotlinModuleVariant.platformCompilationPluginData(): List = + containingModule + .plugins + .mapNotNull { plugin -> plugin.forPlatformCompilation(this) } + +/** + * Represents trivial Compiler Plugin adapter for Kotlin Project Model + * Where Compiler Plugin can have common and native artifacts + */ +abstract class BasicKpmCompilerPlugin : KpmCompilerPlugin { + + abstract val pluginId: String + + protected abstract fun commonPluginArtifact(): PluginData.ArtifactCoordinates? + + protected abstract fun nativePluginArtifact(): PluginData.ArtifactCoordinates? + + protected abstract val pluginOptions: List + + + override fun forMetadataCompilation(fragment: KotlinModuleFragment) = pluginDataOrNull(commonPluginArtifact()) + + override fun forNativeMetadataCompilation(fragment: KotlinModuleFragment) = pluginDataOrNull(nativePluginArtifact()) + + override fun forPlatformCompilation(variant: KotlinModuleVariant) = + when (variant.platform) { + KotlinPlatformTypeAttribute.NATIVE -> nativePluginArtifact() + else -> commonPluginArtifact() + }.let(::pluginDataOrNull) + + private fun pluginDataOrNull(artifact: PluginData.ArtifactCoordinates?) = + if (artifact != null) PluginData(pluginId, artifact, pluginOptions) + else null +} + +