Add separate Plugin Classpaths per compilation
Make them extend the common CP for sake of backward compatibility ^KT-45020 Fixed
This commit is contained in:
+185
@@ -0,0 +1,185 @@
|
||||
/*
|
||||
* 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
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-9
@@ -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)
|
||||
|
||||
+1
-3
@@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -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
|
||||
|
||||
+15
@@ -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)
|
||||
+5
-6
@@ -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)
|
||||
|
||||
+3
-1
@@ -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)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -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()
|
||||
|
||||
Reference in New Issue
Block a user