diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
deleted file mode 100644
index 78f1346b901..00000000000
--- a/.idea/inspectionProfiles/profiles_settings.xml
+++ /dev/null
@@ -1,7 +0,0 @@
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinNativeTaretConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinNativeTaretConfigurator.kt
new file mode 100644
index 00000000000..eb37b6e9abb
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinNativeTaretConfigurator.kt
@@ -0,0 +1,788 @@
+/*
+ * 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.Project
+import org.gradle.api.Task
+import org.gradle.api.artifacts.*
+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.FileCollection
+import org.gradle.api.internal.artifacts.ArtifactAttributes
+import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact
+import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
+import org.gradle.api.internal.plugins.DslObject
+import org.gradle.api.plugins.BasePlugin
+import org.gradle.api.plugins.JavaBasePlugin
+import org.gradle.api.tasks.Copy
+import org.gradle.api.tasks.Delete
+import org.gradle.api.tasks.Exec
+import org.gradle.api.tasks.bundling.Jar
+import org.gradle.api.tasks.testing.Test
+import org.gradle.language.base.plugins.LifecycleBasePlugin
+import org.gradle.language.jvm.tasks.ProcessResources
+import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
+import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
+import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
+import org.jetbrains.kotlin.gradle.plugin.mpp.*
+import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile
+import org.jetbrains.kotlin.gradle.tasks.CInteropProcess
+import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
+import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+import java.io.File
+import java.util.*
+import java.util.concurrent.Callable
+
+abstract class AbstractKotlinTargetConfigurator(
+ protected val createDefaultSourceSets: Boolean,
+ protected val createTestCompilation: Boolean
+) {
+ open fun configureTarget(
+ target: KotlinTargetType
+ ) {
+ configureCompilationDefaults(target)
+ configureCompilations(target)
+ defineConfigurationsForTarget(target)
+ configureArchivesAndComponent(target)
+ configureTest(target)
+ configureBuild(target)
+ }
+
+
+ abstract protected fun configureArchivesAndComponent(target: KotlinTargetType)
+ abstract protected fun configureTest(target: KotlinTargetType)
+
+ private fun Project.registerOutputsForStaleOutputCleanup(kotlinCompilation: KotlinCompilation<*>) {
+ val cleanTask = tasks.getByName(LifecycleBasePlugin.CLEAN_TASK_NAME) as Delete
+ cleanTask.delete(kotlinCompilation.output.allOutputs)
+ }
+
+ protected fun configureCompilations(platformTarget: KotlinTargetType) {
+ val project = platformTarget.project
+ val main = platformTarget.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME)
+
+ platformTarget.compilations.all {
+ project.registerOutputsForStaleOutputCleanup(it)
+ it.compileDependencyFiles = project.configurations.maybeCreate(it.compileDependencyConfigurationName)
+ if (it is KotlinCompilationToRunnableFiles) {
+ it.runtimeDependencyFiles = project.configurations.maybeCreate(it.runtimeDependencyConfigurationName)
+ }
+ }
+
+ if (createTestCompilation) {
+ platformTarget.compilations.create(KotlinCompilation.TEST_COMPILATION_NAME).apply {
+ compileDependencyFiles = project.files(
+ main.output.allOutputs,
+ project.configurations.maybeCreate(compileDependencyConfigurationName)
+ )
+
+ if (this is KotlinCompilationToRunnableFiles) {
+ runtimeDependencyFiles = project.files(
+ output.allOutputs,
+ main.output.allOutputs,
+ project.configurations.maybeCreate(runtimeDependencyConfigurationName)
+ )
+ }
+ }
+ }
+ }
+
+ protected fun configureCompilationDefaults(target: KotlinTargetType) {
+ val project = target.project
+
+ target.compilations.all { compilation ->
+ defineConfigurationsForCompilation(compilation)
+
+ if (createDefaultSourceSets) {
+ project.kotlinExtension.sourceSets.maybeCreate(compilation.defaultSourceSetName).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(compilation, project.files(Callable { compilation.allKotlinSourceSets.map { it.resources } }))
+ }
+
+ createLifecycleTask(compilation)
+ }
+ }
+
+ protected fun configureResourceProcessing(
+ compilation: KotlinCompilationWithResources<*>,
+ resourceSet: FileCollection
+ ) {
+ val project = compilation.target.project
+
+ val resourcesTask = project.tasks.maybeCreate(compilation.processResourcesTaskName, ProcessResources::class.java)
+ resourcesTask.description = "Processes $resourceSet."
+ DslObject(resourcesTask).conventionMapping.map("destinationDir") { project.file(compilation.output.resourcesDir) }
+ resourcesTask.from(resourceSet)
+ }
+
+ protected fun createLifecycleTask(compilation: KotlinCompilation<*>) {
+ val project = compilation.target.project
+
+ compilation.output.classesDirs.from(project.files().builtBy(compilation.compileAllTaskName))
+
+ project.tasks.create(compilation.compileAllTaskName).apply {
+ group = LifecycleBasePlugin.BUILD_GROUP
+ description = "Assembles outputs for compilation '${compilation.name}' of target '${compilation.target.name}'"
+ dependsOn(compilation.compileKotlinTaskName)
+ if (compilation is KotlinCompilationWithResources) {
+ dependsOn(compilation.processResourcesTaskName)
+ }
+ }
+ }
+
+ protected open fun defineConfigurationsForTarget(target: KotlinTargetType) {
+ val project = target.project
+
+ val configurations = project.configurations
+
+ val defaultConfiguration = configurations.maybeCreate(target.defaultConfigurationName).apply {
+ setupAsLocalTargetSpecificConfigurationIfSupported(target)
+ }
+
+ val mainCompilation = target.compilations.maybeCreate(KotlinCompilation.MAIN_COMPILATION_NAME)
+
+ val compileConfiguration = configurations.maybeCreate(mainCompilation.deprecatedCompileConfigurationName)
+ val implementationConfiguration = configurations.maybeCreate(mainCompilation.implementationConfigurationName)
+
+ val runtimeOnlyConfiguration = configurations.maybeCreate(mainCompilation.runtimeOnlyConfigurationName)
+
+ val apiElementsConfiguration = configurations.maybeCreate(target.apiElementsConfigurationName).apply {
+ description = "API elements for main."
+ isVisible = false
+ isCanBeResolved = false
+ isCanBeConsumed = true
+ attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
+ extendsFrom(configurations.maybeCreate(mainCompilation.apiConfigurationName))
+ if (mainCompilation is KotlinCompilationToRunnableFiles) {
+ val runtimeConfiguration = configurations.maybeCreate(mainCompilation.deprecatedRuntimeConfigurationName)
+ extendsFrom(runtimeConfiguration)
+ }
+ usesPlatformOf(target)
+ setupAsPublicConfigurationIfSupported(target)
+ }
+
+ if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
+ val runtimeElementsConfiguration = configurations.maybeCreate(target.runtimeElementsConfigurationName).apply {
+ description = "Elements of runtime for main."
+ isVisible = false
+ isCanBeConsumed = true
+ isCanBeResolved = false
+ attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target))
+ val runtimeConfiguration = configurations.maybeCreate(mainCompilation.deprecatedRuntimeConfigurationName)
+ extendsFrom(implementationConfiguration, runtimeOnlyConfiguration, runtimeConfiguration)
+ usesPlatformOf(target)
+ setupAsPublicConfigurationIfSupported(target)
+ }
+ defaultConfiguration.extendsFrom(runtimeElementsConfiguration)
+ } else {
+ defaultConfiguration.extendsFrom(apiElementsConfiguration)
+ }
+
+ if (createTestCompilation) {
+ val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
+ val compileTestsConfiguration = configurations.maybeCreate(testCompilation.deprecatedCompileConfigurationName)
+ val testImplementationConfiguration = configurations.maybeCreate(testCompilation.implementationConfigurationName)
+ val testRuntimeOnlyConfiguration = configurations.maybeCreate(testCompilation.runtimeOnlyConfigurationName)
+
+ compileTestsConfiguration.extendsFrom(compileConfiguration)
+ testImplementationConfiguration.extendsFrom(implementationConfiguration)
+ testRuntimeOnlyConfiguration.extendsFrom(runtimeOnlyConfiguration)
+
+ if (mainCompilation is KotlinCompilationToRunnableFiles && testCompilation is KotlinCompilationToRunnableFiles) {
+ val runtimeConfiguration = configurations.maybeCreate(mainCompilation.deprecatedRuntimeConfigurationName)
+ val testRuntimeConfiguration = configurations.maybeCreate(testCompilation.deprecatedRuntimeConfigurationName)
+ testRuntimeConfiguration.extendsFrom(runtimeConfiguration)
+ }
+ }
+ }
+
+ protected fun configureBuild(target: KotlinTargetType) {
+ val project = target.project
+
+ val buildNeeded = project.tasks.getByName(JavaBasePlugin.BUILD_NEEDED_TASK_NAME)
+ val buildDependent = project.tasks.getByName(JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME)
+
+ if (createTestCompilation) {
+ val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
+ if (testCompilation is KotlinCompilationToRunnableFiles) {
+ addDependsOnTaskInOtherProjects(buildNeeded, true, testCompilation.deprecatedRuntimeConfigurationName)
+ addDependsOnTaskInOtherProjects(buildDependent, false, testCompilation.deprecatedRuntimeConfigurationName)
+ }
+ }
+ }
+
+ private fun addDependsOnTaskInOtherProjects(task: Task, useDependedOn: Boolean, configurationName: String) {
+ val project = task.project
+ val configuration = project.configurations.getByName(configurationName)
+ task.dependsOn(configuration.getTaskDependencyFromProjectDependency(useDependedOn, task.name))
+ }
+
+ companion object {
+ const val testTaskNameSuffix = "test"
+
+ fun defineConfigurationsForCompilation(
+ compilation: KotlinCompilation<*>
+ ) {
+ val target = compilation.target
+ val configurations = target.project.configurations
+
+ val compileConfiguration = configurations.maybeCreate(compilation.deprecatedCompileConfigurationName).apply {
+ setupAsLocalTargetSpecificConfigurationIfSupported(target)
+ isVisible = false
+ isCanBeResolved = true // Needed for IDE import
+ description = "Dependencies for $compilation (deprecated, use '${compilation.implementationConfigurationName} ' instead)."
+ }
+
+ val apiConfiguration = configurations.maybeCreate(compilation.apiConfigurationName).apply {
+ extendsFrom(compileConfiguration)
+ isVisible = false
+ isCanBeConsumed = false
+ isCanBeResolved = false
+ description = "API dependencies for $compilation."
+ }
+
+ val implementationConfiguration = configurations.maybeCreate(compilation.implementationConfigurationName).apply {
+ extendsFrom(compileConfiguration, apiConfiguration)
+ isVisible = false
+ isCanBeConsumed = false
+ isCanBeResolved = false
+ description = "Implementation only dependencies for $compilation."
+ }
+
+ val compileOnlyConfiguration = configurations.maybeCreate(compilation.compileOnlyConfigurationName).apply {
+ setupAsLocalTargetSpecificConfigurationIfSupported(target)
+ isVisible = false
+ isCanBeResolved = true // Needed for IDE import
+ 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, KotlinUsages.consumerApiUsage(compilation.target))
+ description = "Compile classpath for $compilation."
+ }
+
+ if (compilation is KotlinCompilationToRunnableFiles) {
+ val runtimeConfiguration = configurations.maybeCreate(compilation.deprecatedRuntimeConfigurationName).apply {
+ setupAsLocalTargetSpecificConfigurationIfSupported(target)
+ extendsFrom(compileConfiguration)
+ isVisible = false
+ isCanBeResolved = true // Needed for IDE import
+ description =
+ "Runtime dependencies for $compilation (deprecated, use '${compilation.runtimeOnlyConfigurationName} ' instead)."
+ }
+
+ val runtimeOnlyConfiguration = configurations.maybeCreate(compilation.runtimeOnlyConfigurationName).apply {
+ 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, KotlinUsages.consumerRuntimeUsage(compilation.target))
+ description = "Runtime classpath of $compilation."
+ }
+ }
+ }
+ }
+}
+
+internal val KotlinCompilation<*>.deprecatedCompileConfigurationName: String
+ get() = disambiguateName("compile")
+
+internal val KotlinCompilationToRunnableFiles<*>.deprecatedRuntimeConfigurationName: String
+ get() = disambiguateName("runtime")
+
+open class KotlinTargetConfigurator>(
+ createDefaultSourceSets: Boolean,
+ createTestCompilation: Boolean
+) : AbstractKotlinTargetConfigurator>(
+ createDefaultSourceSets,
+ createTestCompilation
+) {
+
+ override fun configureArchivesAndComponent(target: KotlinOnlyTarget) {
+ val project = target.project
+
+ 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.allOutputs)
+
+ val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
+
+ target.disambiguationClassifier?.let { jar.appendix = it.toLowerCase() }
+
+ // 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?
+ }
+ }
+ }
+ }
+
+ override fun configureTest(target: KotlinOnlyTarget) {
+ val testCompilation = target.compilations.findByName(KotlinCompilation.TEST_COMPILATION_NAME) as? KotlinCompilationToRunnableFiles<*>
+ ?: return // Otherwise, there is no runtime classpath
+
+ target.project.tasks.create(lowerCamelCaseName(target.targetName, testTaskNameSuffix), Test::class.java).apply {
+ project.afterEvaluate {
+ // use afterEvaluate to override the JavaPlugin defaults for Test tasks
+ conventionMapping.map("testClassesDirs") { testCompilation.output.classesDirs }
+ conventionMapping.map("classpath") { testCompilation.runtimeDependencyFiles }
+ description = "Runs the unit tests."
+ group = JavaBasePlugin.VERIFICATION_GROUP
+ target.project.tasks.findByName(JavaBasePlugin.CHECK_TASK_NAME)?.dependsOn(this@apply)
+ }
+ }
+ }
+
+ 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)
+ }
+}
+
+
+open class KotlinNativeTargetConfigurator(
+ private val kotlinPluginVersion: String
+) : AbstractKotlinTargetConfigurator(
+ createDefaultSourceSets = true,
+ createTestCompilation = true
+) {
+ private fun Project.klibOutputDirectory(
+ compilation: KotlinNativeCompilation
+ ): File {
+ val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty()
+ return buildDir.resolve("classes/kotlin/$targetSubDirectory${compilation.name}")
+ }
+
+ private fun AbstractKotlinNativeCompile.addCompilerPlugins() {
+ SubpluginEnvironment
+ .loadSubplugins(project, kotlinPluginVersion)
+ .addSubpluginOptions(project, this, compilerPluginOptions)
+ compilerPluginClasspath = project.configurations.getByName(NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME)
+ }
+
+ // region Artifact creation.
+ private fun Project.createKlibArtifact(
+ compilation: KotlinNativeCompilation,
+ artifactFile: File,
+ classifier: String?,
+ producingTask: Task,
+ copy: Boolean = false
+ ) {
+ if (!compilation.target.konanTarget.enabledOnCurrentHost) {
+ return
+ }
+
+ val apiElements = configurations.getByName(compilation.target.apiElementsConfigurationName)
+
+ val realProducingTask: Task
+ // TODO: Someone remove this HACK PLEASE!
+ val realArtifactFile = if (copy) {
+ realProducingTask = project.tasks.create("copy${producingTask.name.capitalize()}", Copy::class.java) {
+ val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty()
+ it.destinationDir = project.buildDir.resolve("libs/$targetSubDirectory${compilation.name}")
+ it.from(artifactFile)
+ it.dependsOn(producingTask)
+ }
+ realProducingTask.destinationDir.resolve(artifactFile.name)
+ } else {
+ realProducingTask = producingTask
+ artifactFile
+ }
+
+ val klibArtifact = DefaultPublishArtifact(
+ compilation.name,
+ "klib",
+ "klib",
+ classifier,
+ Date(),
+ realArtifactFile,
+ realProducingTask
+ )
+ project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
+
+ with(apiElements.outgoing) {
+ artifacts.add(klibArtifact)
+ attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
+ }
+ }
+
+ private fun Project.createRegularKlibArtifact(
+ compilation: KotlinNativeCompilation,
+ compileTask: KotlinNativeCompile
+ ) = createKlibArtifact(compilation, compileTask.outputFile.get(), null, compileTask)
+
+ private fun Project.createCInteropKlibArtifact(
+ interop: DefaultCInteropSettings,
+ interopTask: CInteropProcess
+ ) = createKlibArtifact(interop.compilation, interopTask.outputFile, "cinterop-${interop.name}", interopTask, copy = true)
+ // endregion.
+
+ // region Task creation.
+ private fun Project.createLinkTask(binary: NativeBinary) {
+ tasks.create(
+ binary.linkTaskName,
+ KotlinNativeLink::class.java
+ ).apply {
+ val target = binary.target
+ this.binary = binary
+ group = BasePlugin.BUILD_GROUP
+ description = "Links ${binary.outputKind.description} '${binary.name}' for a target '${target.name}'."
+ enabled = target.konanTarget.enabledOnCurrentHost
+ destinationDir = binary.outputDirectory
+ addCompilerPlugins()
+
+ tasks.maybeCreate(target.artifactsTaskName).dependsOn(this)
+ tasks.maybeCreate(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(this)
+ }
+ }
+
+ private fun Project.createRunTask(binary: Executable) {
+ val taskName = binary.runTaskName ?: return
+ // TODO provide a special exec task for tests.
+ tasks.create(taskName, Exec::class.java).apply {
+ if (binary.isDefaultTestExecutable) {
+ group = LifecycleBasePlugin.VERIFICATION_GROUP
+ description = "Executes Kotlin/Native unit tests for target ${binary.target.name}."
+ tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME).dependsOn(this)
+ if (project.hasProperty("teamcity.version")) {
+ args("--ktest_logger=TEAMCITY")
+ }
+ } else {
+ group = RUN_GROUP
+ description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}"
+ }
+
+ enabled = binary.target.konanTarget.isCurrentHost
+
+ executable = binary.outputFile.absolutePath
+ workingDir = project.projectDir
+
+ onlyIf { binary.outputFile.exists() }
+ dependsOn(binary.linkTaskName)
+ }
+ }
+
+ private fun Project.createKlibCompilationTask(compilation: KotlinNativeCompilation) {
+ val compileTask = tasks.create(
+ compilation.compileKotlinTaskName,
+ KotlinNativeCompile::class.java
+ ).apply {
+ this.compilation = compilation
+ group = BasePlugin.BUILD_GROUP
+ description = "Compiles a klibrary from the '${compilation.name}' " +
+ "compilation for target '${compilation.platformType.name}'."
+ enabled = compilation.target.konanTarget.enabledOnCurrentHost
+
+ destinationDir = klibOutputDirectory(compilation)
+ addCompilerPlugins()
+ compilation.output.addClassesDir {
+ project.files(this.outputFile).builtBy(this)
+ }
+ }
+
+ project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTask)
+
+ if (compilation.compilationName == KotlinCompilation.MAIN_COMPILATION_NAME) {
+ project.tasks.getByName(compilation.target.artifactsTaskName).apply {
+ dependsOn(compileTask)
+ }
+ project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply {
+ dependsOn(compileTask)
+ }
+ createRegularKlibArtifact(compilation, compileTask)
+ }
+ }
+
+ private fun Project.createCInteropTasks(compilation: KotlinNativeCompilation) {
+ compilation.cinterops.all { interop ->
+ val interopTask = tasks.create(interop.interopProcessingTaskName, CInteropProcess::class.java).apply {
+ settings = interop
+ destinationDir = provider { klibOutputDirectory(compilation) }
+ group = INTEROP_GROUP
+ description = "Generates Kotlin/Native interop library '${interop.name}' " +
+ "for compilation '${compilation.name}'" +
+ "of target '${konanTarget.name}'."
+ enabled = compilation.target.konanTarget.enabledOnCurrentHost
+
+ val interopOutput = project.files(outputFileProvider).builtBy(this)
+ with(compilation) {
+ project.dependencies.add(compileDependencyConfigurationName, interopOutput)
+ if (isMainCompilation) {
+ target.compilations.findByName(TEST_COMPILATION_NAME)?.let {
+ project.dependencies.add(it.compileDependencyConfigurationName, interopOutput)
+ }
+ }
+ project.dependencies.add(target.apiElementsConfigurationName, interopOutput)
+ }
+ }
+ createCInteropKlibArtifact(interop, interopTask)
+ }
+ }
+ // endregion.
+
+ // region Configuration.
+ override fun configureTarget(target: KotlinNativeTarget) {
+ super.configureTarget(target)
+ configureBinaries(target)
+ configureFrameworkExport(target)
+ configureCInterops(target)
+ warnAboutIncorrectDependencies(target)
+ }
+
+ override fun configureArchivesAndComponent(target: KotlinNativeTarget): Unit = with(target.project) {
+ tasks.create(target.artifactsTaskName)
+ target.compilations.all {
+ createKlibCompilationTask(it)
+ }
+
+ with(configurations.getByName(target.apiElementsConfigurationName)) {
+ outgoing.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
+ }
+ }
+
+ override fun configureTest(target: KotlinNativeTarget) {
+ target.binaries.defaultTestExecutable {
+ compilation = target.compilations.maybeCreate(KotlinCompilation.TEST_COMPILATION_NAME)
+ // Allow accessing the test binary using the old getters (e.g. compilations.test.getBinary('EXECUTABLE', 'DEBUG'))
+ compilation.binaries[NativeOutputKind.EXECUTABLE to KotlinNativeBinaryContainer.DEFAULT_TEST_BUILD_TYPE] = this
+ }
+ }
+
+ protected fun configureCInterops(target: KotlinNativeTarget): Unit = with(target.project) {
+ target.compilations.all { compilation ->
+ createCInteropTasks(compilation)
+ compilation.cinterops.all {
+ defineConfigurationsForCInterop(compilation, it, target, configurations)
+ }
+ }
+
+ if (createTestCompilation) {
+ val mainCompilation = target.compilations.getByName(MAIN_COMPILATION_NAME)
+ target.compilations.findByName(TEST_COMPILATION_NAME)?.apply {
+ cinterops.all {
+ it.dependencyFiles += mainCompilation.output.allOutputs
+ }
+ }
+ }
+ }
+
+ protected fun configureBinaries(target: KotlinNativeTarget) {
+ val project = target.project
+ // Create link and run tasks.
+ target.binaries.all {
+ project.createLinkTask(it)
+ }
+
+ target.binaries.withType(Executable::class.java).all {
+ project.createRunTask(it)
+ }
+
+ target.binaries.prefixGroups.all { prefixGroup ->
+ val linkGroupTask = project.tasks.maybeCreate(prefixGroup.linkTaskName)
+ prefixGroup.binaries.all {
+ linkGroupTask.dependsOn(it.linkTaskName)
+ }
+ }
+
+ // Create an aggregate link task for each compilation.
+ target.compilations.all {
+ project.tasks.create(it.binariesTaskName)
+ }
+
+ project.whenEvaluated {
+ target.binaries.forEach {
+ project.tasks.getByName(it.compilation.binariesTaskName).dependsOn(it.linkTaskName)
+ }
+ }
+
+ // Create binaries for output kinds declared using the old DSL.
+ project.whenEvaluated {
+ target.compilations.all { compilation ->
+ val binaries = target.binaries
+ val konanTarget = compilation.target.konanTarget
+ val name = compilation.name
+ val buildTypes = compilation.buildTypes
+ val availableOutputKinds = compilation.outputKinds.filter { it.availableFor(konanTarget) }
+
+ val configure: NativeBinary.() -> Unit = {
+ this.compilation = compilation
+ linkerOpts.addAll(compilation.linkerOpts)
+ if (this is Executable) {
+ entryPoint = compilation.entryPoint
+ }
+ compilation.binaries[outputKind to buildType] = this
+ }
+
+ for (kind in availableOutputKinds) {
+ when (kind) {
+ NativeOutputKind.EXECUTABLE -> binaries.executable(name, buildTypes, configure)
+ NativeOutputKind.DYNAMIC -> binaries.sharedLib(name, buildTypes, configure)
+ NativeOutputKind.STATIC -> binaries.staticLib(name, buildTypes, configure)
+ NativeOutputKind.FRAMEWORK -> binaries.framework(name, buildTypes, configure)
+ }
+ }
+ }
+ // Allow setting linker options for the default test executable using the
+ // corresponding properties of the test compilation.
+ target.binaries.getDefaultTestExecutable().apply {
+ linkerOpts.addAll(target.compilations.getByName(TEST_COMPILATION_NAME).linkerOpts)
+ }
+ }
+ }
+
+ fun configureFrameworkExport(target: KotlinNativeTarget) {
+ val project = target.project
+
+ target.compilations.all {
+ // Allow resolving api configurations directly to be able to check that
+ // all exported dependency are also added in the corresponding api configurations.
+ // The check is performed during a link task execution.
+ project.configurations.maybeCreate(it.apiConfigurationName).apply {
+ isCanBeResolved = true
+ usesPlatformOf(target)
+ attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(target))
+ }
+ }
+
+ target.binaries.withType(Framework::class.java).all { framework ->
+ val exportConfiguration = project.configurations.maybeCreate(framework.exportConfigurationName).apply {
+ isVisible = false
+ isTransitive = false
+ isCanBeConsumed = false
+ isCanBeResolved = true
+ usesPlatformOf(target)
+ attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(target))
+ description = "Dependenceis to be exported in framework ${framework.name} for target ${target.targetName}"
+ }
+ }
+ }
+
+ override fun defineConfigurationsForTarget(target: KotlinNativeTarget) {
+ super.defineConfigurationsForTarget(target)
+ val configurations = target.project.configurations
+
+ // The configuration and the main compilation are created by the base class.
+ val mainCompilation = target.compilations.getByName(MAIN_COMPILATION_NAME)
+ configurations.getByName(target.apiElementsConfigurationName).apply {
+ // K/N compiler doesn't divide libraries into implementation and api ones. So we need to add implementation
+ // dependencies into the outgoing configuration.
+ extendsFrom(configurations.getByName(mainCompilation.implementationConfigurationName))
+ }
+ }
+
+ private fun warnAboutIncorrectDependencies(target: KotlinNativeTarget) = target.project.whenEvaluated {
+
+ val compileOnlyDependencies = target.compilations.mapNotNull {
+ val dependencies = configurations.getByName(it.compileOnlyConfigurationName).allDependencies
+ if (dependencies.isNotEmpty()) {
+ it to dependencies
+ } else null
+ }
+
+ fun Dependency.stringCoordinates(): String = buildString {
+ group?.let { append(it).append(':') }
+ append(name)
+ version?.let { append(':').append(it) }
+ }
+
+ if (compileOnlyDependencies.isNotEmpty()) {
+ with(target.project.logger) {
+ warn("A compileOnly dependency is used in the Kotlin/Native target '${target.name}':")
+ compileOnlyDependencies.forEach {
+ warn(
+ """
+ Compilation: ${it.first.name}
+
+ Dependencies:
+ ${it.second.joinToString(separator = "\n") { it.stringCoordinates() }}
+
+ """.trimIndent()
+ )
+ }
+ warn("Such dependencies are not applicable for Kotlin/Native, consider changing the dependency type to 'implementation' or 'api'.")
+ }
+ }
+ }
+ // endregion.
+
+ object NativeArtifactFormat {
+ const val KLIB = "org.jetbrains.kotlin.klib"
+ }
+
+ companion object {
+ const val INTEROP_GROUP = "interop"
+ const val RUN_GROUP = "run"
+
+ protected fun defineConfigurationsForCInterop(
+ compilation: KotlinNativeCompilation,
+ cinterop: CInteropSettings,
+ target: KotlinTarget,
+ configurations: ConfigurationContainer
+ ) {
+ val compileOnlyConfiguration = configurations.getByName(compilation.compileOnlyConfigurationName)
+ val implementationConfiguration = configurations.getByName(compilation.implementationConfigurationName)
+
+ cinterop.dependencyFiles = configurations.maybeCreate(cinterop.dependencyConfigurationName).apply {
+ extendsFrom(compileOnlyConfiguration, implementationConfiguration)
+ usesPlatformOf(target)
+ isVisible = false
+ isCanBeConsumed = false
+ attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(target))
+ description = "Dependencies for cinterop '${cinterop.name}' (compilation '${compilation.name}')."
+ }
+ }
+ }
+}
+
+internal fun Project.usageByName(usageName: String): Usage =
+ project.objects.named(Usage::class.java, usageName)
+
+fun Configuration.usesPlatformOf(target: KotlinTarget): Configuration {
+ attributes.attribute(KotlinPlatformType.attribute, target.platformType)
+ // TODO: Provide an universal way to copy attributes from the target.
+ if (target is KotlinNativeTarget) {
+ attributes.attribute(KotlinNativeTarget.konanTargetAttribute, target.konanTarget.name)
+ }
+ return this
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinAndroidTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinAndroidTarget.kt
new file mode 100644
index 00000000000..f4bbb5d60f9
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinAndroidTarget.kt
@@ -0,0 +1,437 @@
+/*
+ * 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.*
+import org.gradle.api.artifacts.ConfigurablePublishArtifact
+import org.gradle.api.artifacts.Dependency
+import org.gradle.api.artifacts.PublishArtifact
+import org.gradle.api.attributes.Attribute
+import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.attributes.Usage.JAVA_API
+import org.gradle.api.attributes.Usage.JAVA_RUNTIME_JARS
+import org.gradle.api.plugins.JavaPlugin
+import org.gradle.api.publish.maven.MavenPublication
+import org.gradle.util.ConfigureUtil
+import org.gradle.util.WrapUtil
+import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
+import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
+import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
+import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
+import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+import org.jetbrains.kotlin.konan.target.KonanTarget
+
+abstract class AbstractKotlinTarget(
+ final override val project: Project
+) : KotlinTarget {
+ private val attributeContainer = HierarchyAttributeContainer(parent = null)
+
+ override fun getAttributes(): AttributeContainer = attributeContainer
+
+ override val defaultConfigurationName: String
+ get() = disambiguateName("default")
+
+ override val apiElementsConfigurationName: String
+ get() = disambiguateName("apiElements")
+
+ override val runtimeElementsConfigurationName: String
+ get() = disambiguateName("runtimeElements")
+
+ override val artifactsTaskName: String
+ get() = disambiguateName("jar")
+
+ override fun toString(): String = "target $name ($platformType)"
+
+ override val publishable: Boolean
+ get() = true
+
+ override val components: Set by lazy {
+ val mainCompilation = compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
+ val usageContexts = createUsageContexts(mainCompilation)
+ setOf(
+ if (isGradleVersionAtLeast(4, 7)) {
+ val componentName = mainCompilation.target.name
+ createKotlinVariant(componentName, mainCompilation, usageContexts).apply {
+ sourcesArtifacts = setOf(
+ sourcesJarArtifact(
+ mainCompilation, componentName,
+ dashSeparatedName(target.name.toLowerCase(), componentName.toLowerCase())
+ )
+ )
+ }
+ } else {
+ KotlinVariant(mainCompilation, usageContexts)
+ }
+ ).also { project.components.addAll(it) }
+ }
+
+ protected fun createKotlinVariant(
+ componentName: String,
+ compilation: KotlinCompilation<*>,
+ usageContexts: Set
+ ): KotlinVariant {
+
+ val kotlinExtension = project.kotlinExtension as? KotlinMultiplatformExtension
+ ?: return KotlinVariantWithCoordinates(compilation, usageContexts)
+
+ if (targetName == KotlinMultiplatformPlugin.METADATA_TARGET_NAME)
+ return KotlinVariantWithCoordinates(compilation, usageContexts)
+
+ val separateMetadataTarget = kotlinExtension.targets.getByName(KotlinMultiplatformPlugin.METADATA_TARGET_NAME)
+
+ val result = if (kotlinExtension.isGradleMetadataAvailable) {
+ KotlinVariantWithMetadataVariant(compilation, usageContexts, separateMetadataTarget)
+ } else {
+ // we should only add the Kotlin metadata dependency if we publish no Gradle metadata related to Kotlin MPP;
+ // with metadata, such a dependency would get invalid, since a platform module should only depend on modules for that
+ // same platform, not Kotlin metadata modules
+ KotlinVariantWithMetadataDependency(compilation, usageContexts, separateMetadataTarget)
+ }
+
+ result.componentName = componentName
+ return result
+ }
+
+ private fun createUsageContexts(
+ producingCompilation: KotlinCompilation<*>
+ ): Set {
+ // Here, `JAVA_API` and `JAVA_RUNTIME_JARS` are used intentionally as Gradle needs this for
+ // ordering of the usage contexts (prioritizing the dependencies) when merging them into the POM;
+ // These Java usages should not be replaced with the custom Kotlin usages.
+ return listOfNotNull(
+ JAVA_API to apiElementsConfigurationName,
+ (JAVA_RUNTIME_JARS to runtimeElementsConfigurationName).takeIf { producingCompilation is KotlinCompilationToRunnableFiles }
+ ).mapTo(mutableSetOf()) { (usageName, dependenciesConfigurationName) ->
+ DefaultKotlinUsageContext(
+ producingCompilation,
+ project.usageByName(usageName),
+ dependenciesConfigurationName
+ )
+ }
+ }
+
+ protected fun sourcesJarArtifact(
+ producingCompilation: KotlinCompilation<*>,
+ componentName: String,
+ artifactNameAppendix: String,
+ classifierPrefix: String? = null
+ ): PublishArtifact {
+ val sourcesJarTask = sourcesJarTask(producingCompilation, componentName, artifactNameAppendix)
+ val sourceArtifactConfigurationName = producingCompilation.disambiguateName("sourceArtifacts")
+ return producingCompilation.target.project.run {
+ (configurations.findByName(sourceArtifactConfigurationName) ?: run {
+ val configuration = configurations.create(sourceArtifactConfigurationName) {
+ it.isCanBeResolved = false
+ it.isCanBeConsumed = false
+ }
+ artifacts.add(sourceArtifactConfigurationName, sourcesJarTask)
+ configuration
+ }).artifacts.single().apply {
+ this as ConfigurablePublishArtifact
+ classifier = dashSeparatedName(classifierPrefix, "sources")
+ }
+ }
+ }
+
+ @Suppress("UNCHECKED_CAST")
+ internal val publicationConfigureActions =
+ WrapUtil.toDomainObjectSet(Action::class.java) as DomainObjectSet>
+
+ override fun mavenPublication(action: Action) {
+ publicationConfigureActions.add(action)
+ }
+
+ override fun mavenPublication(action: Closure) =
+ mavenPublication(ConfigureUtil.configureUsing(action))
+
+ override var preset: KotlinTargetPreset? = null
+ internal set
+}
+
+internal fun KotlinTarget.disambiguateName(simpleName: String) =
+ lowerCamelCaseName(targetName, simpleName)
+
+open class KotlinAndroidTarget(
+ override val targetName: String,
+ project: Project
+) : AbstractKotlinTarget(project) {
+
+ override var disambiguationClassifier: String? = null
+ internal set
+
+ override val platformType: KotlinPlatformType
+ get() = KotlinPlatformType.androidJvm
+
+ private val compilationFactory = KotlinJvmAndroidCompilationFactory(project, this)
+
+ override val compilations: NamedDomainObjectContainer =
+ project.container(compilationFactory.itemClass, compilationFactory)
+
+ /** Names of the Android library variants that should be published from the target's project within the default publications which are
+ * set up if the `maven-publish` Gradle plugin is applied.
+ *
+ * Item examples:
+ * * 'release' (in case no product flavors were defined)
+ * * 'fooRelease' (for the release build type of a flavor 'foo')
+ * * 'fooBarRelease' (for the release build type multi-dimensional flavors 'foo' and 'bar').
+ *
+ * If set to null, which can also be done with [publishAllLibraryVariants],
+ * all library variants will be published, but not test or application variants. */
+ var publishLibraryVariants: List? = listOf()
+ // Workaround for Groovy GString items in a list:
+ set(value) { field = value?.map(Any::toString) }
+
+ /** Add Android library variant names to [publishLibraryVariants]. */
+ fun publishLibraryVariants(vararg names: String) {
+ publishLibraryVariants = publishLibraryVariants.orEmpty() + names
+ }
+
+ /** Set up all of the Android library variants to be published from this target's project within the default publications, which are
+ * set up if the `maven-publish` Gradle plugin is applied. This overrides the variants chosen with [publishLibraryVariants] */
+ fun publishAllLibraryVariants() {
+ publishLibraryVariants = null
+ }
+
+ /** If true, a publication will be created per merged product flavor, with the build types used as classifiers for the artifacts
+ * published within each publication. If set to false, each Android variant will have a separate publication. */
+ var publishLibraryVariantsGroupedByFlavor = false
+
+ private fun checkPublishLibraryVariantsExist() {
+ // Capture type parameter T
+ fun AbstractAndroidProjectHandler.getLibraryVariantNames() =
+ mutableSetOf().apply {
+ forEachVariant(project) {
+ if (getLibraryOutputTask(it) != null)
+ add(getVariantName(it))
+ }
+ }
+
+ val variantNames =
+ KotlinAndroidPlugin.androidTargetHandler(project.getKotlinPluginVersion()!!, this)
+ .getLibraryVariantNames()
+
+ val missingVariants =
+ publishLibraryVariants?.minus(variantNames).orEmpty()
+
+ if (missingVariants.isNotEmpty())
+ throw InvalidUserDataException(
+ "Kotlin target '$targetName' tried to set up publishing for Android build variants that are not library variants " +
+ "or do not exist:\n" + missingVariants.joinToString("\n") { "* $it" } +
+ "\nCheck the 'publishLibraryVariants' property, it should point to existing Android library variants. Publishing " +
+ "of application and test variants is not supported."
+ )
+ }
+
+ override val components by lazy {
+ checkPublishLibraryVariantsExist()
+
+ KotlinAndroidPlugin.androidTargetHandler(project.getKotlinPluginVersion()!!, this).doCreateComponents()
+ .also { project.components.addAll(it) }
+ }
+
+ // Capture the type parameter T for `AbstractAndroidProjectHandler`
+ private fun AbstractAndroidProjectHandler.doCreateComponents(): Set {
+ if (!isGradleVersionAtLeast(4, 7))
+ return emptySet()
+
+ val publishableVariants = mutableListOf()
+ .apply { forEachVariant(project) { add(it) } }
+ .toList() // Defensive copy against unlikely modification by the lambda that captures the list above in forEachVariant { }
+ .filter { getLibraryOutputTask(it) != null && publishLibraryVariants?.contains(getVariantName(it)) ?: true }
+
+ val publishableVariantGroups = publishableVariants.groupBy { variant ->
+ val flavorNames = getFlavorNames(variant)
+ if (publishLibraryVariantsGroupedByFlavor) {
+ // For each flavor, we group its variants (which differ only in the build type) in a single component in order to publish
+ // all of the build types of the flavor as a single module with the build type as the classifier of the artifacts
+ flavorNames
+ } else {
+ flavorNames + getBuildTypeName(variant)
+ }
+ }
+
+ return publishableVariantGroups.map { (flavorGroupNameParts, androidVariants) ->
+ val nestedVariants = androidVariants.mapTo(mutableSetOf()) { androidVariant ->
+ val androidVariantName = getVariantName(androidVariant)
+ val compilation = compilations.getByName(androidVariantName)
+
+ val flavorNames = getFlavorNames(androidVariant)
+ val buildTypeName = getBuildTypeName(androidVariant)
+
+ val artifactClassifier = buildTypeName.takeIf { it != "release" && publishLibraryVariantsGroupedByFlavor }
+
+ val usageContexts = createAndroidUsageContexts(androidVariant, compilation, artifactClassifier)
+ createKotlinVariant(
+ lowerCamelCaseName(compilation.target.name, *flavorGroupNameParts.toTypedArray()),
+ compilation,
+ usageContexts
+ ).apply {
+ sourcesArtifacts = setOf(
+ sourcesJarArtifact(
+ compilation, compilation.disambiguateName(""),
+ dashSeparatedName(
+ compilation.target.name.toLowerCase(),
+ *flavorNames.map { it.toLowerCase() }.toTypedArray(),
+ buildTypeName.takeIf { it != "release" }?.toLowerCase()
+ ),
+ classifierPrefix = artifactClassifier
+ )
+ )
+
+ if (!publishLibraryVariantsGroupedByFlavor) {
+ defaultArtifactIdSuffix =
+ dashSeparatedName(
+ (getFlavorNames(androidVariant) + getBuildTypeName(androidVariant).takeIf { it != "release" })
+ .map { it?.toLowerCase() }
+ ).takeIf { it.isNotEmpty() }
+ }
+ }
+ }
+
+ if (publishLibraryVariantsGroupedByFlavor) {
+ JointAndroidKotlinTargetComponent(
+ this@KotlinAndroidTarget,
+ nestedVariants,
+ flavorGroupNameParts,
+ nestedVariants.flatMap { it.sourcesArtifacts }.toSet()
+ )
+ } else {
+ nestedVariants.single()
+ } as KotlinTargetComponent
+ }.toSet()
+ }
+
+ private fun AbstractAndroidProjectHandler.createAndroidUsageContexts(
+ variant: T,
+ compilation: KotlinCompilation<*>,
+ artifactClassifier: String?
+ ): Set {
+ val variantName = getVariantName(variant)
+ val outputTask = getLibraryOutputTask(variant) ?: return emptySet()
+ val artifact = run {
+ val archivesConfigurationName = lowerCamelCaseName(targetName, variantName, "archives")
+ project.configurations.maybeCreate(archivesConfigurationName).apply {
+ isCanBeConsumed = false
+ isCanBeResolved = false
+ }
+ project.artifacts.add(archivesConfigurationName, outputTask) { artifact ->
+ artifact.classifier = artifactClassifier
+ }
+ }
+
+ val apiElementsConfigurationName = lowerCamelCaseName(variantName, "apiElements")
+ val runtimeElementsConfigurationName = lowerCamelCaseName(variantName, "runtimeElements")
+
+ // Here, `JAVA_API` and `JAVA_RUNTIME_JARS` are used intentionally as Gradle needs this for
+ // ordering of the usage contexts (prioritizing the dependencies) when merging them into the POM;
+ // These Java usages should not be replaced with the custom Kotlin usages.
+ return listOf(
+ apiElementsConfigurationName to JAVA_API,
+ runtimeElementsConfigurationName to JAVA_RUNTIME_JARS
+ ).mapTo(mutableSetOf()) { (dependencyConfigurationName, usageName) ->
+ DefaultKotlinUsageContext(
+ compilation,
+ project.usageByName(usageName),
+ dependencyConfigurationName,
+ overrideConfigurationArtifacts = setOf(artifact)
+ )
+ }
+ }
+}
+
+open class KotlinWithJavaTarget(
+ project: Project,
+ override val platformType: KotlinPlatformType,
+ override val targetName: String
+) : AbstractKotlinTarget(project) {
+ override var disambiguationClassifier: String? = null
+ internal set
+
+ override val defaultConfigurationName: String
+ get() = Dependency.DEFAULT_CONFIGURATION
+
+ override val apiElementsConfigurationName: String
+ get() = JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME
+
+ override val runtimeElementsConfigurationName: String
+ get() = JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME
+
+ override val artifactsTaskName: String
+ get() = JavaPlugin.JAR_TASK_NAME
+
+ override val compilations: NamedDomainObjectContainer> =
+ @Suppress("UNCHECKED_CAST")
+ project.container(
+ KotlinWithJavaCompilation::class.java as Class>,
+ KotlinWithJavaCompilationFactory(project, this)
+ )
+}
+
+open class KotlinOnlyTarget>(
+ project: Project,
+ override val platformType: KotlinPlatformType
+) : AbstractKotlinTarget(project) {
+
+ override lateinit var compilations: NamedDomainObjectContainer
+ internal set
+
+ override lateinit var targetName: String
+ internal set
+
+ override var disambiguationClassifier: String? = null
+ internal set
+}
+
+class KotlinNativeTarget(
+ project: Project,
+ val konanTarget: KonanTarget
+) : KotlinOnlyTarget(project, KotlinPlatformType.native) {
+
+ init {
+ attributes.attribute(konanTargetAttribute, konanTarget.name)
+ }
+
+ val binaries = if(isGradleVersionAtLeast(4, 2)) {
+ // Use newInstance to allow accessing binaries by their names in Groovy using the extension mechanism.
+ project.objects.newInstance(KotlinNativeBinaryContainer::class.java, this, WrapUtil.toDomainObjectSet(NativeBinary::class.java))
+ } else {
+ KotlinNativeBinaryContainer(this, WrapUtil.toDomainObjectSet(NativeBinary::class.java))
+ }
+
+ fun binaries(configure: KotlinNativeBinaryContainer.() -> Unit) {
+ binaries.configure()
+ }
+
+ fun binaries(configure: Closure<*>) {
+ ConfigureUtil.configure(configure, binaries)
+ }
+
+ override val artifactsTaskName: String
+ get() = disambiguateName("binaries")
+
+ override val publishable: Boolean
+ get() = konanTarget.enabledOnCurrentHost
+
+ // User-visible constants
+ val DEBUG = NativeBuildType.DEBUG
+ val RELEASE = NativeBuildType.RELEASE
+
+ val EXECUTABLE = NativeOutputKind.EXECUTABLE
+ val FRAMEWORK = NativeOutputKind.FRAMEWORK
+ val DYNAMIC = NativeOutputKind.DYNAMIC
+ val STATIC = NativeOutputKind.STATIC
+
+ companion object {
+ val konanTargetAttribute = Attribute.of(
+ "org.jetbrains.kotlin.native.target",
+ String::class.java
+ )
+ }
+}
+
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinAndroidTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinAndroidTargetPreset.kt
new file mode 100644
index 00000000000..921736ad861
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinAndroidTargetPreset.kt
@@ -0,0 +1,330 @@
+/*
+ * 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.Dependency
+import org.gradle.api.internal.file.FileResolver
+import org.gradle.api.plugins.JavaPlugin
+import org.gradle.internal.reflect.Instantiator
+import org.jetbrains.kotlin.compilerRunner.KotlinNativeProjectProperty
+import org.jetbrains.kotlin.compilerRunner.hasProperty
+import org.jetbrains.kotlin.compilerRunner.konanHome
+import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
+import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask
+import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
+import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
+import org.jetbrains.kotlin.konan.KonanVersion
+import org.jetbrains.kotlin.konan.target.HostManager
+import org.jetbrains.kotlin.konan.target.KonanTarget
+import java.io.File
+import java.util.*
+
+abstract class KotlinOnlyTargetPreset>(
+ protected val project: Project,
+ private val instantiator: Instantiator,
+ private val fileResolver: FileResolver,
+ protected val kotlinPluginVersion: String
+) : KotlinTargetPreset> {
+
+ protected open fun createKotlinTargetConfigurator(): KotlinTargetConfigurator =
+ KotlinTargetConfigurator(createDefaultSourceSets = true, createTestCompilation = true)
+
+ override fun createTarget(name: String): KotlinOnlyTarget {
+ val result = KotlinOnlyTarget(project, platformType).apply {
+ targetName = name
+ disambiguationClassifier = name
+ preset = this@KotlinOnlyTargetPreset
+
+ val compilationFactory = createCompilationFactory(this)
+ compilations = project.container(compilationFactory.itemClass, compilationFactory)
+ }
+
+ createKotlinTargetConfigurator().configureTarget(result)
+
+ result.compilations.all { compilation ->
+ buildCompilationProcessor(compilation).run()
+ if (compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME) {
+ sourcesJarTask(compilation, result.targetName, result.targetName.toLowerCase())
+ }
+ }
+
+ return result
+ }
+
+ protected abstract fun createCompilationFactory(forTarget: KotlinOnlyTarget): KotlinCompilationFactory
+ protected abstract val platformType: KotlinPlatformType
+ internal abstract fun buildCompilationProcessor(compilation: T): KotlinSourceSetProcessor<*>
+}
+
+class KotlinMetadataTargetPreset(
+ project: Project,
+ instantiator: Instantiator,
+ fileResolver: FileResolver,
+ kotlinPluginVersion: String
+) : KotlinOnlyTargetPreset(
+ project,
+ instantiator,
+ fileResolver,
+ kotlinPluginVersion
+) {
+ override fun getName(): String = PRESET_NAME
+
+ override fun createCompilationFactory(
+ forTarget: KotlinOnlyTarget
+ ): KotlinCompilationFactory =
+ KotlinCommonCompilationFactory(forTarget)
+
+ override val platformType: KotlinPlatformType
+ get() = KotlinPlatformType.common
+
+ override fun buildCompilationProcessor(compilation: KotlinCommonCompilation): KotlinSourceSetProcessor<*> {
+ val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
+ return KotlinCommonSourceSetProcessor(project, compilation, tasksProvider, kotlinPluginVersion)
+ }
+
+ companion object {
+ const val PRESET_NAME = "metadata"
+ }
+
+ override fun createKotlinTargetConfigurator(): KotlinTargetConfigurator =
+ KotlinTargetConfigurator(createDefaultSourceSets = false, createTestCompilation = false)
+
+ override fun createTarget(name: String): KotlinOnlyTarget =
+ super.createTarget(name).apply {
+ val mainCompilation = compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
+ val commonMainSourceSet = project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
+
+ mainCompilation.source(commonMainSourceSet)
+
+ project.afterEvaluate {
+ // Since there's no default source set, apply language settings from commonMain:
+ val compileKotlinMetadata = project.tasks.getByName(mainCompilation.compileKotlinTaskName) as KotlinCompile<*>
+ applyLanguageSettingsToKotlinTask(commonMainSourceSet.languageSettings, compileKotlinMetadata)
+ }
+ }
+}
+
+class KotlinJvmTargetPreset(
+ project: Project,
+ instantiator: Instantiator,
+ fileResolver: FileResolver,
+ kotlinPluginVersion: String
+) : KotlinOnlyTargetPreset(
+ project,
+ instantiator,
+ fileResolver,
+ kotlinPluginVersion
+) {
+ override fun getName(): String = PRESET_NAME
+
+ override fun createCompilationFactory(forTarget: KotlinOnlyTarget): KotlinCompilationFactory =
+ KotlinJvmCompilationFactory(forTarget)
+
+ override val platformType: KotlinPlatformType
+ get() = KotlinPlatformType.jvm
+
+ override fun buildCompilationProcessor(compilation: KotlinJvmCompilation): KotlinSourceSetProcessor<*> {
+ val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
+ return Kotlin2JvmSourceSetProcessor(project, tasksProvider, compilation, kotlinPluginVersion)
+ }
+
+ companion object {
+ const val PRESET_NAME = "jvm"
+ }
+}
+
+class KotlinJsTargetPreset(
+ project: Project,
+ instantiator: Instantiator,
+ fileResolver: FileResolver,
+ kotlinPluginVersion: String
+) : KotlinOnlyTargetPreset(
+ project,
+ instantiator,
+ fileResolver,
+ kotlinPluginVersion
+) {
+ override fun getName(): String = PRESET_NAME
+
+ override fun createCompilationFactory(forTarget: KotlinOnlyTarget) =
+ KotlinJsCompilationFactory(project, forTarget)
+
+ override val platformType: KotlinPlatformType
+ get() = KotlinPlatformType.js
+
+ override fun buildCompilationProcessor(compilation: KotlinJsCompilation): KotlinSourceSetProcessor<*> {
+ val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
+ return Kotlin2JsSourceSetProcessor(project, tasksProvider, compilation, kotlinPluginVersion)
+ }
+
+ companion object {
+ const val PRESET_NAME = "js"
+ }
+}
+
+class KotlinAndroidTargetPreset(
+ private val project: Project,
+ private val kotlinPluginVersion: String
+) : KotlinTargetPreset {
+
+ override fun getName(): String = PRESET_NAME
+
+ override fun createTarget(name: String): KotlinAndroidTarget {
+ val result = KotlinAndroidTarget(name, project).apply {
+ disambiguationClassifier = name
+ preset = this@KotlinAndroidTargetPreset
+ }
+
+ KotlinAndroidPlugin.applyToTarget(kotlinPluginVersion, result)
+ return result
+ }
+
+ companion object {
+ const val PRESET_NAME = "android"
+ }
+}
+
+class KotlinJvmWithJavaTargetPreset(
+ private val project: Project,
+ private val kotlinPluginVersion: String
+) : KotlinTargetPreset> {
+
+ 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
+ preset = this@KotlinJvmWithJavaTargetPreset
+ }
+
+ AbstractKotlinPlugin.configureTarget(target) { compilation ->
+ Kotlin2JvmSourceSetProcessor(project, KotlinTasksProvider(name), compilation, kotlinPluginVersion)
+ }
+
+ target.compilations.getByName("test").run {
+ val main = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
+
+ compileDependencyFiles = project.files(
+ main.output.allOutputs,
+ project.configurations.maybeCreate(compileDependencyConfigurationName)
+ )
+ runtimeDependencyFiles = project.files(
+ output.allOutputs,
+ main.output.allOutputs,
+ project.configurations.maybeCreate(runtimeDependencyConfigurationName)
+ )
+ }
+
+ return target
+ }
+
+ companion object {
+ const val PRESET_NAME = "jvmWithJava"
+ }
+}
+
+class KotlinNativeTargetPreset(
+ private val name: String,
+ val project: Project,
+ val konanTarget: KonanTarget,
+ private val kotlinPluginVersion: String
+) : KotlinTargetPreset {
+
+ init {
+ // This is required to obtain Kotlin/Native home in CLion plugin:
+ setupNativeHomePrivateProperty()
+ }
+
+ override fun getName(): String = name
+
+ private fun setupNativeHomePrivateProperty() = with(project) {
+ if (!hasProperty(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY))
+ extensions.extraProperties.set(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY, konanHome)
+ }
+
+ private fun setupNativeCompiler() = with(project) {
+ if (!hasProperty(KotlinNativeProjectProperty.KONAN_HOME_OVERRIDE)) {
+ NativeCompilerDownloader(this).downloadIfNeeded()
+ logger.info("Kotlin/Native distribution: $konanHome")
+ } else {
+ logger.info("User-provided Kotlin/Native distribution: $konanHome")
+ }
+ }
+
+ // We declare default K/N dependencies as files to avoid searching them in remote repos (see KT-28128).
+ private fun defaultLibs(target: KonanTarget? = null): List = with(project) {
+
+ val relPath = if (target != null) "platform/${target.name}" else "common"
+
+ file("$konanHome/klib/$relPath")
+ .listFiles { file -> file.isDirectory }
+ ?.sortedBy { dir -> dir.name.toLowerCase() }
+ ?.map { dir -> dependencies.create(files(dir)) } ?: emptyList()
+ }
+
+ override fun createTarget(name: String): KotlinNativeTarget {
+ setupNativeCompiler()
+
+ val result = KotlinNativeTarget(project, konanTarget).apply {
+ targetName = name
+ disambiguationClassifier = name
+ preset = this@KotlinNativeTargetPreset
+
+ val compilationFactory = KotlinNativeCompilationFactory(project, this)
+ compilations = project.container(compilationFactory.itemClass, compilationFactory)
+ }
+
+ KotlinNativeTargetConfigurator(kotlinPluginVersion).configureTarget(result)
+
+ // Allow IDE to resolve the libraries provided by the compiler by adding them into dependencies.
+ result.compilations.all { compilation ->
+ val target = compilation.target.konanTarget
+ // First, put common libs:
+ defaultLibs().forEach {
+ project.dependencies.add(compilation.compileDependencyConfigurationName, it)
+ }
+ // Then, platform-specific libs:
+ defaultLibs(target).forEach {
+ project.dependencies.add(compilation.compileDependencyConfigurationName, it)
+ }
+ }
+
+ if (!konanTarget.enabledOnCurrentHost) {
+ with(HostManager()) {
+ val supportedHosts = enabledTargetsByHost.filterValues { konanTarget in it }.keys
+ val supportedHostsString =
+ if (supportedHosts.size == 1)
+ "a ${supportedHosts.single()} host" else
+ "one of the host platforms: ${supportedHosts.joinToString(", ")}"
+ project.logger.warn(
+ "Target '$name' for platform ${konanTarget} is ignored during build on this ${HostManager.host} machine. " +
+ "You can build it with $supportedHostsString."
+ )
+ }
+ }
+
+ return result
+ }
+
+ companion object {
+ private const val KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY = "konanHome"
+ }
+}
+
+internal val KonanTarget.isCurrentHost: Boolean
+ get() = this == HostManager.host
+
+internal val KonanTarget.enabledOnCurrentHost
+ get() = HostManager().isEnabled(this)
+
+internal val KotlinNativeCompilation.isMainCompilation: Boolean
+ get() = name == KotlinCompilation.MAIN_COMPILATION_NAME
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCommonCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCommonCompilation.kt
new file mode 100644
index 00000000000..1284fe446f3
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCommonCompilation.kt
@@ -0,0 +1,471 @@
+ /*
+ * 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.Action
+import org.gradle.api.NamedDomainObjectContainer
+import org.gradle.api.Project
+import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.file.FileCollection
+import org.gradle.api.file.SourceDirectorySet
+import org.gradle.api.tasks.SourceSet
+import org.gradle.util.ConfigureUtil
+import org.jetbrains.kotlin.gradle.dsl.*
+import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
+import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
+import org.jetbrains.kotlin.gradle.tasks.*
+import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+import java.io.File
+import java.util.*
+import java.util.concurrent.Callable
+
+internal fun KotlinCompilation<*>.composeName(prefix: String? = null, suffix: String? = null): String {
+ val compilationNamePart = compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }
+ val targetNamePart = target.disambiguationClassifier
+
+ return lowerCamelCaseName(prefix, targetNamePart, compilationNamePart, suffix)
+}
+
+internal val KotlinCompilation<*>.defaultSourceSetName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName)
+
+abstract class AbstractKotlinCompilation(
+ target: KotlinTarget,
+ override val compilationName: String
+) : KotlinCompilation, HasKotlinDependencies {
+
+ override val kotlinOptions: T
+ get() = compileKotlinTask.kotlinOptions
+
+ override fun kotlinOptions(configure: T.() -> Unit) =
+ configure(kotlinOptions)
+
+ @Suppress("UNCHECKED_CAST")
+ override val compileKotlinTask: KotlinCompile
+ get() = (target.project.tasks.getByName(compileKotlinTaskName) as KotlinCompile)
+
+ // Don't declare this property in the constructor to avoid NPE
+ // when an overriding property of a subclass is accessed instead.
+ override val target: KotlinTarget = target
+
+ private val attributeContainer = HierarchyAttributeContainer(target.attributes)
+
+ override fun getAttributes(): AttributeContainer = attributeContainer
+
+ override val kotlinSourceSets: MutableSet = mutableSetOf()
+
+ override val allKotlinSourceSets: Set
+ get() = kotlinSourceSets.flatMapTo(mutableSetOf()) { it.getSourceSetHierarchy() }
+
+ override val defaultSourceSet: KotlinSourceSet
+ get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName)
+
+ override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) =
+ configure(defaultSourceSet)
+
+ override val output: KotlinCompilationOutput by lazy {
+ DefaultKotlinCompilationOutput(
+ target.project,
+ Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
+ }
+
+ open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
+ fun AbstractKotlinCompile<*>.configureAction() {
+ source(sourceSet.kotlin)
+ sourceFilesExtensions(sourceSet.customSourceFilesExtensions)
+ if (addAsCommonSources) {
+ commonSourceSet += sourceSet.kotlin
+ }
+ }
+
+ // Note! Invocation of withType-all results in preliminary task instantiation.
+ // After fix of this issue the following code should be uncommented:
+// if (useLazyTaskConfiguration) {
+// (target.project.tasks.named(compileKotlinTaskName) as TaskProvider>).configure {
+// it.configureAction()
+// }
+// }
+
+ target.project.tasks
+ // To configure a task that may have not yet been created at this point, use 'withType-matching-all`:
+ .withType(AbstractKotlinCompile::class.java)
+ .matching { it.name == compileKotlinTaskName }
+ .all { compileKotlinTask ->
+ compileKotlinTask.configureAction()
+ }
+ }
+
+ override fun source(sourceSet: KotlinSourceSet) {
+ if (kotlinSourceSets.add(sourceSet)) {
+ //TODO possibly issue with forced instantiation
+ target.project.whenEvaluated {
+ sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
+ val isCommonSource =
+ CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false
+
+ addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
+
+ // Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
+ // old Java & Android projects:
+ addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
+ addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
+ addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
+
+ if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
+ addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
+ }
+
+ if (sourceSet.name != defaultSourceSetName) {
+ kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
+ // Temporary solution for checking consistency across source sets participating in a compilation that may
+ // not be interconnected with the dependsOn relation: check the settings as if the default source set of
+ // the compilation depends on the one added to the compilation:
+ defaultSourceSetLanguageSettingsChecker.runAllChecks(
+ defaultSourceSet,
+ sourceSet
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override val compileDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
+ "compileClasspath"
+ )
+
+ override val compileKotlinTaskName: String
+ get() = lowerCamelCaseName(
+ "compile",
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "Kotlin",
+ target.targetName
+ )
+
+ override val compileAllTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "classes")
+
+ override lateinit var compileDependencyFiles: FileCollection
+
+ override val apiConfigurationName: String
+ get() = disambiguateName("api")
+
+ override val implementationConfigurationName: String
+ get() = disambiguateName("implementation")
+
+ override val compileOnlyConfigurationName: String
+ get() = disambiguateName("compileOnly")
+
+ override val runtimeOnlyConfigurationName: String
+ get() = disambiguateName("runtimeOnly")
+
+ override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
+ DefaultKotlinDependencyHandler(this, target.project).run(configure)
+
+ override fun dependencies(configureClosure: Closure) =
+ dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
+
+ override fun toString(): String = "compilation '$compilationName' ($target)"
+}
+
+abstract class AbstractKotlinCompilationToRunnableFiles(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name), KotlinCompilationToRunnableFiles {
+ override val runtimeDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "runtimeClasspath"
+ )
+
+ override lateinit var runtimeDependencyFiles: FileCollection
+}
+
+internal fun KotlinCompilation<*>.disambiguateName(simpleName: String): String {
+ return lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ simpleName
+ )
+}
+
+open class KotlinJvmCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+ get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+}
+
+class KotlinWithJavaCompilation(
+ target: KotlinWithJavaTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ lateinit var javaSourceSet: SourceSet
+
+ override val output: KotlinCompilationOutput by lazy { KotlinWithJavaCompilationOutput(this) }
+
+ override val processResourcesTaskName: String
+ get() = javaSourceSet.processResourcesTaskName
+
+ override var runtimeDependencyFiles: FileCollection
+ get() = javaSourceSet.runtimeClasspath
+ set(value) {
+ javaSourceSet.runtimeClasspath = value
+ }
+
+ override val runtimeDependencyConfigurationName: String
+ get() = javaSourceSet.runtimeClasspathConfigurationName
+
+ override val compileDependencyConfigurationName: String
+ get() = javaSourceSet.compileClasspathConfigurationName
+
+ override val runtimeOnlyConfigurationName: String
+ get() = javaSourceSet.runtimeOnlyConfigurationName
+
+ override val implementationConfigurationName: String
+ get() = javaSourceSet.implementationConfigurationName
+
+ override val apiConfigurationName: String
+ get() = javaSourceSet.apiConfigurationName
+
+ override val compileOnlyConfigurationName: String
+ get() = javaSourceSet.compileOnlyConfigurationName
+
+ override val compileAllTaskName: String
+ get() = javaSourceSet.classesTaskName
+
+ override var compileDependencyFiles: FileCollection
+ get() = javaSourceSet.compileClasspath
+ set(value) {
+ javaSourceSet.compileClasspath = value
+ }
+
+ fun source(javaSourceSet: SourceSet) {
+ with(target.project) {
+ afterEvaluate {
+ (tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(javaSourceSet.java)
+ }
+ }
+ }
+}
+
+class KotlinJvmAndroidCompilation(
+ target: KotlinAndroidTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name) {
+ override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+ get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+ override val relatedConfigurationNames: List
+ get() = super.relatedConfigurationNames + listOf("${name}ApiElements", "${name}RuntimeElements")
+}
+
+class KotlinJsCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ override val compileKotlinTask: Kotlin2JsCompile
+ get() = super.compileKotlinTask as Kotlin2JsCompile
+}
+
+class KotlinCommonCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name) {
+ override val compileKotlinTask: KotlinCompileCommon
+ get() = super.compileKotlinTask as KotlinCompileCommon
+
+ // TODO once we properly compile metadata for each source set, the default source sets will likely become just the source sets
+ // which are transformed to metadata
+ private val commonSourceSetName = when (compilationName) {
+ KotlinCompilation.MAIN_COMPILATION_NAME -> KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
+ else -> error("Custom metadata compilations are not supported yet")
+ }
+
+ override val defaultSourceSet: KotlinSourceSet
+ get() = target.project.kotlinExtension.sourceSets.getByName(commonSourceSetName)
+}
+
+class KotlinNativeCompilation(
+ override val target: KotlinNativeTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name), KotlinCompilationWithResources {
+
+ override val kotlinOptions: KotlinCommonOptions
+ get() = compileKotlinTask.kotlinOptions
+
+ override val compileKotlinTask: KotlinNativeCompile
+ get() = super.compileKotlinTask as KotlinNativeCompile
+
+ private val project: Project
+ get() = target.project
+
+ // A collection containing all source sets used by this compilation
+ // (taking into account dependencies between source sets). Used by both compilation
+ // and linking tasks. Unlike kotlinSourceSets, includes dependency source sets.
+ // TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
+ internal val allSources: MutableSet = mutableSetOf()
+
+ // TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
+ internal val commonSources: MutableSet = mutableSetOf()
+
+ var isTestCompilation = false
+
+ var friendCompilationName: String? = null
+
+ internal val friendCompilation: KotlinNativeCompilation?
+ get() = friendCompilationName?.let {
+ target.compilations.getByName(it)
+ }
+
+ // Used only to support the old APIs. TODO: Remove when the old APIs are removed.
+ internal val binaries = mutableMapOf, NativeBinary>()
+
+ // Native-specific DSL.
+ var extraOpts = mutableListOf()
+
+ fun extraOpts(vararg values: Any) = extraOpts(values.toList())
+ fun extraOpts(values: List) {
+ extraOpts.addAll(values.map { it.toString() })
+ }
+
+ var buildTypes = mutableListOf()
+ var outputKinds = mutableListOf()
+
+ fun outputKind(kind: NativeOutputKind) = outputKinds.add(kind)
+
+ fun outputKinds(vararg kinds: NativeOutputKind) {
+ outputKinds = kinds.toMutableList()
+ }
+
+ fun outputKinds(vararg kinds: String) {
+ outputKinds = kinds.map { NativeOutputKind.valueOf(it.toUpperCase()) }.toMutableList()
+ }
+
+ fun outputKinds(kinds: List) {
+ outputKinds = kinds.map {
+ when (it) {
+ is NativeOutputKind -> it
+ is String -> NativeOutputKind.valueOf(it.toUpperCase())
+ else -> error("Cannot use $it as an output kind")
+ }
+ }.toMutableList()
+ }
+
+ var entryPoint: String? = null
+ fun entryPoint(value: String) {
+ entryPoint = value
+ }
+
+ // Interop DSL.
+ val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
+ DefaultCInteropSettings(project, cinteropName, this)
+ }
+
+ var linkerOpts = mutableListOf()
+
+ fun cinterops(action: NamedDomainObjectContainer.() -> Unit) = cinterops.action()
+ fun cinterops(action: Closure) = cinterops(ConfigureUtil.configureUsing(action))
+ fun cinterops(action: Action>) = action.execute(cinterops)
+
+ fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
+ fun linkerOpts(values: List) {
+ linkerOpts.addAll(values)
+ }
+
+ // Task accessors.
+ fun findLinkTask(kind: NativeOutputKind, buildType: NativeBuildType): KotlinNativeLink? = binaries[kind to buildType]?.linkTask
+
+ fun getLinkTask(kind: NativeOutputKind, buildType: NativeBuildType): KotlinNativeLink =
+ findLinkTask(kind, buildType)
+ ?: throw IllegalArgumentException("Cannot find a link task for the binary kind '$kind' and the build type '$buildType'")
+
+ fun findLinkTask(kind: String, buildType: String) =
+ findLinkTask(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun getLinkTask(kind: String, buildType: String) =
+ getLinkTask(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun findBinary(kind: NativeOutputKind, buildType: NativeBuildType): File? = findLinkTask(kind, buildType)?.outputFile?.get()
+
+ fun getBinary(kind: NativeOutputKind, buildType: NativeBuildType): File = getLinkTask(kind, buildType).outputFile.get()
+
+ fun findBinary(kind: String, buildType: String) =
+ findBinary(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun getBinary(kind: String, buildType: String) =
+ getBinary(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ // Naming
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ fun linkTaskName(kind: NativeOutputKind, buildType: NativeBuildType): String =
+ lowerCamelCaseName(
+ "link",
+ KotlinNativeBinaryContainer.generateBinaryName(compilationName, buildType, kind.taskNameClassifier),
+ target.targetName
+ )
+
+ fun linkTaskName(kind: String, buildType: String) =
+ linkTaskName(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ override val compileDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
+ "compileKlibraries"
+ )
+
+ override val compileAllTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "klibrary")
+
+ val binariesTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "binaries")
+
+ override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
+ allSources.add(sourceSet.kotlin)
+ if (addAsCommonSources) {
+ commonSources.add(sourceSet.kotlin)
+ }
+ }
+}
+
+private object CompilationSourceSetUtil {
+ // Cache the results per project
+ private val projectSourceSetsInMultipleCompilationsCache = WeakHashMap>()
+
+ fun sourceSetsInMultipleCompilations(project: Project) =
+ projectSourceSetsInMultipleCompilationsCache.computeIfAbsent(project) { _ ->
+ check(project.state.executed) { "Should only be computed after the project is evaluated" }
+
+ val compilations = (project.kotlinExtension as? KotlinMultiplatformExtension)?.targets?.flatMap { it.compilations }
+ ?: return@computeIfAbsent null
+
+ compilations
+ .flatMap { compilation -> compilation.allKotlinSourceSets.map { sourceSet -> compilation to sourceSet } }
+ .groupingBy { (_, sourceSet) -> sourceSet }
+ .eachCount()
+ .filterValues { it > 1 }
+ .keys
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsCompilation.kt
new file mode 100644
index 00000000000..1284fe446f3
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsCompilation.kt
@@ -0,0 +1,471 @@
+ /*
+ * 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.Action
+import org.gradle.api.NamedDomainObjectContainer
+import org.gradle.api.Project
+import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.file.FileCollection
+import org.gradle.api.file.SourceDirectorySet
+import org.gradle.api.tasks.SourceSet
+import org.gradle.util.ConfigureUtil
+import org.jetbrains.kotlin.gradle.dsl.*
+import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
+import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
+import org.jetbrains.kotlin.gradle.tasks.*
+import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+import java.io.File
+import java.util.*
+import java.util.concurrent.Callable
+
+internal fun KotlinCompilation<*>.composeName(prefix: String? = null, suffix: String? = null): String {
+ val compilationNamePart = compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }
+ val targetNamePart = target.disambiguationClassifier
+
+ return lowerCamelCaseName(prefix, targetNamePart, compilationNamePart, suffix)
+}
+
+internal val KotlinCompilation<*>.defaultSourceSetName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName)
+
+abstract class AbstractKotlinCompilation(
+ target: KotlinTarget,
+ override val compilationName: String
+) : KotlinCompilation, HasKotlinDependencies {
+
+ override val kotlinOptions: T
+ get() = compileKotlinTask.kotlinOptions
+
+ override fun kotlinOptions(configure: T.() -> Unit) =
+ configure(kotlinOptions)
+
+ @Suppress("UNCHECKED_CAST")
+ override val compileKotlinTask: KotlinCompile
+ get() = (target.project.tasks.getByName(compileKotlinTaskName) as KotlinCompile)
+
+ // Don't declare this property in the constructor to avoid NPE
+ // when an overriding property of a subclass is accessed instead.
+ override val target: KotlinTarget = target
+
+ private val attributeContainer = HierarchyAttributeContainer(target.attributes)
+
+ override fun getAttributes(): AttributeContainer = attributeContainer
+
+ override val kotlinSourceSets: MutableSet = mutableSetOf()
+
+ override val allKotlinSourceSets: Set
+ get() = kotlinSourceSets.flatMapTo(mutableSetOf()) { it.getSourceSetHierarchy() }
+
+ override val defaultSourceSet: KotlinSourceSet
+ get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName)
+
+ override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) =
+ configure(defaultSourceSet)
+
+ override val output: KotlinCompilationOutput by lazy {
+ DefaultKotlinCompilationOutput(
+ target.project,
+ Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
+ }
+
+ open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
+ fun AbstractKotlinCompile<*>.configureAction() {
+ source(sourceSet.kotlin)
+ sourceFilesExtensions(sourceSet.customSourceFilesExtensions)
+ if (addAsCommonSources) {
+ commonSourceSet += sourceSet.kotlin
+ }
+ }
+
+ // Note! Invocation of withType-all results in preliminary task instantiation.
+ // After fix of this issue the following code should be uncommented:
+// if (useLazyTaskConfiguration) {
+// (target.project.tasks.named(compileKotlinTaskName) as TaskProvider>).configure {
+// it.configureAction()
+// }
+// }
+
+ target.project.tasks
+ // To configure a task that may have not yet been created at this point, use 'withType-matching-all`:
+ .withType(AbstractKotlinCompile::class.java)
+ .matching { it.name == compileKotlinTaskName }
+ .all { compileKotlinTask ->
+ compileKotlinTask.configureAction()
+ }
+ }
+
+ override fun source(sourceSet: KotlinSourceSet) {
+ if (kotlinSourceSets.add(sourceSet)) {
+ //TODO possibly issue with forced instantiation
+ target.project.whenEvaluated {
+ sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
+ val isCommonSource =
+ CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false
+
+ addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
+
+ // Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
+ // old Java & Android projects:
+ addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
+ addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
+ addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
+
+ if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
+ addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
+ }
+
+ if (sourceSet.name != defaultSourceSetName) {
+ kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
+ // Temporary solution for checking consistency across source sets participating in a compilation that may
+ // not be interconnected with the dependsOn relation: check the settings as if the default source set of
+ // the compilation depends on the one added to the compilation:
+ defaultSourceSetLanguageSettingsChecker.runAllChecks(
+ defaultSourceSet,
+ sourceSet
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override val compileDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
+ "compileClasspath"
+ )
+
+ override val compileKotlinTaskName: String
+ get() = lowerCamelCaseName(
+ "compile",
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "Kotlin",
+ target.targetName
+ )
+
+ override val compileAllTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "classes")
+
+ override lateinit var compileDependencyFiles: FileCollection
+
+ override val apiConfigurationName: String
+ get() = disambiguateName("api")
+
+ override val implementationConfigurationName: String
+ get() = disambiguateName("implementation")
+
+ override val compileOnlyConfigurationName: String
+ get() = disambiguateName("compileOnly")
+
+ override val runtimeOnlyConfigurationName: String
+ get() = disambiguateName("runtimeOnly")
+
+ override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
+ DefaultKotlinDependencyHandler(this, target.project).run(configure)
+
+ override fun dependencies(configureClosure: Closure) =
+ dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
+
+ override fun toString(): String = "compilation '$compilationName' ($target)"
+}
+
+abstract class AbstractKotlinCompilationToRunnableFiles(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name), KotlinCompilationToRunnableFiles {
+ override val runtimeDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "runtimeClasspath"
+ )
+
+ override lateinit var runtimeDependencyFiles: FileCollection
+}
+
+internal fun KotlinCompilation<*>.disambiguateName(simpleName: String): String {
+ return lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ simpleName
+ )
+}
+
+open class KotlinJvmCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+ get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+}
+
+class KotlinWithJavaCompilation(
+ target: KotlinWithJavaTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ lateinit var javaSourceSet: SourceSet
+
+ override val output: KotlinCompilationOutput by lazy { KotlinWithJavaCompilationOutput(this) }
+
+ override val processResourcesTaskName: String
+ get() = javaSourceSet.processResourcesTaskName
+
+ override var runtimeDependencyFiles: FileCollection
+ get() = javaSourceSet.runtimeClasspath
+ set(value) {
+ javaSourceSet.runtimeClasspath = value
+ }
+
+ override val runtimeDependencyConfigurationName: String
+ get() = javaSourceSet.runtimeClasspathConfigurationName
+
+ override val compileDependencyConfigurationName: String
+ get() = javaSourceSet.compileClasspathConfigurationName
+
+ override val runtimeOnlyConfigurationName: String
+ get() = javaSourceSet.runtimeOnlyConfigurationName
+
+ override val implementationConfigurationName: String
+ get() = javaSourceSet.implementationConfigurationName
+
+ override val apiConfigurationName: String
+ get() = javaSourceSet.apiConfigurationName
+
+ override val compileOnlyConfigurationName: String
+ get() = javaSourceSet.compileOnlyConfigurationName
+
+ override val compileAllTaskName: String
+ get() = javaSourceSet.classesTaskName
+
+ override var compileDependencyFiles: FileCollection
+ get() = javaSourceSet.compileClasspath
+ set(value) {
+ javaSourceSet.compileClasspath = value
+ }
+
+ fun source(javaSourceSet: SourceSet) {
+ with(target.project) {
+ afterEvaluate {
+ (tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(javaSourceSet.java)
+ }
+ }
+ }
+}
+
+class KotlinJvmAndroidCompilation(
+ target: KotlinAndroidTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name) {
+ override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+ get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+ override val relatedConfigurationNames: List
+ get() = super.relatedConfigurationNames + listOf("${name}ApiElements", "${name}RuntimeElements")
+}
+
+class KotlinJsCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ override val compileKotlinTask: Kotlin2JsCompile
+ get() = super.compileKotlinTask as Kotlin2JsCompile
+}
+
+class KotlinCommonCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name) {
+ override val compileKotlinTask: KotlinCompileCommon
+ get() = super.compileKotlinTask as KotlinCompileCommon
+
+ // TODO once we properly compile metadata for each source set, the default source sets will likely become just the source sets
+ // which are transformed to metadata
+ private val commonSourceSetName = when (compilationName) {
+ KotlinCompilation.MAIN_COMPILATION_NAME -> KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
+ else -> error("Custom metadata compilations are not supported yet")
+ }
+
+ override val defaultSourceSet: KotlinSourceSet
+ get() = target.project.kotlinExtension.sourceSets.getByName(commonSourceSetName)
+}
+
+class KotlinNativeCompilation(
+ override val target: KotlinNativeTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name), KotlinCompilationWithResources {
+
+ override val kotlinOptions: KotlinCommonOptions
+ get() = compileKotlinTask.kotlinOptions
+
+ override val compileKotlinTask: KotlinNativeCompile
+ get() = super.compileKotlinTask as KotlinNativeCompile
+
+ private val project: Project
+ get() = target.project
+
+ // A collection containing all source sets used by this compilation
+ // (taking into account dependencies between source sets). Used by both compilation
+ // and linking tasks. Unlike kotlinSourceSets, includes dependency source sets.
+ // TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
+ internal val allSources: MutableSet = mutableSetOf()
+
+ // TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
+ internal val commonSources: MutableSet = mutableSetOf()
+
+ var isTestCompilation = false
+
+ var friendCompilationName: String? = null
+
+ internal val friendCompilation: KotlinNativeCompilation?
+ get() = friendCompilationName?.let {
+ target.compilations.getByName(it)
+ }
+
+ // Used only to support the old APIs. TODO: Remove when the old APIs are removed.
+ internal val binaries = mutableMapOf, NativeBinary>()
+
+ // Native-specific DSL.
+ var extraOpts = mutableListOf()
+
+ fun extraOpts(vararg values: Any) = extraOpts(values.toList())
+ fun extraOpts(values: List) {
+ extraOpts.addAll(values.map { it.toString() })
+ }
+
+ var buildTypes = mutableListOf()
+ var outputKinds = mutableListOf()
+
+ fun outputKind(kind: NativeOutputKind) = outputKinds.add(kind)
+
+ fun outputKinds(vararg kinds: NativeOutputKind) {
+ outputKinds = kinds.toMutableList()
+ }
+
+ fun outputKinds(vararg kinds: String) {
+ outputKinds = kinds.map { NativeOutputKind.valueOf(it.toUpperCase()) }.toMutableList()
+ }
+
+ fun outputKinds(kinds: List) {
+ outputKinds = kinds.map {
+ when (it) {
+ is NativeOutputKind -> it
+ is String -> NativeOutputKind.valueOf(it.toUpperCase())
+ else -> error("Cannot use $it as an output kind")
+ }
+ }.toMutableList()
+ }
+
+ var entryPoint: String? = null
+ fun entryPoint(value: String) {
+ entryPoint = value
+ }
+
+ // Interop DSL.
+ val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
+ DefaultCInteropSettings(project, cinteropName, this)
+ }
+
+ var linkerOpts = mutableListOf()
+
+ fun cinterops(action: NamedDomainObjectContainer.() -> Unit) = cinterops.action()
+ fun cinterops(action: Closure) = cinterops(ConfigureUtil.configureUsing(action))
+ fun cinterops(action: Action>) = action.execute(cinterops)
+
+ fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
+ fun linkerOpts(values: List) {
+ linkerOpts.addAll(values)
+ }
+
+ // Task accessors.
+ fun findLinkTask(kind: NativeOutputKind, buildType: NativeBuildType): KotlinNativeLink? = binaries[kind to buildType]?.linkTask
+
+ fun getLinkTask(kind: NativeOutputKind, buildType: NativeBuildType): KotlinNativeLink =
+ findLinkTask(kind, buildType)
+ ?: throw IllegalArgumentException("Cannot find a link task for the binary kind '$kind' and the build type '$buildType'")
+
+ fun findLinkTask(kind: String, buildType: String) =
+ findLinkTask(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun getLinkTask(kind: String, buildType: String) =
+ getLinkTask(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun findBinary(kind: NativeOutputKind, buildType: NativeBuildType): File? = findLinkTask(kind, buildType)?.outputFile?.get()
+
+ fun getBinary(kind: NativeOutputKind, buildType: NativeBuildType): File = getLinkTask(kind, buildType).outputFile.get()
+
+ fun findBinary(kind: String, buildType: String) =
+ findBinary(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun getBinary(kind: String, buildType: String) =
+ getBinary(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ // Naming
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ fun linkTaskName(kind: NativeOutputKind, buildType: NativeBuildType): String =
+ lowerCamelCaseName(
+ "link",
+ KotlinNativeBinaryContainer.generateBinaryName(compilationName, buildType, kind.taskNameClassifier),
+ target.targetName
+ )
+
+ fun linkTaskName(kind: String, buildType: String) =
+ linkTaskName(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ override val compileDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
+ "compileKlibraries"
+ )
+
+ override val compileAllTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "klibrary")
+
+ val binariesTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "binaries")
+
+ override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
+ allSources.add(sourceSet.kotlin)
+ if (addAsCommonSources) {
+ commonSources.add(sourceSet.kotlin)
+ }
+ }
+}
+
+private object CompilationSourceSetUtil {
+ // Cache the results per project
+ private val projectSourceSetsInMultipleCompilationsCache = WeakHashMap>()
+
+ fun sourceSetsInMultipleCompilations(project: Project) =
+ projectSourceSetsInMultipleCompilationsCache.computeIfAbsent(project) { _ ->
+ check(project.state.executed) { "Should only be computed after the project is evaluated" }
+
+ val compilations = (project.kotlinExtension as? KotlinMultiplatformExtension)?.targets?.flatMap { it.compilations }
+ ?: return@computeIfAbsent null
+
+ compilations
+ .flatMap { compilation -> compilation.allKotlinSourceSets.map { sourceSet -> compilation to sourceSet } }
+ .groupingBy { (_, sourceSet) -> sourceSet }
+ .eachCount()
+ .filterValues { it > 1 }
+ .keys
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsCompilationFactory.kt
new file mode 100644
index 00000000000..e63b6e6573d
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsCompilationFactory.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.NamedDomainObjectFactory
+import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+
+interface KotlinCompilationFactory> : NamedDomainObjectFactory {
+ val itemClass: Class
+}
+
+class KotlinCommonCompilationFactory(
+ val target: KotlinOnlyTarget
+) : KotlinCompilationFactory {
+ override val itemClass: Class
+ get() = KotlinCommonCompilation::class.java
+
+ override fun create(name: String): KotlinCommonCompilation =
+ KotlinCommonCompilation(target, name)
+}
+
+class KotlinJvmCompilationFactory(
+ val target: KotlinOnlyTarget
+) : KotlinCompilationFactory {
+ override val itemClass: Class
+ get() = KotlinJvmCompilation::class.java
+
+ override fun create(name: String): KotlinJvmCompilation =
+ KotlinJvmCompilation(target, name)
+}
+
+class KotlinWithJavaCompilationFactory(
+ val project: Project,
+ val target: KotlinWithJavaTarget
+) : KotlinCompilationFactory> {
+
+ override val itemClass: Class>
+ @Suppress("UNCHECKED_CAST")
+ get() = KotlinWithJavaCompilation::class.java as Class>
+
+ override fun create(name: String): KotlinWithJavaCompilation {
+ val result = KotlinWithJavaCompilation(target, name)
+ return result
+ }
+}
+
+class KotlinJvmAndroidCompilationFactory(
+ val project: Project,
+ val target: KotlinAndroidTarget
+) : KotlinCompilationFactory {
+
+ override val itemClass: Class
+ get() = KotlinJvmAndroidCompilation::class.java
+
+ override fun create(name: String): KotlinJvmAndroidCompilation =
+ KotlinJvmAndroidCompilation(target, name)
+}
+
+class KotlinJsCompilationFactory(
+ val project: Project,
+ val target: KotlinOnlyTarget
+) : KotlinCompilationFactory {
+ override val itemClass: Class
+ get() = KotlinJsCompilation::class.java
+
+ override fun create(name: String): KotlinJsCompilation =
+ KotlinJsCompilation(target, name)
+}
+
+class KotlinNativeCompilationFactory(
+ val project: Project,
+ val target: KotlinNativeTarget
+) : KotlinCompilationFactory {
+
+ override val itemClass: Class
+ get() = KotlinNativeCompilation::class.java
+
+ override fun create(name: String): KotlinNativeCompilation =
+ KotlinNativeCompilation(target, name).apply {
+ if (name == KotlinCompilation.TEST_COMPILATION_NAME) {
+ friendCompilationName = KotlinCompilation.MAIN_COMPILATION_NAME
+ isTestCompilation = true
+ }
+ buildTypes = mutableListOf(NativeBuildType.DEBUG, NativeBuildType.RELEASE)
+ }
+
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsTargetPreset.kt
new file mode 100644
index 00000000000..921736ad861
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJsTargetPreset.kt
@@ -0,0 +1,330 @@
+/*
+ * 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.Dependency
+import org.gradle.api.internal.file.FileResolver
+import org.gradle.api.plugins.JavaPlugin
+import org.gradle.internal.reflect.Instantiator
+import org.jetbrains.kotlin.compilerRunner.KotlinNativeProjectProperty
+import org.jetbrains.kotlin.compilerRunner.hasProperty
+import org.jetbrains.kotlin.compilerRunner.konanHome
+import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
+import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
+import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask
+import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
+import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
+import org.jetbrains.kotlin.konan.KonanVersion
+import org.jetbrains.kotlin.konan.target.HostManager
+import org.jetbrains.kotlin.konan.target.KonanTarget
+import java.io.File
+import java.util.*
+
+abstract class KotlinOnlyTargetPreset>(
+ protected val project: Project,
+ private val instantiator: Instantiator,
+ private val fileResolver: FileResolver,
+ protected val kotlinPluginVersion: String
+) : KotlinTargetPreset> {
+
+ protected open fun createKotlinTargetConfigurator(): KotlinTargetConfigurator =
+ KotlinTargetConfigurator(createDefaultSourceSets = true, createTestCompilation = true)
+
+ override fun createTarget(name: String): KotlinOnlyTarget {
+ val result = KotlinOnlyTarget(project, platformType).apply {
+ targetName = name
+ disambiguationClassifier = name
+ preset = this@KotlinOnlyTargetPreset
+
+ val compilationFactory = createCompilationFactory(this)
+ compilations = project.container(compilationFactory.itemClass, compilationFactory)
+ }
+
+ createKotlinTargetConfigurator().configureTarget(result)
+
+ result.compilations.all { compilation ->
+ buildCompilationProcessor(compilation).run()
+ if (compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME) {
+ sourcesJarTask(compilation, result.targetName, result.targetName.toLowerCase())
+ }
+ }
+
+ return result
+ }
+
+ protected abstract fun createCompilationFactory(forTarget: KotlinOnlyTarget): KotlinCompilationFactory
+ protected abstract val platformType: KotlinPlatformType
+ internal abstract fun buildCompilationProcessor(compilation: T): KotlinSourceSetProcessor<*>
+}
+
+class KotlinMetadataTargetPreset(
+ project: Project,
+ instantiator: Instantiator,
+ fileResolver: FileResolver,
+ kotlinPluginVersion: String
+) : KotlinOnlyTargetPreset(
+ project,
+ instantiator,
+ fileResolver,
+ kotlinPluginVersion
+) {
+ override fun getName(): String = PRESET_NAME
+
+ override fun createCompilationFactory(
+ forTarget: KotlinOnlyTarget
+ ): KotlinCompilationFactory =
+ KotlinCommonCompilationFactory(forTarget)
+
+ override val platformType: KotlinPlatformType
+ get() = KotlinPlatformType.common
+
+ override fun buildCompilationProcessor(compilation: KotlinCommonCompilation): KotlinSourceSetProcessor<*> {
+ val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
+ return KotlinCommonSourceSetProcessor(project, compilation, tasksProvider, kotlinPluginVersion)
+ }
+
+ companion object {
+ const val PRESET_NAME = "metadata"
+ }
+
+ override fun createKotlinTargetConfigurator(): KotlinTargetConfigurator =
+ KotlinTargetConfigurator(createDefaultSourceSets = false, createTestCompilation = false)
+
+ override fun createTarget(name: String): KotlinOnlyTarget =
+ super.createTarget(name).apply {
+ val mainCompilation = compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
+ val commonMainSourceSet = project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME)
+
+ mainCompilation.source(commonMainSourceSet)
+
+ project.afterEvaluate {
+ // Since there's no default source set, apply language settings from commonMain:
+ val compileKotlinMetadata = project.tasks.getByName(mainCompilation.compileKotlinTaskName) as KotlinCompile<*>
+ applyLanguageSettingsToKotlinTask(commonMainSourceSet.languageSettings, compileKotlinMetadata)
+ }
+ }
+}
+
+class KotlinJvmTargetPreset(
+ project: Project,
+ instantiator: Instantiator,
+ fileResolver: FileResolver,
+ kotlinPluginVersion: String
+) : KotlinOnlyTargetPreset(
+ project,
+ instantiator,
+ fileResolver,
+ kotlinPluginVersion
+) {
+ override fun getName(): String = PRESET_NAME
+
+ override fun createCompilationFactory(forTarget: KotlinOnlyTarget): KotlinCompilationFactory =
+ KotlinJvmCompilationFactory(forTarget)
+
+ override val platformType: KotlinPlatformType
+ get() = KotlinPlatformType.jvm
+
+ override fun buildCompilationProcessor(compilation: KotlinJvmCompilation): KotlinSourceSetProcessor<*> {
+ val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
+ return Kotlin2JvmSourceSetProcessor(project, tasksProvider, compilation, kotlinPluginVersion)
+ }
+
+ companion object {
+ const val PRESET_NAME = "jvm"
+ }
+}
+
+class KotlinJsTargetPreset(
+ project: Project,
+ instantiator: Instantiator,
+ fileResolver: FileResolver,
+ kotlinPluginVersion: String
+) : KotlinOnlyTargetPreset(
+ project,
+ instantiator,
+ fileResolver,
+ kotlinPluginVersion
+) {
+ override fun getName(): String = PRESET_NAME
+
+ override fun createCompilationFactory(forTarget: KotlinOnlyTarget) =
+ KotlinJsCompilationFactory(project, forTarget)
+
+ override val platformType: KotlinPlatformType
+ get() = KotlinPlatformType.js
+
+ override fun buildCompilationProcessor(compilation: KotlinJsCompilation): KotlinSourceSetProcessor<*> {
+ val tasksProvider = KotlinTasksProvider(compilation.target.targetName)
+ return Kotlin2JsSourceSetProcessor(project, tasksProvider, compilation, kotlinPluginVersion)
+ }
+
+ companion object {
+ const val PRESET_NAME = "js"
+ }
+}
+
+class KotlinAndroidTargetPreset(
+ private val project: Project,
+ private val kotlinPluginVersion: String
+) : KotlinTargetPreset {
+
+ override fun getName(): String = PRESET_NAME
+
+ override fun createTarget(name: String): KotlinAndroidTarget {
+ val result = KotlinAndroidTarget(name, project).apply {
+ disambiguationClassifier = name
+ preset = this@KotlinAndroidTargetPreset
+ }
+
+ KotlinAndroidPlugin.applyToTarget(kotlinPluginVersion, result)
+ return result
+ }
+
+ companion object {
+ const val PRESET_NAME = "android"
+ }
+}
+
+class KotlinJvmWithJavaTargetPreset(
+ private val project: Project,
+ private val kotlinPluginVersion: String
+) : KotlinTargetPreset> {
+
+ 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
+ preset = this@KotlinJvmWithJavaTargetPreset
+ }
+
+ AbstractKotlinPlugin.configureTarget(target) { compilation ->
+ Kotlin2JvmSourceSetProcessor(project, KotlinTasksProvider(name), compilation, kotlinPluginVersion)
+ }
+
+ target.compilations.getByName("test").run {
+ val main = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
+
+ compileDependencyFiles = project.files(
+ main.output.allOutputs,
+ project.configurations.maybeCreate(compileDependencyConfigurationName)
+ )
+ runtimeDependencyFiles = project.files(
+ output.allOutputs,
+ main.output.allOutputs,
+ project.configurations.maybeCreate(runtimeDependencyConfigurationName)
+ )
+ }
+
+ return target
+ }
+
+ companion object {
+ const val PRESET_NAME = "jvmWithJava"
+ }
+}
+
+class KotlinNativeTargetPreset(
+ private val name: String,
+ val project: Project,
+ val konanTarget: KonanTarget,
+ private val kotlinPluginVersion: String
+) : KotlinTargetPreset {
+
+ init {
+ // This is required to obtain Kotlin/Native home in CLion plugin:
+ setupNativeHomePrivateProperty()
+ }
+
+ override fun getName(): String = name
+
+ private fun setupNativeHomePrivateProperty() = with(project) {
+ if (!hasProperty(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY))
+ extensions.extraProperties.set(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY, konanHome)
+ }
+
+ private fun setupNativeCompiler() = with(project) {
+ if (!hasProperty(KotlinNativeProjectProperty.KONAN_HOME_OVERRIDE)) {
+ NativeCompilerDownloader(this).downloadIfNeeded()
+ logger.info("Kotlin/Native distribution: $konanHome")
+ } else {
+ logger.info("User-provided Kotlin/Native distribution: $konanHome")
+ }
+ }
+
+ // We declare default K/N dependencies as files to avoid searching them in remote repos (see KT-28128).
+ private fun defaultLibs(target: KonanTarget? = null): List = with(project) {
+
+ val relPath = if (target != null) "platform/${target.name}" else "common"
+
+ file("$konanHome/klib/$relPath")
+ .listFiles { file -> file.isDirectory }
+ ?.sortedBy { dir -> dir.name.toLowerCase() }
+ ?.map { dir -> dependencies.create(files(dir)) } ?: emptyList()
+ }
+
+ override fun createTarget(name: String): KotlinNativeTarget {
+ setupNativeCompiler()
+
+ val result = KotlinNativeTarget(project, konanTarget).apply {
+ targetName = name
+ disambiguationClassifier = name
+ preset = this@KotlinNativeTargetPreset
+
+ val compilationFactory = KotlinNativeCompilationFactory(project, this)
+ compilations = project.container(compilationFactory.itemClass, compilationFactory)
+ }
+
+ KotlinNativeTargetConfigurator(kotlinPluginVersion).configureTarget(result)
+
+ // Allow IDE to resolve the libraries provided by the compiler by adding them into dependencies.
+ result.compilations.all { compilation ->
+ val target = compilation.target.konanTarget
+ // First, put common libs:
+ defaultLibs().forEach {
+ project.dependencies.add(compilation.compileDependencyConfigurationName, it)
+ }
+ // Then, platform-specific libs:
+ defaultLibs(target).forEach {
+ project.dependencies.add(compilation.compileDependencyConfigurationName, it)
+ }
+ }
+
+ if (!konanTarget.enabledOnCurrentHost) {
+ with(HostManager()) {
+ val supportedHosts = enabledTargetsByHost.filterValues { konanTarget in it }.keys
+ val supportedHostsString =
+ if (supportedHosts.size == 1)
+ "a ${supportedHosts.single()} host" else
+ "one of the host platforms: ${supportedHosts.joinToString(", ")}"
+ project.logger.warn(
+ "Target '$name' for platform ${konanTarget} is ignored during build on this ${HostManager.host} machine. " +
+ "You can build it with $supportedHostsString."
+ )
+ }
+ }
+
+ return result
+ }
+
+ companion object {
+ private const val KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY = "konanHome"
+ }
+}
+
+internal val KonanTarget.isCurrentHost: Boolean
+ get() = this == HostManager.host
+
+internal val KonanTarget.enabledOnCurrentHost
+ get() = HostManager().isEnabled(this)
+
+internal val KotlinNativeCompilation.isMainCompilation: Boolean
+ get() = name == KotlinCompilation.MAIN_COMPILATION_NAME
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmAndroidCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmAndroidCompilation.kt
new file mode 100644
index 00000000000..1284fe446f3
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmAndroidCompilation.kt
@@ -0,0 +1,471 @@
+ /*
+ * 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.Action
+import org.gradle.api.NamedDomainObjectContainer
+import org.gradle.api.Project
+import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.file.FileCollection
+import org.gradle.api.file.SourceDirectorySet
+import org.gradle.api.tasks.SourceSet
+import org.gradle.util.ConfigureUtil
+import org.jetbrains.kotlin.gradle.dsl.*
+import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
+import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
+import org.jetbrains.kotlin.gradle.tasks.*
+import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+import java.io.File
+import java.util.*
+import java.util.concurrent.Callable
+
+internal fun KotlinCompilation<*>.composeName(prefix: String? = null, suffix: String? = null): String {
+ val compilationNamePart = compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }
+ val targetNamePart = target.disambiguationClassifier
+
+ return lowerCamelCaseName(prefix, targetNamePart, compilationNamePart, suffix)
+}
+
+internal val KotlinCompilation<*>.defaultSourceSetName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName)
+
+abstract class AbstractKotlinCompilation(
+ target: KotlinTarget,
+ override val compilationName: String
+) : KotlinCompilation, HasKotlinDependencies {
+
+ override val kotlinOptions: T
+ get() = compileKotlinTask.kotlinOptions
+
+ override fun kotlinOptions(configure: T.() -> Unit) =
+ configure(kotlinOptions)
+
+ @Suppress("UNCHECKED_CAST")
+ override val compileKotlinTask: KotlinCompile
+ get() = (target.project.tasks.getByName(compileKotlinTaskName) as KotlinCompile)
+
+ // Don't declare this property in the constructor to avoid NPE
+ // when an overriding property of a subclass is accessed instead.
+ override val target: KotlinTarget = target
+
+ private val attributeContainer = HierarchyAttributeContainer(target.attributes)
+
+ override fun getAttributes(): AttributeContainer = attributeContainer
+
+ override val kotlinSourceSets: MutableSet = mutableSetOf()
+
+ override val allKotlinSourceSets: Set
+ get() = kotlinSourceSets.flatMapTo(mutableSetOf()) { it.getSourceSetHierarchy() }
+
+ override val defaultSourceSet: KotlinSourceSet
+ get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName)
+
+ override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) =
+ configure(defaultSourceSet)
+
+ override val output: KotlinCompilationOutput by lazy {
+ DefaultKotlinCompilationOutput(
+ target.project,
+ Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
+ }
+
+ open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
+ fun AbstractKotlinCompile<*>.configureAction() {
+ source(sourceSet.kotlin)
+ sourceFilesExtensions(sourceSet.customSourceFilesExtensions)
+ if (addAsCommonSources) {
+ commonSourceSet += sourceSet.kotlin
+ }
+ }
+
+ // Note! Invocation of withType-all results in preliminary task instantiation.
+ // After fix of this issue the following code should be uncommented:
+// if (useLazyTaskConfiguration) {
+// (target.project.tasks.named(compileKotlinTaskName) as TaskProvider>).configure {
+// it.configureAction()
+// }
+// }
+
+ target.project.tasks
+ // To configure a task that may have not yet been created at this point, use 'withType-matching-all`:
+ .withType(AbstractKotlinCompile::class.java)
+ .matching { it.name == compileKotlinTaskName }
+ .all { compileKotlinTask ->
+ compileKotlinTask.configureAction()
+ }
+ }
+
+ override fun source(sourceSet: KotlinSourceSet) {
+ if (kotlinSourceSets.add(sourceSet)) {
+ //TODO possibly issue with forced instantiation
+ target.project.whenEvaluated {
+ sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
+ val isCommonSource =
+ CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false
+
+ addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
+
+ // Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
+ // old Java & Android projects:
+ addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
+ addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
+ addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
+
+ if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
+ addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
+ }
+
+ if (sourceSet.name != defaultSourceSetName) {
+ kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
+ // Temporary solution for checking consistency across source sets participating in a compilation that may
+ // not be interconnected with the dependsOn relation: check the settings as if the default source set of
+ // the compilation depends on the one added to the compilation:
+ defaultSourceSetLanguageSettingsChecker.runAllChecks(
+ defaultSourceSet,
+ sourceSet
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override val compileDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
+ "compileClasspath"
+ )
+
+ override val compileKotlinTaskName: String
+ get() = lowerCamelCaseName(
+ "compile",
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "Kotlin",
+ target.targetName
+ )
+
+ override val compileAllTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "classes")
+
+ override lateinit var compileDependencyFiles: FileCollection
+
+ override val apiConfigurationName: String
+ get() = disambiguateName("api")
+
+ override val implementationConfigurationName: String
+ get() = disambiguateName("implementation")
+
+ override val compileOnlyConfigurationName: String
+ get() = disambiguateName("compileOnly")
+
+ override val runtimeOnlyConfigurationName: String
+ get() = disambiguateName("runtimeOnly")
+
+ override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
+ DefaultKotlinDependencyHandler(this, target.project).run(configure)
+
+ override fun dependencies(configureClosure: Closure) =
+ dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
+
+ override fun toString(): String = "compilation '$compilationName' ($target)"
+}
+
+abstract class AbstractKotlinCompilationToRunnableFiles(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name), KotlinCompilationToRunnableFiles {
+ override val runtimeDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "runtimeClasspath"
+ )
+
+ override lateinit var runtimeDependencyFiles: FileCollection
+}
+
+internal fun KotlinCompilation<*>.disambiguateName(simpleName: String): String {
+ return lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ simpleName
+ )
+}
+
+open class KotlinJvmCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+ get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+}
+
+class KotlinWithJavaCompilation(
+ target: KotlinWithJavaTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ lateinit var javaSourceSet: SourceSet
+
+ override val output: KotlinCompilationOutput by lazy { KotlinWithJavaCompilationOutput(this) }
+
+ override val processResourcesTaskName: String
+ get() = javaSourceSet.processResourcesTaskName
+
+ override var runtimeDependencyFiles: FileCollection
+ get() = javaSourceSet.runtimeClasspath
+ set(value) {
+ javaSourceSet.runtimeClasspath = value
+ }
+
+ override val runtimeDependencyConfigurationName: String
+ get() = javaSourceSet.runtimeClasspathConfigurationName
+
+ override val compileDependencyConfigurationName: String
+ get() = javaSourceSet.compileClasspathConfigurationName
+
+ override val runtimeOnlyConfigurationName: String
+ get() = javaSourceSet.runtimeOnlyConfigurationName
+
+ override val implementationConfigurationName: String
+ get() = javaSourceSet.implementationConfigurationName
+
+ override val apiConfigurationName: String
+ get() = javaSourceSet.apiConfigurationName
+
+ override val compileOnlyConfigurationName: String
+ get() = javaSourceSet.compileOnlyConfigurationName
+
+ override val compileAllTaskName: String
+ get() = javaSourceSet.classesTaskName
+
+ override var compileDependencyFiles: FileCollection
+ get() = javaSourceSet.compileClasspath
+ set(value) {
+ javaSourceSet.compileClasspath = value
+ }
+
+ fun source(javaSourceSet: SourceSet) {
+ with(target.project) {
+ afterEvaluate {
+ (tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(javaSourceSet.java)
+ }
+ }
+ }
+}
+
+class KotlinJvmAndroidCompilation(
+ target: KotlinAndroidTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name) {
+ override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+ get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+
+ override val relatedConfigurationNames: List
+ get() = super.relatedConfigurationNames + listOf("${name}ApiElements", "${name}RuntimeElements")
+}
+
+class KotlinJsCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ override val compileKotlinTask: Kotlin2JsCompile
+ get() = super.compileKotlinTask as Kotlin2JsCompile
+}
+
+class KotlinCommonCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name) {
+ override val compileKotlinTask: KotlinCompileCommon
+ get() = super.compileKotlinTask as KotlinCompileCommon
+
+ // TODO once we properly compile metadata for each source set, the default source sets will likely become just the source sets
+ // which are transformed to metadata
+ private val commonSourceSetName = when (compilationName) {
+ KotlinCompilation.MAIN_COMPILATION_NAME -> KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
+ else -> error("Custom metadata compilations are not supported yet")
+ }
+
+ override val defaultSourceSet: KotlinSourceSet
+ get() = target.project.kotlinExtension.sourceSets.getByName(commonSourceSetName)
+}
+
+class KotlinNativeCompilation(
+ override val target: KotlinNativeTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name), KotlinCompilationWithResources {
+
+ override val kotlinOptions: KotlinCommonOptions
+ get() = compileKotlinTask.kotlinOptions
+
+ override val compileKotlinTask: KotlinNativeCompile
+ get() = super.compileKotlinTask as KotlinNativeCompile
+
+ private val project: Project
+ get() = target.project
+
+ // A collection containing all source sets used by this compilation
+ // (taking into account dependencies between source sets). Used by both compilation
+ // and linking tasks. Unlike kotlinSourceSets, includes dependency source sets.
+ // TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
+ internal val allSources: MutableSet = mutableSetOf()
+
+ // TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
+ internal val commonSources: MutableSet = mutableSetOf()
+
+ var isTestCompilation = false
+
+ var friendCompilationName: String? = null
+
+ internal val friendCompilation: KotlinNativeCompilation?
+ get() = friendCompilationName?.let {
+ target.compilations.getByName(it)
+ }
+
+ // Used only to support the old APIs. TODO: Remove when the old APIs are removed.
+ internal val binaries = mutableMapOf, NativeBinary>()
+
+ // Native-specific DSL.
+ var extraOpts = mutableListOf()
+
+ fun extraOpts(vararg values: Any) = extraOpts(values.toList())
+ fun extraOpts(values: List) {
+ extraOpts.addAll(values.map { it.toString() })
+ }
+
+ var buildTypes = mutableListOf()
+ var outputKinds = mutableListOf()
+
+ fun outputKind(kind: NativeOutputKind) = outputKinds.add(kind)
+
+ fun outputKinds(vararg kinds: NativeOutputKind) {
+ outputKinds = kinds.toMutableList()
+ }
+
+ fun outputKinds(vararg kinds: String) {
+ outputKinds = kinds.map { NativeOutputKind.valueOf(it.toUpperCase()) }.toMutableList()
+ }
+
+ fun outputKinds(kinds: List) {
+ outputKinds = kinds.map {
+ when (it) {
+ is NativeOutputKind -> it
+ is String -> NativeOutputKind.valueOf(it.toUpperCase())
+ else -> error("Cannot use $it as an output kind")
+ }
+ }.toMutableList()
+ }
+
+ var entryPoint: String? = null
+ fun entryPoint(value: String) {
+ entryPoint = value
+ }
+
+ // Interop DSL.
+ val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName ->
+ DefaultCInteropSettings(project, cinteropName, this)
+ }
+
+ var linkerOpts = mutableListOf()
+
+ fun cinterops(action: NamedDomainObjectContainer.() -> Unit) = cinterops.action()
+ fun cinterops(action: Closure) = cinterops(ConfigureUtil.configureUsing(action))
+ fun cinterops(action: Action>) = action.execute(cinterops)
+
+ fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
+ fun linkerOpts(values: List) {
+ linkerOpts.addAll(values)
+ }
+
+ // Task accessors.
+ fun findLinkTask(kind: NativeOutputKind, buildType: NativeBuildType): KotlinNativeLink? = binaries[kind to buildType]?.linkTask
+
+ fun getLinkTask(kind: NativeOutputKind, buildType: NativeBuildType): KotlinNativeLink =
+ findLinkTask(kind, buildType)
+ ?: throw IllegalArgumentException("Cannot find a link task for the binary kind '$kind' and the build type '$buildType'")
+
+ fun findLinkTask(kind: String, buildType: String) =
+ findLinkTask(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun getLinkTask(kind: String, buildType: String) =
+ getLinkTask(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun findBinary(kind: NativeOutputKind, buildType: NativeBuildType): File? = findLinkTask(kind, buildType)?.outputFile?.get()
+
+ fun getBinary(kind: NativeOutputKind, buildType: NativeBuildType): File = getLinkTask(kind, buildType).outputFile.get()
+
+ fun findBinary(kind: String, buildType: String) =
+ findBinary(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ fun getBinary(kind: String, buildType: String) =
+ getBinary(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ // Naming
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ fun linkTaskName(kind: NativeOutputKind, buildType: NativeBuildType): String =
+ lowerCamelCaseName(
+ "link",
+ KotlinNativeBinaryContainer.generateBinaryName(compilationName, buildType, kind.taskNameClassifier),
+ target.targetName
+ )
+
+ fun linkTaskName(kind: String, buildType: String) =
+ linkTaskName(NativeOutputKind.valueOf(kind.toUpperCase()), NativeBuildType.valueOf(buildType.toUpperCase()))
+
+ override val compileDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
+ "compileKlibraries"
+ )
+
+ override val compileAllTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "klibrary")
+
+ val binariesTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "binaries")
+
+ override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
+ allSources.add(sourceSet.kotlin)
+ if (addAsCommonSources) {
+ commonSources.add(sourceSet.kotlin)
+ }
+ }
+}
+
+private object CompilationSourceSetUtil {
+ // Cache the results per project
+ private val projectSourceSetsInMultipleCompilationsCache = WeakHashMap>()
+
+ fun sourceSetsInMultipleCompilations(project: Project) =
+ projectSourceSetsInMultipleCompilationsCache.computeIfAbsent(project) { _ ->
+ check(project.state.executed) { "Should only be computed after the project is evaluated" }
+
+ val compilations = (project.kotlinExtension as? KotlinMultiplatformExtension)?.targets?.flatMap { it.compilations }
+ ?: return@computeIfAbsent null
+
+ compilations
+ .flatMap { compilation -> compilation.allKotlinSourceSets.map { sourceSet -> compilation to sourceSet } }
+ .groupingBy { (_, sourceSet) -> sourceSet }
+ .eachCount()
+ .filterValues { it > 1 }
+ .keys
+ }
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmAndroidCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmAndroidCompilationFactory.kt
new file mode 100644
index 00000000000..e63b6e6573d
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmAndroidCompilationFactory.kt
@@ -0,0 +1,93 @@
+/*
+ * 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.NamedDomainObjectFactory
+import org.gradle.api.Project
+import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
+import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
+
+interface KotlinCompilationFactory> : NamedDomainObjectFactory {
+ val itemClass: Class
+}
+
+class KotlinCommonCompilationFactory(
+ val target: KotlinOnlyTarget
+) : KotlinCompilationFactory {
+ override val itemClass: Class
+ get() = KotlinCommonCompilation::class.java
+
+ override fun create(name: String): KotlinCommonCompilation =
+ KotlinCommonCompilation(target, name)
+}
+
+class KotlinJvmCompilationFactory(
+ val target: KotlinOnlyTarget
+) : KotlinCompilationFactory {
+ override val itemClass: Class
+ get() = KotlinJvmCompilation::class.java
+
+ override fun create(name: String): KotlinJvmCompilation =
+ KotlinJvmCompilation(target, name)
+}
+
+class KotlinWithJavaCompilationFactory(
+ val project: Project,
+ val target: KotlinWithJavaTarget
+) : KotlinCompilationFactory> {
+
+ override val itemClass: Class>
+ @Suppress("UNCHECKED_CAST")
+ get() = KotlinWithJavaCompilation::class.java as Class>
+
+ override fun create(name: String): KotlinWithJavaCompilation {
+ val result = KotlinWithJavaCompilation(target, name)
+ return result
+ }
+}
+
+class KotlinJvmAndroidCompilationFactory(
+ val project: Project,
+ val target: KotlinAndroidTarget
+) : KotlinCompilationFactory {
+
+ override val itemClass: Class
+ get() = KotlinJvmAndroidCompilation::class.java
+
+ override fun create(name: String): KotlinJvmAndroidCompilation =
+ KotlinJvmAndroidCompilation(target, name)
+}
+
+class KotlinJsCompilationFactory(
+ val project: Project,
+ val target: KotlinOnlyTarget
+) : KotlinCompilationFactory {
+ override val itemClass: Class
+ get() = KotlinJsCompilation::class.java
+
+ override fun create(name: String): KotlinJsCompilation =
+ KotlinJsCompilation(target, name)
+}
+
+class KotlinNativeCompilationFactory(
+ val project: Project,
+ val target: KotlinNativeTarget
+) : KotlinCompilationFactory {
+
+ override val itemClass: Class
+ get() = KotlinNativeCompilation::class.java
+
+ override fun create(name: String): KotlinNativeCompilation =
+ KotlinNativeCompilation(target, name).apply {
+ if (name == KotlinCompilation.TEST_COMPILATION_NAME) {
+ friendCompilationName = KotlinCompilation.MAIN_COMPILATION_NAME
+ isTestCompilation = true
+ }
+ buildTypes = mutableListOf(NativeBuildType.DEBUG, NativeBuildType.RELEASE)
+ }
+
+}
\ No newline at end of file
diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmCompilation.kt
new file mode 100644
index 00000000000..1284fe446f3
--- /dev/null
+++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinJvmCompilation.kt
@@ -0,0 +1,471 @@
+ /*
+ * 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.Action
+import org.gradle.api.NamedDomainObjectContainer
+import org.gradle.api.Project
+import org.gradle.api.attributes.AttributeContainer
+import org.gradle.api.file.FileCollection
+import org.gradle.api.file.SourceDirectorySet
+import org.gradle.api.tasks.SourceSet
+import org.gradle.util.ConfigureUtil
+import org.jetbrains.kotlin.gradle.dsl.*
+import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
+import org.jetbrains.kotlin.gradle.plugin.*
+import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker
+import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
+import org.jetbrains.kotlin.gradle.tasks.*
+import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
+import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
+import java.io.File
+import java.util.*
+import java.util.concurrent.Callable
+
+internal fun KotlinCompilation<*>.composeName(prefix: String? = null, suffix: String? = null): String {
+ val compilationNamePart = compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }
+ val targetNamePart = target.disambiguationClassifier
+
+ return lowerCamelCaseName(prefix, targetNamePart, compilationNamePart, suffix)
+}
+
+internal val KotlinCompilation<*>.defaultSourceSetName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName)
+
+abstract class AbstractKotlinCompilation(
+ target: KotlinTarget,
+ override val compilationName: String
+) : KotlinCompilation, HasKotlinDependencies {
+
+ override val kotlinOptions: T
+ get() = compileKotlinTask.kotlinOptions
+
+ override fun kotlinOptions(configure: T.() -> Unit) =
+ configure(kotlinOptions)
+
+ @Suppress("UNCHECKED_CAST")
+ override val compileKotlinTask: KotlinCompile
+ get() = (target.project.tasks.getByName(compileKotlinTaskName) as KotlinCompile)
+
+ // Don't declare this property in the constructor to avoid NPE
+ // when an overriding property of a subclass is accessed instead.
+ override val target: KotlinTarget = target
+
+ private val attributeContainer = HierarchyAttributeContainer(target.attributes)
+
+ override fun getAttributes(): AttributeContainer = attributeContainer
+
+ override val kotlinSourceSets: MutableSet = mutableSetOf()
+
+ override val allKotlinSourceSets: Set
+ get() = kotlinSourceSets.flatMapTo(mutableSetOf()) { it.getSourceSetHierarchy() }
+
+ override val defaultSourceSet: KotlinSourceSet
+ get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName)
+
+ override fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) =
+ configure(defaultSourceSet)
+
+ override val output: KotlinCompilationOutput by lazy {
+ DefaultKotlinCompilationOutput(
+ target.project,
+ Callable { target.project.buildDir.resolve("processedResources/${target.targetName}/$name") })
+ }
+
+ open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) {
+ fun AbstractKotlinCompile<*>.configureAction() {
+ source(sourceSet.kotlin)
+ sourceFilesExtensions(sourceSet.customSourceFilesExtensions)
+ if (addAsCommonSources) {
+ commonSourceSet += sourceSet.kotlin
+ }
+ }
+
+ // Note! Invocation of withType-all results in preliminary task instantiation.
+ // After fix of this issue the following code should be uncommented:
+// if (useLazyTaskConfiguration) {
+// (target.project.tasks.named(compileKotlinTaskName) as TaskProvider>).configure {
+// it.configureAction()
+// }
+// }
+
+ target.project.tasks
+ // To configure a task that may have not yet been created at this point, use 'withType-matching-all`:
+ .withType(AbstractKotlinCompile::class.java)
+ .matching { it.name == compileKotlinTaskName }
+ .all { compileKotlinTask ->
+ compileKotlinTask.configureAction()
+ }
+ }
+
+ override fun source(sourceSet: KotlinSourceSet) {
+ if (kotlinSourceSets.add(sourceSet)) {
+ //TODO possibly issue with forced instantiation
+ target.project.whenEvaluated {
+ sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
+ val isCommonSource =
+ CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false
+
+ addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource)
+
+ // Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
+ // old Java & Android projects:
+ addExtendsFromRelation(apiConfigurationName, sourceSet.apiConfigurationName, forced = false)
+ addExtendsFromRelation(implementationConfigurationName, sourceSet.implementationConfigurationName, forced = false)
+ addExtendsFromRelation(compileOnlyConfigurationName, sourceSet.compileOnlyConfigurationName, forced = false)
+
+ if (this@AbstractKotlinCompilation is KotlinCompilationToRunnableFiles<*>) {
+ addExtendsFromRelation(runtimeOnlyConfigurationName, sourceSet.runtimeOnlyConfigurationName, forced = false)
+ }
+
+ if (sourceSet.name != defaultSourceSetName) {
+ kotlinExtension.sourceSets.findByName(defaultSourceSetName)?.let { defaultSourceSet ->
+ // Temporary solution for checking consistency across source sets participating in a compilation that may
+ // not be interconnected with the dependsOn relation: check the settings as if the default source set of
+ // the compilation depends on the one added to the compilation:
+ defaultSourceSetLanguageSettingsChecker.runAllChecks(
+ defaultSourceSet,
+ sourceSet
+ )
+ }
+ }
+ }
+ }
+ }
+ }
+
+ override val compileDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
+ "compileClasspath"
+ )
+
+ override val compileKotlinTaskName: String
+ get() = lowerCamelCaseName(
+ "compile",
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "Kotlin",
+ target.targetName
+ )
+
+ override val compileAllTaskName: String
+ get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "classes")
+
+ override lateinit var compileDependencyFiles: FileCollection
+
+ override val apiConfigurationName: String
+ get() = disambiguateName("api")
+
+ override val implementationConfigurationName: String
+ get() = disambiguateName("implementation")
+
+ override val compileOnlyConfigurationName: String
+ get() = disambiguateName("compileOnly")
+
+ override val runtimeOnlyConfigurationName: String
+ get() = disambiguateName("runtimeOnly")
+
+ override fun dependencies(configure: KotlinDependencyHandler.() -> Unit): Unit =
+ DefaultKotlinDependencyHandler(this, target.project).run(configure)
+
+ override fun dependencies(configureClosure: Closure) =
+ dependencies f@{ ConfigureUtil.configure(configureClosure, this@f) }
+
+ override fun toString(): String = "compilation '$compilationName' ($target)"
+}
+
+abstract class AbstractKotlinCompilationToRunnableFiles(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilation(target, name), KotlinCompilationToRunnableFiles {
+ override val runtimeDependencyConfigurationName: String
+ get() = lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ "runtimeClasspath"
+ )
+
+ override lateinit var runtimeDependencyFiles: FileCollection
+}
+
+internal fun KotlinCompilation<*>.disambiguateName(simpleName: String): String {
+ return lowerCamelCaseName(
+ target.disambiguationClassifier,
+ compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME },
+ simpleName
+ )
+}
+
+open class KotlinJvmCompilation(
+ target: KotlinTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ override val processResourcesTaskName: String
+ get() = disambiguateName("processResources")
+
+ override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+ get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
+}
+
+class KotlinWithJavaCompilation(
+ target: KotlinWithJavaTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles(target, name), KotlinCompilationWithResources {
+ lateinit var javaSourceSet: SourceSet
+
+ override val output: KotlinCompilationOutput by lazy { KotlinWithJavaCompilationOutput(this) }
+
+ override val processResourcesTaskName: String
+ get() = javaSourceSet.processResourcesTaskName
+
+ override var runtimeDependencyFiles: FileCollection
+ get() = javaSourceSet.runtimeClasspath
+ set(value) {
+ javaSourceSet.runtimeClasspath = value
+ }
+
+ override val runtimeDependencyConfigurationName: String
+ get() = javaSourceSet.runtimeClasspathConfigurationName
+
+ override val compileDependencyConfigurationName: String
+ get() = javaSourceSet.compileClasspathConfigurationName
+
+ override val runtimeOnlyConfigurationName: String
+ get() = javaSourceSet.runtimeOnlyConfigurationName
+
+ override val implementationConfigurationName: String
+ get() = javaSourceSet.implementationConfigurationName
+
+ override val apiConfigurationName: String
+ get() = javaSourceSet.apiConfigurationName
+
+ override val compileOnlyConfigurationName: String
+ get() = javaSourceSet.compileOnlyConfigurationName
+
+ override val compileAllTaskName: String
+ get() = javaSourceSet.classesTaskName
+
+ override var compileDependencyFiles: FileCollection
+ get() = javaSourceSet.compileClasspath
+ set(value) {
+ javaSourceSet.compileClasspath = value
+ }
+
+ fun source(javaSourceSet: SourceSet) {
+ with(target.project) {
+ afterEvaluate {
+ (tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(javaSourceSet.java)
+ }
+ }
+ }
+}
+
+class KotlinJvmAndroidCompilation(
+ target: KotlinAndroidTarget,
+ name: String
+) : AbstractKotlinCompilationToRunnableFiles