Implement new MPP plugin
This commit is contained in:
@@ -130,6 +130,10 @@ pluginBundle {
|
||||
id = 'org.jetbrains.kotlin.jvm'
|
||||
description = displayName = 'Kotlin JVM plugin'
|
||||
}
|
||||
kotlinMultiplatformPlugin {
|
||||
id = 'org.jetbrains.kotlin.multiplatform'
|
||||
description = displayName = 'Kotlin Multiplatform plugin'
|
||||
}
|
||||
kotlinAndroidPlugin {
|
||||
id = 'org.jetbrains.kotlin.android'
|
||||
description = displayName = 'Kotlin Android plugin'
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.dsl
|
||||
|
||||
import org.gradle.api.NamedDomainObjectCollection
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetPreset
|
||||
|
||||
open class KotlinMultiplatformExtension : KotlinProjectExtension() {
|
||||
lateinit var presets: NamedDomainObjectCollection<KotlinTargetPreset<*>>
|
||||
internal set
|
||||
|
||||
lateinit var targets: NamedDomainObjectCollection<KotlinTarget>
|
||||
internal set
|
||||
}
|
||||
+15
@@ -121,6 +121,21 @@ open class Kotlin2JsPluginWrapper @Inject constructor(
|
||||
get() = KotlinSingleJavaTargetExtension::class
|
||||
}
|
||||
|
||||
open class KotlinMultiplatformPluginWrapper @Inject constructor(
|
||||
fileResolver: FileResolver,
|
||||
private val instantiator: Instantiator,
|
||||
private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry
|
||||
): KotlinBasePluginWrapper(fileResolver) {
|
||||
override fun getPlugin(project: Project, kotlinGradleBuildServices: KotlinGradleBuildServices): Plugin<Project> =
|
||||
KotlinMultiplatformPlugin(
|
||||
buildOutputCleanupRegistry, fileResolver,
|
||||
instantiator, kotlinPluginVersion
|
||||
)
|
||||
|
||||
override val projectExtensionClass: KClass<out KotlinMultiplatformExtension>
|
||||
get() = KotlinMultiplatformExtension::class
|
||||
}
|
||||
|
||||
fun Project.getKotlinPluginVersion(): String? =
|
||||
plugins.asSequence().mapNotNull { (it as? KotlinBasePluginWrapper)?.kotlinPluginVersion }.firstOrNull()
|
||||
|
||||
|
||||
+366
@@ -0,0 +1,366 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ConfigurationContainer
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.PublishArtifact
|
||||
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.artifacts.ArtifactAttributes
|
||||
import org.gradle.api.internal.plugins.DslObject
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.tasks.bundling.Jar
|
||||
import org.gradle.internal.cleanup.BuildOutputCleanupRegistry
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.fullName
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||
import java.io.File
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
open class KotlinTargetConfigurator(
|
||||
private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry
|
||||
) {
|
||||
fun <KotlinCompilationType: KotlinCompilation> configureTarget(
|
||||
project: Project,
|
||||
target: KotlinOnlyTarget<KotlinCompilationType>
|
||||
) {
|
||||
configureCompilationDefaults(project, target)
|
||||
configureCompilations(project, target)
|
||||
defineConfigurationsForTarget(project, target)
|
||||
configureArchivesAndComponent(project, target)
|
||||
configureBuild(project, target)
|
||||
|
||||
setCompatibilityOfAbstractCompileTasks(project)
|
||||
}
|
||||
|
||||
private fun <KotlinCompilationType: KotlinCompilation> configureCompilations(
|
||||
project: Project,
|
||||
platformTarget: KotlinOnlyTarget<KotlinCompilationType>
|
||||
) {
|
||||
val main = platformTarget.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
|
||||
platformTarget.compilations.create(KotlinCompilation.TEST_COMPILATION_NAME).apply {
|
||||
compileDependencyFiles = project.files(main.output, project.configurations.maybeCreate(compileDependencyConfigurationName))
|
||||
|
||||
if (this is KotlinCompilationToRunnableFiles) {
|
||||
runtimeDependencyFiles = project.files(output, main.output, project.configurations.maybeCreate(runtimeDependencyConfigurationName))
|
||||
}
|
||||
}
|
||||
|
||||
platformTarget.compilations.all {
|
||||
buildOutputCleanupRegistry.registerOutputs(it.output)
|
||||
}
|
||||
}
|
||||
|
||||
private fun <KotlinCompilationType: KotlinCompilation> configureCompilationDefaults(project: Project, target: KotlinOnlyTarget<KotlinCompilationType>) {
|
||||
target.compilations.all { compilation ->
|
||||
defineConfigurationsForCompilation(compilation, target, project.configurations)
|
||||
|
||||
project.kotlinExtension.sourceSets.maybeCreate(compilation.fullName).also { sourceSet ->
|
||||
compilation.source(sourceSet) // also adds dependencies, requires the configurations for target and source set to exist at this point
|
||||
}
|
||||
|
||||
if (compilation is KotlinCompilationWithResources) {
|
||||
configureResourceProcessing(project, compilation, project.files())
|
||||
}
|
||||
|
||||
createLifecycleTask(compilation, project)
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureArchivesAndComponent(project: Project, target: KotlinOnlyTarget<*>) {
|
||||
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
|
||||
val jar = project.tasks.create(target.artifactsTaskName, Jar::class.java)
|
||||
jar.description = "Assembles a jar archive containing the main classes."
|
||||
jar.group = BasePlugin.BUILD_GROUP
|
||||
jar.from(mainCompilation.output)
|
||||
|
||||
val jarArtifact = ArchivePublishArtifact(jar)
|
||||
val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
|
||||
|
||||
target.disambiguationClassifier?.let { jar.classifier = it }
|
||||
|
||||
// Workaround: adding the artifact during configuration seems to interfere with the Java plugin, which results into missing
|
||||
// task dependency 'assemble -> jar' if the Java plugin is applied after this steps
|
||||
project.afterEvaluate {
|
||||
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, jar) { jarArtifact ->
|
||||
jarArtifact.builtBy(jar)
|
||||
jarArtifact.type = ArtifactTypeDefinition.JAR_TYPE
|
||||
|
||||
addJar(apiElementsConfiguration, jarArtifact)
|
||||
|
||||
if (mainCompilation is KotlinCompilationToRunnableFiles) {
|
||||
val runtimeConfiguration = project.configurations.getByName(mainCompilation.deprecatedRuntimeConfigurationName)
|
||||
val runtimeElementsConfiguration = project.configurations.getByName(target.runtimeElementsConfigurationName)
|
||||
addJar(runtimeConfiguration, jarArtifact)
|
||||
addJar(runtimeElementsConfiguration, jarArtifact)
|
||||
// TODO Check Gradle's special split into variants for classes & resources -- do we need that too?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addJar(configuration: Configuration, jarArtifact: PublishArtifact) {
|
||||
val publications = configuration.outgoing
|
||||
|
||||
// Configure an implicit variant
|
||||
publications.artifacts.add(jarArtifact)
|
||||
publications.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, ArtifactTypeDefinition.JAR_TYPE)
|
||||
}
|
||||
|
||||
private fun configureResourceProcessing(
|
||||
project: Project,
|
||||
compilation: KotlinCompilationWithResources,
|
||||
resourceSet: FileCollection
|
||||
) {
|
||||
compilation.output.setResourcesDir(Callable {
|
||||
val classesDirName = "resources/" + compilation.compilationName
|
||||
File(project.buildDir, classesDirName)
|
||||
})
|
||||
|
||||
val resourcesTask = project.tasks.maybeCreate(compilation.processResourcesTaskName, ProcessResources::class.java)
|
||||
resourcesTask.description = "Processes $resourceSet."
|
||||
DslObject(resourcesTask).conventionMapping.map("destinationDir") { compilation.output.resourcesDir }
|
||||
resourcesTask.from(resourceSet)
|
||||
}
|
||||
|
||||
private fun createLifecycleTask(compilation: KotlinCompilation, project: Project) {
|
||||
(compilation.output.classesDirs as ConfigurableFileCollection).from(project.files().builtBy(compilation.compileAllTaskName))
|
||||
|
||||
project.tasks.create(compilation.compileAllTaskName).apply {
|
||||
group = LifecycleBasePlugin.BUILD_GROUP
|
||||
description = "Assembles " + compilation.output + ""
|
||||
dependsOn(
|
||||
compilation.output.dirs,
|
||||
compilation.compileKotlinTaskName
|
||||
)
|
||||
if (compilation is KotlinCompilationWithResources) {
|
||||
dependsOn(compilation.processResourcesTaskName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun defineConfigurationsForTarget(project: Project, target: KotlinOnlyTarget<*>) {
|
||||
val configurations = project.configurations
|
||||
|
||||
val defaultConfiguration = configurations.maybeCreate(target.defaultConfigurationName)
|
||||
val mainCompilation = target.compilations.maybeCreate(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
val testCompilation = target.compilations.maybeCreate(KotlinCompilation.TEST_COMPILATION_NAME)
|
||||
|
||||
val compileConfiguration = configurations.maybeCreate(mainCompilation.deprecatedCompileConfigurationName)
|
||||
val implementationConfiguration = configurations.maybeCreate(mainCompilation.implementationConfigurationName)
|
||||
|
||||
val runtimeOnlyConfiguration = configurations.maybeCreate(mainCompilation.runtimeOnlyConfigurationName)
|
||||
val compileTestsConfiguration = configurations.maybeCreate(testCompilation.deprecatedCompileConfigurationName)
|
||||
val testImplementationConfiguration = configurations.maybeCreate(testCompilation.implementationConfigurationName)
|
||||
val testRuntimeOnlyConfiguration = configurations.maybeCreate(testCompilation.runtimeOnlyConfigurationName)
|
||||
|
||||
compileTestsConfiguration.extendsFrom(compileConfiguration).usesPlatformOf(target)
|
||||
testImplementationConfiguration.extendsFrom(implementationConfiguration).usesPlatformOf(target)
|
||||
testRuntimeOnlyConfiguration.extendsFrom(runtimeOnlyConfiguration).usesPlatformOf(target)
|
||||
|
||||
configurations.maybeCreate(target.apiElementsConfigurationName).apply {
|
||||
description = "API elements for main."
|
||||
isVisible = false
|
||||
isCanBeResolved = false
|
||||
isCanBeConsumed = true
|
||||
attributes.attribute<Usage>(USAGE_ATTRIBUTE, project.usageByName(Usage.JAVA_API))
|
||||
extendsFrom(configurations.maybeCreate(mainCompilation.apiConfigurationName))
|
||||
if (mainCompilation is KotlinCompilationToRunnableFiles) {
|
||||
val runtimeConfiguration = configurations.maybeCreate(mainCompilation.deprecatedRuntimeConfigurationName)
|
||||
extendsFrom(runtimeConfiguration)
|
||||
}
|
||||
usesPlatformOf(target)
|
||||
}
|
||||
|
||||
val runtimeElementsConfiguration = configurations.maybeCreate(target.runtimeElementsConfigurationName).apply {
|
||||
description = "Elements of runtime for main."
|
||||
isVisible = false
|
||||
isCanBeConsumed = true
|
||||
isCanBeResolved = false
|
||||
attributes.attribute<Usage>(USAGE_ATTRIBUTE, project.usageByName(Usage.JAVA_RUNTIME_JARS))
|
||||
if (mainCompilation is KotlinCompilationToRunnableFiles) {
|
||||
val runtimeConfiguration = configurations.maybeCreate(mainCompilation.deprecatedRuntimeConfigurationName)
|
||||
extendsFrom(implementationConfiguration, runtimeOnlyConfiguration, runtimeConfiguration)
|
||||
}
|
||||
usesPlatformOf(target)
|
||||
}
|
||||
|
||||
if (mainCompilation is KotlinCompilationToRunnableFiles && testCompilation is KotlinCompilationToRunnableFiles) {
|
||||
val runtimeConfiguration = configurations.maybeCreate(mainCompilation.deprecatedRuntimeConfigurationName)
|
||||
val testRuntimeConfiguration = configurations.maybeCreate(testCompilation.deprecatedRuntimeConfigurationName)
|
||||
testRuntimeConfiguration.extendsFrom(runtimeConfiguration).usesPlatformOf(target)
|
||||
}
|
||||
|
||||
defaultConfiguration.extendsFrom(runtimeElementsConfiguration).usesPlatformOf(target)
|
||||
}
|
||||
|
||||
private fun configureBuild(project: Project, target: KotlinOnlyTarget<*>) {
|
||||
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
|
||||
project.tasks.maybeCreate(buildNeededTaskName, DefaultTask::class.java).apply {
|
||||
description = "Assembles and tests this project and all projects it depends on."
|
||||
group = "build"
|
||||
dependsOn("build")
|
||||
if (testCompilation is KotlinCompilationToRunnableFiles) {
|
||||
addDependsOnTaskInOtherProjects(this@apply, true, name, testCompilation.deprecatedRuntimeConfigurationName)
|
||||
}
|
||||
}
|
||||
|
||||
project.tasks.maybeCreate(buildDependentTaskName, DefaultTask::class.java).apply {
|
||||
setDescription("Assembles and tests this project and all projects that depend on it.")
|
||||
setGroup("build")
|
||||
dependsOn("build")
|
||||
doFirst {
|
||||
if (!project.gradle.includedBuilds.isEmpty()) {
|
||||
project.logger.warn("[composite-build] Warning: `" + path + "` task does not build included builds.")
|
||||
}
|
||||
}
|
||||
if (testCompilation is KotlinCompilationToRunnableFiles) {
|
||||
addDependsOnTaskInOtherProjects(this@apply, false, name, testCompilation.deprecatedRuntimeConfigurationName)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addDependsOnTaskInOtherProjects(
|
||||
task: Task, useDependedOn: Boolean, otherProjectTaskName: String,
|
||||
configurationName: String
|
||||
) {
|
||||
val project = task.project
|
||||
val configuration = project.configurations.getByName(configurationName)
|
||||
task.dependsOn(configuration.getTaskDependencyFromProjectDependency(useDependedOn, otherProjectTaskName))
|
||||
}
|
||||
|
||||
private fun setCompatibilityOfAbstractCompileTasks(project: Project) = with (project) {
|
||||
tasks.withType(AbstractKotlinCompile::class.java).all {
|
||||
// Workaround: these are input properties and should not hold null values:
|
||||
it.targetCompatibility = ""
|
||||
it.sourceCompatibility = ""
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val buildNeededTaskName = "buildAllNeeded"
|
||||
const val buildDependentTaskName = "buildAllDependents"
|
||||
|
||||
fun defineConfigurationsForCompilation(
|
||||
compilation: KotlinCompilation,
|
||||
target: KotlinTarget,
|
||||
configurations: ConfigurationContainer
|
||||
) {
|
||||
val compileConfiguration = configurations.maybeCreate(compilation.deprecatedCompileConfigurationName).apply {
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = false
|
||||
description = "Dependencies for $compilation (deprecated, use '${compilation.implementationConfigurationName} ' instead)."
|
||||
}
|
||||
|
||||
val apiConfiguration = configurations.maybeCreate(compilation.apiConfigurationName).apply {
|
||||
extendsFrom(compileConfiguration)
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = false
|
||||
description = "API dependencies for $compilation."
|
||||
}
|
||||
|
||||
val implementationConfiguration = configurations.maybeCreate(compilation.implementationConfigurationName).apply {
|
||||
extendsFrom(compileConfiguration, apiConfiguration)
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = false
|
||||
description = "Implementation only dependencies for $compilation."
|
||||
}
|
||||
|
||||
val compileOnlyConfiguration = configurations.maybeCreate(compilation.compileOnlyConfigurationName).apply {
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = false
|
||||
description = "Compile only dependencies for $compilation."
|
||||
}
|
||||
|
||||
val compileClasspathConfiguration = configurations.maybeCreate(compilation.compileDependencyConfigurationName).apply {
|
||||
extendsFrom(compileOnlyConfiguration, implementationConfiguration)
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
attributes.attribute(USAGE_ATTRIBUTE, compilation.target.project.usageByName(Usage.JAVA_API))
|
||||
description = "Compile classpath for $compilation."
|
||||
}
|
||||
|
||||
compilation.compileDependencyFiles = compileClasspathConfiguration
|
||||
|
||||
if (compilation is KotlinCompilationToRunnableFiles) {
|
||||
val runtimeConfiguration = configurations.maybeCreate(compilation.deprecatedRuntimeConfigurationName).apply {
|
||||
extendsFrom(compileConfiguration)
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = false
|
||||
description =
|
||||
"Runtime dependencies for $compilation (deprecated, use '${compilation.runtimeOnlyConfigurationName} ' instead)."
|
||||
}
|
||||
|
||||
val runtimeOnlyConfiguration = configurations.maybeCreate(compilation.runtimeOnlyConfigurationName).apply {
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = false
|
||||
description = "Runtime only dependencies for $compilation."
|
||||
}
|
||||
|
||||
val runtimeClasspathConfiguration = configurations.maybeCreate(compilation.runtimeDependencyConfigurationName).apply {
|
||||
extendsFrom(runtimeOnlyConfiguration, runtimeConfiguration, implementationConfiguration)
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
attributes.attribute(USAGE_ATTRIBUTE, compilation.target.project.usageByName(Usage.JAVA_RUNTIME))
|
||||
description = "Runtime classpath of $compilation."
|
||||
}
|
||||
|
||||
compilation.runtimeDependencyFiles = compilation.output.plus(runtimeClasspathConfiguration)
|
||||
}
|
||||
}
|
||||
|
||||
private val KotlinCompilation.deprecatedCompileConfigurationName: String
|
||||
get() = disambiguateName("compile")
|
||||
|
||||
private val KotlinCompilationToRunnableFiles.deprecatedRuntimeConfigurationName: String
|
||||
get() = disambiguateName("runtime")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Project.usageByName(usageName: String): Usage =
|
||||
if (isGradleVersionAtLeast(4, 0)) {
|
||||
// `project.objects` is an API introduced in Gradle 4.0
|
||||
project.objects.named(Usage::class.java, usageName)
|
||||
} else {
|
||||
val usagesClass = Class.forName("org.gradle.api.internal.attributes.Usages")
|
||||
val usagesMethod = usagesClass.getMethod("usage", String::class.java)
|
||||
usagesMethod(null, usageName) as Usage
|
||||
}
|
||||
|
||||
fun Configuration.usesPlatformOf(target: KotlinTarget): Configuration {
|
||||
attributes.attribute(KotlinPlatformType.attribute, target.platformType)
|
||||
return this
|
||||
}
|
||||
+160
@@ -0,0 +1,160 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.NamedDomainObjectCollection
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.attributes.Attribute
|
||||
import org.gradle.api.attributes.AttributeContainer
|
||||
import org.gradle.api.internal.file.FileResolver
|
||||
import org.gradle.api.internal.plugins.DslObject
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.plugins.ReportingBasePlugin
|
||||
import org.gradle.api.publish.PublishingExtension
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal
|
||||
import org.gradle.internal.cleanup.BuildOutputCleanupRegistry
|
||||
import org.gradle.internal.reflect.Instantiator
|
||||
import org.gradle.util.ConfigureUtil
|
||||
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.plugin.source.KotlinSourceSet
|
||||
|
||||
internal val Project.multiplatformExtension get(): KotlinMultiplatformExtension? =
|
||||
project.extensions.getByName("kotlin") as KotlinMultiplatformExtension
|
||||
|
||||
internal class KotlinMultiplatformPlugin(
|
||||
private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry,
|
||||
private val fileResolver: FileResolver,
|
||||
private val instantiator: Instantiator,
|
||||
private val kotlinPluginVersion: String
|
||||
) : Plugin<Project> {
|
||||
|
||||
private class TargetFromPresetExtension(val targetsContainer: NamedDomainObjectCollection<KotlinTarget>) {
|
||||
fun <T : KotlinTarget> fromPreset(preset: KotlinTargetPreset<T>, name: String, configureClosure: Closure<*>): T =
|
||||
fromPreset(preset, name, { ConfigureUtil.configure(configureClosure, this) })
|
||||
|
||||
@JvmOverloads
|
||||
fun <T : KotlinTarget> fromPreset(preset: KotlinTargetPreset<T>, name: String, configureAction: T.() -> Unit = { }): T {
|
||||
val target = preset.createTarget(name)
|
||||
targetsContainer.add(target)
|
||||
target.run(configureAction)
|
||||
return target
|
||||
}
|
||||
}
|
||||
|
||||
override fun apply(project: Project) {
|
||||
project.plugins.apply(BasePlugin::class.java)
|
||||
project.plugins.apply(ReportingBasePlugin::class.java)
|
||||
|
||||
val targetsContainer = project.container(KotlinTarget::class.java)
|
||||
val targetsFromPreset = TargetFromPresetExtension(targetsContainer)
|
||||
|
||||
project.extensions.getByType(KotlinMultiplatformExtension::class.java).apply {
|
||||
DslObject(targetsContainer).addConvention("fromPreset", targetsFromPreset)
|
||||
|
||||
targets = targetsContainer
|
||||
addExtension("targets", targets)
|
||||
|
||||
presets = project.container(KotlinTargetPreset::class.java)
|
||||
addExtension("presets", presets)
|
||||
}
|
||||
|
||||
setupDefaultPresets(project)
|
||||
configureDefaultVersionsResolutionStrategy(project, kotlinPluginVersion)
|
||||
configureSourceSets(project)
|
||||
|
||||
setUpConfigurationAttributes(project)
|
||||
configurePublishingWithMavenPublish(project)
|
||||
}
|
||||
|
||||
fun setupDefaultPresets(project: Project) {
|
||||
with((project.kotlinExtension as KotlinMultiplatformExtension).presets) {
|
||||
add(KotlinUniversalTargetPreset(project, instantiator, fileResolver, buildOutputCleanupRegistry, kotlinPluginVersion))
|
||||
add(KotlinJvmTargetPreset(project, instantiator, fileResolver, buildOutputCleanupRegistry, kotlinPluginVersion))
|
||||
add(KotlinJsTargetPreset(project, instantiator, fileResolver, buildOutputCleanupRegistry, kotlinPluginVersion))
|
||||
add(KotlinAndroidTargetPreset(project, kotlinPluginVersion))
|
||||
add(KotlinJvmWithJavaTargetPreset(project, kotlinPluginVersion))
|
||||
}
|
||||
}
|
||||
|
||||
private fun configurePublishingWithMavenPublish(project: Project) = project.pluginManager.withPlugin("maven-publish") {
|
||||
val targets = project.multiplatformExtension!!.targets
|
||||
val kotlinSoftwareComponent = KotlinSoftwareComponent(project, "kotlin", targets)
|
||||
|
||||
project.afterEvaluate { project -> // Use afterEvaluate because publications configuration is no more lazy since Gradle 4.9
|
||||
project.extensions.configure(PublishingExtension::class.java) { publishing ->
|
||||
publishing.publications.create("kotlin", MavenPublication::class.java) { publication ->
|
||||
publication.from(kotlinSoftwareComponent)
|
||||
(publication as MavenPublicationInternal).publishWithOriginalFileName()
|
||||
publication.artifactId = project.name
|
||||
publication.groupId = project.group.toString()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
project.components.add(kotlinSoftwareComponent)
|
||||
}
|
||||
|
||||
private fun configureSourceSets(project: Project) = with (project.kotlinExtension as KotlinMultiplatformExtension) {
|
||||
sourceSets.all { defineSourceSetConfigurations(project, it) }
|
||||
val production = sourceSets.create(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
|
||||
val test = sourceSets.create(KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME)
|
||||
|
||||
targets.all {
|
||||
it.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)?.source(production)
|
||||
it.compilations.findByName(KotlinCompilation.TEST_COMPILATION_NAME)?.source(test)
|
||||
}
|
||||
}
|
||||
|
||||
private fun setUpConfigurationAttributes(project: Project) {
|
||||
val targets = (project.kotlinExtension as KotlinMultiplatformExtension).targets
|
||||
|
||||
project.afterEvaluate {
|
||||
targets.all { target ->
|
||||
val mainCompilationAttributes = target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)?.attributes
|
||||
?: return@all
|
||||
|
||||
fun <T> copyAttribute(key: Attribute<T>, from: AttributeContainer, to: AttributeContainer) {
|
||||
to.attribute(key, from.getAttribute(key)!!)
|
||||
}
|
||||
|
||||
listOf(
|
||||
target.apiElementsConfigurationName,
|
||||
target.runtimeElementsConfigurationName,
|
||||
target.defaultConfigurationName
|
||||
)
|
||||
.mapNotNull { configurationName -> target.project.configurations.findByName(configurationName) }
|
||||
.forEach { configuration ->
|
||||
mainCompilationAttributes.keySet().forEach { key ->
|
||||
copyAttribute(key, mainCompilationAttributes, configuration.attributes)
|
||||
}
|
||||
}
|
||||
|
||||
target.compilations.all { compilation ->
|
||||
val compilationAttributes = compilation.attributes
|
||||
|
||||
compilation.relatedConfigurationNames
|
||||
.mapNotNull { configurationName -> target.project.configurations.findByName(configurationName) }
|
||||
.forEach { configuration ->
|
||||
compilationAttributes.keySet().forEach { key ->
|
||||
copyAttribute(key, compilationAttributes, configuration.attributes)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun defineSourceSetConfigurations(project: Project, sourceSet: KotlinSourceSet) = with (project.configurations) {
|
||||
sourceSet.relatedConfigurationNames.forEach { configurationName ->
|
||||
maybeCreate(configurationName)
|
||||
}
|
||||
}
|
||||
}
|
||||
+70
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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 org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.DependencyConstraint
|
||||
import org.gradle.api.artifacts.ModuleDependency
|
||||
import org.gradle.api.artifacts.PublishArtifact
|
||||
import org.gradle.api.attributes.AttributeContainer
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.capabilities.Capability
|
||||
import org.gradle.api.internal.component.SoftwareComponentInternal
|
||||
import org.gradle.api.internal.component.UsageContext
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.usageByName
|
||||
|
||||
class KotlinSoftwareComponent(
|
||||
private val project: Project,
|
||||
private val name: String,
|
||||
private val kotlinTargets: Iterable<KotlinTarget>
|
||||
) : SoftwareComponentInternal {
|
||||
override fun getUsages(): Set<UsageContext> = kotlinTargets.flatMap { it.createUsageContexts() }.toSet()
|
||||
|
||||
override fun getName(): String = name
|
||||
|
||||
companion object {
|
||||
fun kotlinApiUsage(project: Project) = project.usageByName(Usage.JAVA_API)
|
||||
fun kotlinRuntimeUsage(project: Project) = project.usageByName(Usage.JAVA_RUNTIME)
|
||||
}
|
||||
}
|
||||
|
||||
internal class KotlinPlatformUsageContext(
|
||||
val project: Project,
|
||||
val kotlinTarget: KotlinTarget,
|
||||
private val usage: Usage,
|
||||
val dependencyConfigurationName: String
|
||||
) : UsageContext {
|
||||
override fun getUsage(): Usage = usage
|
||||
|
||||
override fun getName(): String = kotlinTarget.targetName + when (usage.name) {
|
||||
Usage.JAVA_API -> "-api"
|
||||
Usage.JAVA_RUNTIME -> "-runtime"
|
||||
else -> error("unexpected usage")
|
||||
}
|
||||
|
||||
private val configuration: Configuration
|
||||
get() = project.configurations.getByName(dependencyConfigurationName)
|
||||
|
||||
override fun getDependencies(): MutableSet<out ModuleDependency> =
|
||||
configuration.incoming.dependencies.withType(ModuleDependency::class.java)
|
||||
|
||||
override fun getDependencyConstraints(): MutableSet<out DependencyConstraint> =
|
||||
configuration.incoming.dependencyConstraints
|
||||
|
||||
override fun getArtifacts(): MutableSet<out PublishArtifact> =
|
||||
// TODO Gradle Java plugin does that in a different way; check whether we can improve this
|
||||
configuration.artifacts
|
||||
|
||||
override fun getAttributes(): AttributeContainer =
|
||||
configuration.outgoing.attributes
|
||||
|
||||
override fun getCapabilities(): Set<Capability> = emptySet()
|
||||
|
||||
// FIXME this is a stub for a function that is not present in the Gradle API that we compile against
|
||||
fun getGlobalExcludes(): Set<Any> = emptySet()
|
||||
}
|
||||
+206
@@ -0,0 +1,206 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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 org.gradle.api.Project
|
||||
import org.gradle.api.internal.file.FileResolver
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.internal.cleanup.BuildOutputCleanupRegistry
|
||||
import org.gradle.internal.reflect.Instantiator
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.AndroidTasksProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsTasksProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCommonTasksProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
||||
|
||||
abstract class KotlinOnlyTargetPreset<T : KotlinCompilation>(
|
||||
protected val project: Project,
|
||||
private val instantiator: Instantiator,
|
||||
private val fileResolver: FileResolver,
|
||||
private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry,
|
||||
protected val kotlinPluginVersion: String
|
||||
) : KotlinTargetPreset<KotlinOnlyTarget<T>> {
|
||||
|
||||
override fun createTarget(name: String): KotlinOnlyTarget<T> {
|
||||
val result = KotlinOnlyTarget<T>(project, platformType).apply {
|
||||
targetName = name
|
||||
disambiguationClassifier = name
|
||||
|
||||
val compilationFactory = createCompilationFactory(this)
|
||||
compilations = project.container(compilationFactory.itemClass, compilationFactory)
|
||||
}
|
||||
|
||||
KotlinTargetConfigurator(buildOutputCleanupRegistry).configureTarget(project, result)
|
||||
|
||||
result.compilations.all { compilation ->
|
||||
buildCompilationProcessor(compilation).run()
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
protected abstract fun createCompilationFactory(forTarget: KotlinOnlyTarget<T>): KotlinCompilationFactory<T>
|
||||
protected abstract val platformType: KotlinPlatformType
|
||||
internal abstract fun buildCompilationProcessor(compilation: T): KotlinSourceSetProcessor<*>
|
||||
}
|
||||
|
||||
class KotlinUniversalTargetPreset(
|
||||
project: Project,
|
||||
instantiator: Instantiator,
|
||||
fileResolver: FileResolver,
|
||||
buildOutputCleanupRegistry: BuildOutputCleanupRegistry,
|
||||
kotlinPluginVersion: String
|
||||
) : KotlinOnlyTargetPreset<KotlinCommonCompilation>(
|
||||
project,
|
||||
instantiator,
|
||||
fileResolver,
|
||||
buildOutputCleanupRegistry,
|
||||
kotlinPluginVersion
|
||||
) {
|
||||
override fun getName(): String = PRESET_NAME
|
||||
|
||||
override fun createCompilationFactory(
|
||||
forTarget: KotlinOnlyTarget<KotlinCommonCompilation>
|
||||
): KotlinCompilationFactory<KotlinCommonCompilation> =
|
||||
KotlinCommonCompilationFactory(forTarget)
|
||||
|
||||
override val platformType: KotlinPlatformType
|
||||
get() = KotlinPlatformType.common
|
||||
|
||||
override fun buildCompilationProcessor(compilation: KotlinCommonCompilation): KotlinSourceSetProcessor<*> =
|
||||
KotlinCommonSourceSetProcessor(
|
||||
project,
|
||||
compilation,
|
||||
KotlinCommonTasksProvider(),
|
||||
kotlinPluginVersion
|
||||
)
|
||||
|
||||
companion object {
|
||||
const val PRESET_NAME = "universal"
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinJvmTargetPreset(
|
||||
project: Project,
|
||||
instantiator: Instantiator,
|
||||
fileResolver: FileResolver,
|
||||
buildOutputCleanupRegistry: BuildOutputCleanupRegistry,
|
||||
kotlinPluginVersion: String
|
||||
) : KotlinOnlyTargetPreset<KotlinJvmCompilation>(
|
||||
project,
|
||||
instantiator,
|
||||
fileResolver,
|
||||
buildOutputCleanupRegistry,
|
||||
kotlinPluginVersion
|
||||
) {
|
||||
override fun getName(): String = PRESET_NAME
|
||||
|
||||
override fun createCompilationFactory(forTarget: KotlinOnlyTarget<KotlinJvmCompilation>): KotlinCompilationFactory<KotlinJvmCompilation> =
|
||||
KotlinJvmCompilationFactory(forTarget)
|
||||
|
||||
override val platformType: KotlinPlatformType
|
||||
get() = KotlinPlatformType.jvm
|
||||
|
||||
override fun buildCompilationProcessor(compilation: KotlinJvmCompilation): KotlinSourceSetProcessor<*> =
|
||||
Kotlin2JvmSourceSetProcessor(project, KotlinTasksProvider(), compilation, kotlinPluginVersion)
|
||||
|
||||
companion object {
|
||||
const val PRESET_NAME = "jvm"
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinJsTargetPreset(
|
||||
project: Project,
|
||||
instantiator: Instantiator,
|
||||
fileResolver: FileResolver,
|
||||
buildOutputCleanupRegistry: BuildOutputCleanupRegistry,
|
||||
kotlinPluginVersion: String
|
||||
) : KotlinOnlyTargetPreset<KotlinJsCompilation>(
|
||||
project,
|
||||
instantiator,
|
||||
fileResolver,
|
||||
buildOutputCleanupRegistry,
|
||||
kotlinPluginVersion
|
||||
) {
|
||||
override fun getName(): String = PRESET_NAME
|
||||
|
||||
override fun createCompilationFactory(forTarget: KotlinOnlyTarget<KotlinJsCompilation>) =
|
||||
KotlinJsCompilationFactory(project, forTarget)
|
||||
|
||||
override val platformType: KotlinPlatformType
|
||||
get() = KotlinPlatformType.js
|
||||
|
||||
override fun buildCompilationProcessor(compilation: KotlinJsCompilation): KotlinSourceSetProcessor<*> =
|
||||
Kotlin2JsSourceSetProcessor(project, Kotlin2JsTasksProvider(), compilation, kotlinPluginVersion)
|
||||
|
||||
companion object {
|
||||
const val PRESET_NAME = "js"
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinAndroidTargetPreset(
|
||||
private val project: Project,
|
||||
private val kotlinPluginVersion: String
|
||||
) : KotlinTargetPreset<KotlinAndroidTarget> {
|
||||
|
||||
override fun getName(): String = PRESET_NAME
|
||||
|
||||
override fun createTarget(name: String): KotlinAndroidTarget {
|
||||
val result = KotlinAndroidTarget(name, project).apply {
|
||||
disambiguationClassifier = name
|
||||
}
|
||||
|
||||
KotlinAndroidPlugin.applyToTarget(
|
||||
project, result, AndroidTasksProvider(),
|
||||
kotlinPluginVersion
|
||||
)
|
||||
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PRESET_NAME = "android"
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinJvmWithJavaTargetPreset(
|
||||
private val project: Project,
|
||||
private val kotlinPluginVersion: String
|
||||
): KotlinTargetPreset<KotlinWithJavaTarget> {
|
||||
|
||||
override fun getName(): String = PRESET_NAME
|
||||
|
||||
override fun createTarget(name: String): KotlinWithJavaTarget {
|
||||
project.plugins.apply(JavaPlugin::class.java)
|
||||
|
||||
val target = KotlinWithJavaTarget(project, KotlinPlatformType.jvm, name).apply {
|
||||
disambiguationClassifier = name
|
||||
}
|
||||
|
||||
AbstractKotlinPlugin.configureTarget(target) { compilation ->
|
||||
Kotlin2JvmSourceSetProcessor(project, KotlinTasksProvider(), compilation, kotlinPluginVersion)
|
||||
}
|
||||
|
||||
target.compilations.all { compilation ->
|
||||
// Set up dependency resolution using platforms:
|
||||
KotlinTargetConfigurator.defineConfigurationsForCompilation(compilation, target, project.configurations)
|
||||
}
|
||||
|
||||
target.compilations.getByName("test").run {
|
||||
val main = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
|
||||
compileDependencyFiles = project.files(main.output, project.configurations.maybeCreate(compileDependencyConfigurationName))
|
||||
runtimeDependencyFiles = project.files(output, main.output, project.configurations.maybeCreate(runtimeDependencyConfigurationName))
|
||||
}
|
||||
|
||||
return target
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val PRESET_NAME = "jvmWithJava"
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -272,7 +272,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
||||
args.verbose = true
|
||||
}
|
||||
|
||||
args.multiPlatform = project.plugins.any { it is KotlinPlatformPluginBase }
|
||||
args.multiPlatform = project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper }
|
||||
|
||||
setupPlugins(args)
|
||||
}
|
||||
|
||||
+1
@@ -0,0 +1 @@
|
||||
implementation-class=org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
|
||||
+1
@@ -0,0 +1 @@
|
||||
implementation-class=org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
|
||||
Reference in New Issue
Block a user