提交 99ce0477 编写于 作者: A Anton Lakotka

Add separate Plugin Classpaths per compilation

Make them extend the common CP for sake of backward compatibility
^KT-45020 Fixed
上级 9476175c
/*
* 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.
*/
@file:Suppress("invisible_reference", "invisible_member", "FunctionName")
package org.jetbrains.kotlin.gradle.mpp
import org.gradle.api.Project
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.provider.Provider
import org.gradle.testfixtures.ProjectBuilder
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import kotlin.test.Test
import kotlin.test.assertEquals
import kotlin.test.assertNotNull
import kotlin.test.assertTrue
internal class CompilationSpecificPluginPath {
@Test
fun `each compilation should have its own plugin classpath`() {
val project = buildProjectWithMPP {
kotlin {
jvm("jvm1")
jvm("jvm2")
js("js") { browser() }
}
}
// Expect to see plugin classpath for each target compilation
listOf("jvm1", "jvm2", "js")
.map(String::capitalize)
.flatMap { listOf(pluginClassPathConfiguration(it, "main"), pluginClassPathConfiguration(it, "test")) }
.plus(pluginClassPathConfiguration("metadata", "main")) // and also one for metadata
.forEach { assertNotNull(project.configurations.findByName(it), "Configuration $it should exist") }
}
@Test
fun `kotlin plugin author can control plugin artifacts per compilation`() {
// Given platform-specific Kotlin plugins
class JvmOnly : FakeSubPlugin("jvmOnly", null, { target.platformType == KotlinPlatformType.jvm })
class JsOnly : FakeSubPlugin("jsOnly", null, { target.platformType == KotlinPlatformType.js })
// When apply them to a Kotlin MPP Project
val project = buildProjectWithMPP {
plugins.apply(JvmOnly::class.java)
plugins.apply(JsOnly::class.java)
kotlin {
jvm("desktop")
js("web", IR) {
browser()
}
}
}
project.evaluate()
// Then each plugin classpath should have its own dependency
assertEquals(listOf("kotlin-scripting-compiler-embeddable", "jvmOnly"), project.subplugins("desktop"))
assertEquals(listOf("kotlin-scripting-compiler-embeddable", "jsOnly"), project.subplugins("web"))
// And each compilation task should have its own plugin classpath
val compileDesktop = project.tasks.getByName("compileKotlinDesktop") as KotlinCompile
val expectedConfig = project.configurations.getByName(pluginClassPathConfiguration("desktop", "main"))
assertEquals(expectedConfig, compileDesktop.pluginClasspath)
}
@Test
fun `native artifact should take precedence over regular artifact for native platform`() {
// Given common plugin but with native-specific artifact
class NativeSpecificPlugin : FakeSubPlugin("common", "native", { true })
val project = buildProjectWithMPP {
plugins.apply(NativeSpecificPlugin::class.java)
kotlin {
jvm()
linuxX64()
}
}
project.evaluate()
assertTrue("common" in project.subplugins("jvm"))
assertTrue("native" in project.subplugins("linuxX64"))
assertTrue("common" !in project.subplugins("linuxX64"))
}
@Test
fun `it should be possible to add common plugin classpath to all compilations except native`() {
// Given MPP project
val project = buildProjectWithMPP {
kotlin {
jvm()
js { browser() }
linuxX64("native")
}
}
// When adding a shared plugin to common Plugin Classpath
project.dependencies.add(PLUGIN_CLASSPATH_CONFIGURATION_NAME, "test:shared")
project.evaluate()
// Then ALL compilations should have shared plugin EXCEPT native
assertTrue("shared" in project.subplugins("jvm"))
assertTrue("shared" in project.subplugins("js"))
assertTrue("shared" in project.subplugins("js", "test"))
assertTrue("shared" in project.subplugins("metadata"))
assertTrue("shared" !in project.subplugins("native"))
}
@Test
fun `native compilations should have its own shared plugin classpath`() {
// Given MPP project
val project = buildProjectWithMPP {
kotlin {
jvm()
linuxX64("linux")
linuxX64("mac")
}
}
// When adding a shared plugin to native Plugin Classpath
project.dependencies.add(NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME, "test:shared")
project.evaluate()
// Then ALL native compilations should have shared plugin
assertTrue("shared" in project.subplugins("linux"))
assertTrue("shared" in project.subplugins("mac"))
assertTrue("shared" in project.subplugins("mac", "test"))
// And all non-native should not have it
assertTrue("shared" !in project.subplugins("metadata"))
assertTrue("shared" !in project.subplugins("jvm"))
}
private fun pluginClassPathConfiguration(target: String, compilation: String) =
"kotlinCompilerPluginClasspath${target.capitalize()}${compilation.capitalize()}"
private fun Project.subplugins(target: String, compilation: String = "main") = this
.configurations
.getByName(pluginClassPathConfiguration(target, compilation))
.allDependencies
.map { it.name }
private fun buildProjectWithMPP(code: Project.() -> Unit): ProjectInternal {
val project = ProjectBuilder.builder().build()
project.plugins.apply("kotlin-multiplatform")
project.code()
return project as ProjectInternal
}
private fun Project.kotlin(code: KotlinMultiplatformExtension.() -> Unit) {
val kotlin = project.kotlinExtension as KotlinMultiplatformExtension
kotlin.code()
}
private abstract class FakeSubPlugin(
val id: String,
val idNative: String? = null,
val isApplicablePredicate: KotlinCompilation<*>.() -> Boolean
) : KotlinCompilerPluginSupportPlugin {
override fun isApplicable(kotlinCompilation: KotlinCompilation<*>): Boolean = kotlinCompilation.isApplicablePredicate()
override fun applyToCompilation(kotlinCompilation: KotlinCompilation<*>): Provider<List<SubpluginOption>> =
kotlinCompilation.target.project.provider { emptyList<SubpluginOption>() }
override fun getCompilerPluginId(): String = id
override fun getPluginArtifact(): SubpluginArtifact = SubpluginArtifact(
"test",
id
)
override fun getPluginArtifactForNative(): SubpluginArtifact? = idNative?.let {
SubpluginArtifact(
"test",
it
)
}
}
}
\ No newline at end of file
......@@ -21,7 +21,6 @@ import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChan
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger
import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector
import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.tasks.GradleCompileTaskProvider
import org.jetbrains.kotlin.gradle.utils.getValue
......@@ -35,14 +34,7 @@ abstract class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput<
@get:Classpath
@get:InputFiles
@Suppress("unused")
internal val kotlinTaskPluginClasspaths
get() = kotlinCompileTask.pluginClasspath
@get:Classpath
@get:InputFiles
val pluginClasspath: FileCollection
get() = project.configurations.getByName(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
val pluginClasspath: FileCollection get() = kotlinCompileTask.pluginClasspath
@get:Internal
val taskProvider = GradleCompileTaskProvider(this)
......
......@@ -564,9 +564,6 @@ internal abstract class AbstractKotlinPlugin(
// Setup the consuming configurations:
project.dependencies.attributesSchema.attribute(KotlinPlatformType.attribute)
kotlinTarget.compilations.all { compilation ->
AbstractKotlinTargetConfigurator.defineConfigurationsForCompilation(compilation)
}
project.configurations.getByName("default").apply {
setupAsLocalTargetSpecificConfigurationIfSupported(kotlinTarget)
......@@ -595,6 +592,7 @@ internal abstract class AbstractKotlinPlugin(
buildSourceSetProcessor: (AbstractKotlinCompilation<*>) -> KotlinSourceSetProcessor<*>
) {
kotlinTarget.compilations.all { compilation ->
AbstractKotlinTargetConfigurator.defineConfigurationsForCompilation(compilation)
buildSourceSetProcessor(compilation).run()
}
}
......
......@@ -24,7 +24,6 @@ import org.gradle.api.internal.FeaturePreviews
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.cli.common.CompilerSystemProperties
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
......
......@@ -272,6 +272,17 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
val target = compilation.target
val configurations = target.project.configurations
val pluginConfiguration = configurations.maybeCreate(compilation.pluginConfigurationName).apply {
if (target.platformType == KotlinPlatformType.native) {
extendsFrom(configurations.getByName(NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME))
} else {
extendsFrom(target.project.commonKotlinPluginClasspath)
}
isVisible = false
isCanBeConsumed = false
description = "Kotlin compiler plugins for $compilation"
}
val compileConfiguration = configurations.findByName(compilation.deprecatedCompileConfigurationName)?.apply {
isCanBeConsumed = false
setupAsLocalTargetSpecificConfigurationIfSupported(target)
......@@ -493,3 +504,7 @@ fun Configuration.usesPlatformOf(target: KotlinTarget): Configuration {
}
return this
}
internal val Project.commonKotlinPluginClasspath get() = configurations.getByName(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
internal val KotlinCompilation<*>.pluginConfigurationName
get() = lowerCamelCaseName(PLUGIN_CLASSPATH_CONFIGURATION_NAME, target.disambiguationClassifier, compilationName)
\ No newline at end of file
......@@ -66,12 +66,11 @@ class SubpluginEnvironment(
val pluginId = subplugin.getCompilerPluginId()
project.logger.kotlinDebug { "Loading subplugin $pluginId" }
subplugin.getPluginArtifact().let { artifact ->
project.addMavenDependency(PLUGIN_CLASSPATH_CONFIGURATION_NAME, artifact)
}
subplugin.getPluginArtifactForNative()?.let { artifact ->
project.addMavenDependency(NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME, artifact)
val nativeArtifact = subplugin.getPluginArtifactForNative()
if (nativeArtifact != null && kotlinCompilation.platformType == KotlinPlatformType.native) {
project.addMavenDependency(kotlinCompilation.pluginConfigurationName, nativeArtifact)
} else {
project.addMavenDependency(kotlinCompilation.pluginConfigurationName, subplugin.getPluginArtifact())
}
val subpluginOptionsProvider = subplugin.applyToCompilation(kotlinCompilation)
......
......@@ -65,7 +65,9 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
.addSubpluginOptions(project, compilation)
compilation.compileKotlinTaskProvider.configure {
it.compilerPluginClasspath = project.configurations.getByName(NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME)
it.compilerPluginClasspath = project
.configurations
.getByName(compilation.pluginConfigurationName)
}
}
}
......
......@@ -38,10 +38,8 @@ import org.jetbrains.kotlin.gradle.internal.*
import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
import org.jetbrains.kotlin.gradle.logging.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.COMPILER_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformPluginBase
import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithTransitiveClosure
import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName
......@@ -219,7 +217,9 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
@get:InputFiles
@get:Classpath
open val pluginClasspath: FileCollection = project.configurations.getByName(PLUGIN_CLASSPATH_CONFIGURATION_NAME)
open val pluginClasspath: FileCollection by project.provider {
project.configurations.getByName(taskData.compilation.pluginConfigurationName)
}
@get:Internal
internal val pluginOptions = CompilerPluginOptions()
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册