From 970ee4539ba931bdfacdd3c610ad0e2e63773136 Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Mon, 20 Jan 2020 14:28:46 +0300 Subject: [PATCH] Common klib support in the Kotlin Gradle plugin (KT-32677) Refactor the Kotlin/Native compilations and tasks to support Kotlin/Native-shared source sets compilation within the metadata target. Provide the feature flag kotlin.mpp.enableCommonKlibs that enables the following behavior: * compilation of Kotlin/Native-shared source sets to a klib using the Kotlin/Native compiler. * compilation of common source sets (not just Kotlin/Native) into a klib rather than *.kotlin_metadata Issue #KT-32677 Fixed --- .idea/dictionaries/sergey_igushkin.xml | 7 ++ .../kotlin/gradle/plugin/KotlinCompilation.kt | 2 + .../kotlin/gradle/HierarchicalMppIT.kt | 4 +- .../jetbrains/kotlin/gradle/KlibBasedMppIT.kt | 94 +++++++++++++++++++ .../jetbrains/kotlin/gradle/PluginsDslIT.kt | 5 +- .../gradle/VariantAwareDependenciesIT.kt | 24 +++-- .../common-klib-lib-and-app/build.gradle.kts | 70 ++++++++++++++ .../common-klib-lib-and-app/gradle.properties | 2 + .../settings.gradle.kts | 6 ++ .../src/commonMain/kotlin/LibCommonMain.kt | 16 ++++ .../src/iosMain/kotlin/LibIosMain.kt | 17 ++++ .../jvmAndJsMain/kotlin/LibJvmAndJsMain.kt | 12 +++ .../src/jvmMain/kotlin/LibJvmMain.kt | 5 + .../kotlin/gradle/plugin/KotlinPlugin.kt | 68 +++++++------- .../kotlin/gradle/plugin/KotlinProperties.kt | 3 + .../gradle/plugin/KotlinTargetConfigurator.kt | 10 +- .../mpp/GranularMetadataTransformation.kt | 15 +-- .../plugin/mpp/KotlinCommonCompilation.kt | 17 +--- .../plugin/mpp/KotlinCompilationFactory.kt | 2 +- .../gradle/plugin/mpp/KotlinMetadataTarget.kt | 3 +- .../plugin/mpp/KotlinMultiplatformPlugin.kt | 4 +- .../mpp/KotlinProjectStructureMetadata.kt | 43 ++++++++- .../gradle/plugin/mpp/kotlinCompilations.kt | 13 ++- .../targets/js/KotlinJsTargetConfigurator.kt | 4 +- .../jvm/KotlinJvmTargetConfigurator.kt | 2 +- .../jvm/KotlinJvmWithJavaTargetPreset.kt | 2 +- .../KotlinMetadataTargetConfigurator.kt | 94 ++++++++++++++----- .../metadata/KotlinMetadataTargetPreset.kt | 19 ++-- .../targets/native/KotlinNativeCompilation.kt | 94 ++++++------------- .../native/KotlinNativeCompilationFactory.kt | 13 ++- .../native/KotlinNativeTargetConfigurator.kt | 29 +++--- .../native/KotlinNativeTargetPreset.kt | 4 +- .../targets/native/tasks/KotlinNativeTasks.kt | 26 ++--- .../gradle/tasks/KotlinCompileCommon.kt | 5 + .../SourceSetVisibilityInferenceTest.kt | 3 + 35 files changed, 541 insertions(+), 196 deletions(-) create mode 100644 .idea/dictionaries/sergey_igushkin.xml create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/build.gradle.kts create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/gradle.properties create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/settings.gradle.kts create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/commonMain/kotlin/LibCommonMain.kt create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/iosMain/kotlin/LibIosMain.kt create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmAndJsMain/kotlin/LibJvmAndJsMain.kt create mode 100755 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmMain/kotlin/LibJvmMain.kt diff --git a/.idea/dictionaries/sergey_igushkin.xml b/.idea/dictionaries/sergey_igushkin.xml new file mode 100644 index 00000000000..8a2a33591a8 --- /dev/null +++ b/.idea/dictionaries/sergey_igushkin.xml @@ -0,0 +1,7 @@ + + + + klib + + + \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt index a1617b0f837..07b96b910e2 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinCompilation.kt @@ -33,6 +33,8 @@ interface KotlinCompilation : Named, HasAttributes, val allKotlinSourceSets: Set + val defaultSourceSetName: String + val defaultSourceSet: KotlinSourceSet fun defaultSourceSet(configure: KotlinSourceSet.() -> Unit) diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt index c0a19ab3ce8..bc7b62bb4ac 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/HierarchicalMppIT.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle import org.jetbrains.kotlin.gradle.internals.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME import org.jetbrains.kotlin.gradle.internals.parseKotlinSourceSetMetadataFromXml import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata +import org.jetbrains.kotlin.gradle.plugin.mpp.SourceSetMetadataLayout import org.jetbrains.kotlin.gradle.plugin.mpp.ModuleDependencyIdentifier import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet import org.jetbrains.kotlin.gradle.util.checkedReplace @@ -374,7 +375,8 @@ class HierarchicalMppIT : BaseGradleIT() { pairs.map { ModuleDependencyIdentifier(it.first, it.second) }.toSet() - } + }, + sourceSetBinaryLayout = sourceSetModuleDependencies.mapValues { SourceSetMetadataLayout.METADATA } ) } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt new file mode 100644 index 00000000000..61eaf856984 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/KlibBasedMppIT.kt @@ -0,0 +1,94 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle + +import org.jetbrains.kotlin.gradle.util.modify +import org.jetbrains.kotlin.konan.target.HostManager +import org.junit.Assume +import kotlin.test.Ignore +import kotlin.test.Test + +/** FIXME (sergey.igushkin): please enable these tests back as soon as the Kotlin/Native version that is bundled with the + * Kotlin distribution supports compilation to klib and targetless klibs. + */ +@Ignore +class KlibBasedMppIT : BaseGradleIT() { + override val defaultGradleVersion = GradleVersionRequired.AtLeast("6.0") + + @Test + fun testBuildWithProjectDependency() = testBuildWithDependency { + gradleBuildScript().appendText("\n" + """ + dependencies { + commonMainImplementation(project("$embeddedModuleName")) + } + """.trimIndent()) + } + + @Test + fun testBuildWithPublishedDependency() = testBuildWithDependency { + build(":$embeddedModuleName:publish") { + assertSuccessful() + } + + gradleBuildScript().appendText("\n" + """ + repositories { + maven("${'$'}rootDir/repo") + } + dependencies { + commonMainImplementation("com.example:$embeddedModuleName:1.0") + } + """.trimIndent()) + + // prevent Gradle from linking the above dependency to the project: + gradleBuildScript(embeddedModuleName).appendText("\ngroup = \"some.other.group\"") + } + + private val embeddedModuleName = "project-dep" + + private fun testBuildWithDependency(configureDependency: Project.() -> Unit) = with(Project("common-klib-lib-and-app")) { + Assume.assumeTrue(HostManager.hostIsMac) + + embedProject(Project("common-klib-lib-and-app"), renameTo = embeddedModuleName) + gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl) + + projectDir.resolve(embeddedModuleName + "/src").walkTopDown().filter { it.extension == "kt" }.forEach { file -> + file.modify { it.replace("package com.h0tk3y.hmpp.klib.demo", "package com.projectdep") } + } + + configureDependency() + + projectDir.resolve("src/commonMain/kotlin/LibUsage.kt").appendText("\n" + """ + package com.h0tk3y.hmpp.klib.demo.test + + import com.projectdep.LibCommonMainExpect as ProjectDepExpect + + private fun useProjectDep() { + ProjectDepExpect() + } + """.trimIndent()) + + projectDir.resolve("src/iosMain/kotlin/LibIosMainUsage.kt").appendText("\n" + """ + package com.h0tk3y.hmpp.klib.demo.test + + import com.projectdep.libIosMainFun as libFun + + private fun useProjectDep() { + libFun() + } + """.trimIndent()) + + val tasksToExecute = listOf( + ":compileJvmAndJsMainKotlinMetadata", + ":compileIosMainKotlinMetadata" + ) + + build("assemble") { + assertSuccessful() + + assertTasksExecuted(*tasksToExecute.toTypedArray()) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PluginsDslIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PluginsDslIT.kt index e242a0c4166..541c8d58ee6 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PluginsDslIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/PluginsDslIT.kt @@ -80,7 +80,10 @@ internal fun BaseGradleIT.transformProjectWithPluginsDsl( } result.projectDir.walkTopDown() - .filter { it.isFile && (it.name == "build.gradle" || it.name == "build.gradle.kts") } + .filter { + it.isFile && (it.name == "build.gradle" || it.name == "build.gradle.kts" || + it.name == "settings.gradle" || it.name == "settings.gradle.kts") + } .forEach { buildGradle -> buildGradle.modify(::transformBuildScriptWithPluginsDsl) } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt index 9a339377e9b..636a2aebc9a 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/VariantAwareDependenciesIT.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.gradle +import org.jetbrains.kotlin.gradle.util.createTempDir +import org.jetbrains.kotlin.gradle.util.isWindows import org.jetbrains.kotlin.gradle.util.modify import org.jetbrains.kotlin.gradle.util.testResolveAllConfigurations import org.junit.Test @@ -292,15 +294,23 @@ class VariantAwareDependenciesIT : BaseGradleIT() { } -internal fun BaseGradleIT.Project.embedProject(other: BaseGradleIT.Project) { +internal fun BaseGradleIT.Project.embedProject(other: BaseGradleIT.Project, renameTo: String? = null) { setupWorkingDir() other.setupWorkingDir() - other.testCase.apply { - val gradleBuildScript = other.gradleBuildScript() - if (gradleBuildScript.extension == "kts") { - gradleBuildScript.modify { it.replace(".version(\"$PLUGIN_MARKER_VERSION_PLACEHOLDER\")", "") } + val tempDir = createTempDir(if (isWindows) "" else "BaseGradleIT") + val embeddedModuleName = renameTo ?: other.projectName + try { + other.projectDir.copyRecursively(tempDir) + tempDir.copyRecursively(projectDir.resolve(embeddedModuleName)) + } finally { + check(tempDir.deleteRecursively()) + } + testCase.apply { + gradleSettingsScript().appendText("\ninclude(\"$embeddedModuleName\")") + + val embeddedBuildScript = gradleBuildScript(embeddedModuleName) + if (embeddedBuildScript.extension == "kts") { + embeddedBuildScript.modify { it.replace(".version(\"$PLUGIN_MARKER_VERSION_PLACEHOLDER\")", "") } } } - other.projectDir.copyRecursively(projectDir.resolve(other.projectName)) - projectDir.resolve("settings.gradle").appendText("\ninclude '${other.projectName}'") } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/build.gradle.kts new file mode 100644 index 00000000000..4ff208de23e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/build.gradle.kts @@ -0,0 +1,70 @@ +plugins { + kotlin("multiplatform").version("") + id("maven-publish") +} + +group = "com.example" +version = "1.0" + +repositories { + mavenLocal() + jcenter() +} + +kotlin { + jvm() + js() + + ios() + + sourceSets { + val commonMain by getting { + dependencies { + implementation(kotlin("stdlib-common")) + } + } + + val jvmAndJsMain by creating { + dependsOn(commonMain) + } + + val jvmMain by getting { + dependsOn(jvmAndJsMain) + dependencies { + implementation(kotlin("stdlib-jdk8")) + } + } + + val jsMain by getting { + dependsOn(jvmAndJsMain) + dependencies { + implementation(kotlin("stdlib-js")) + } + } + } +} + +publishing { + repositories { + maven("$rootDir/repo") + } +} + +tasks { + val skipCompilationOfTargets = setOf( + "iosArm64", + "iosX64" + ) + all { + val target = name.removePrefix("compileKotlin").decapitalize() + if (target in skipCompilationOfTargets) { + actions.clear() + doLast { + val destinationFile = project.buildDir.resolve("classes/kotlin/$target/main/${project.name}.klib") + destinationFile.parentFile.mkdirs() + println("Writing a dummy klib to $destinationFile") + destinationFile.createNewFile() + } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/gradle.properties new file mode 100755 index 00000000000..96d28f62e25 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/gradle.properties @@ -0,0 +1,2 @@ +kotlin.mpp.enableGranularSourceSetsMetadata=true +kotlin.mpp.enableCommonKlibs=true \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/settings.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/settings.gradle.kts new file mode 100644 index 00000000000..42c04f103d7 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/settings.gradle.kts @@ -0,0 +1,6 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/commonMain/kotlin/LibCommonMain.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/commonMain/kotlin/LibCommonMain.kt new file mode 100755 index 00000000000..898f682462f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/commonMain/kotlin/LibCommonMain.kt @@ -0,0 +1,16 @@ +package com.h0tk3y.hmpp.klib.demo + +interface LibCommonMainIface + +expect class LibCommonMainExpect() : LibCommonMainIface { + fun libCommonMainExpectFun(): Unit +} + +fun libCommonMainTopLevelFun(): Int { + println("commonMainTopLevelFun") + return 2 +} + +fun main() { + +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/iosMain/kotlin/LibIosMain.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/iosMain/kotlin/LibIosMain.kt new file mode 100755 index 00000000000..7f5ca177c33 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/iosMain/kotlin/LibIosMain.kt @@ -0,0 +1,17 @@ +package com.h0tk3y.hmpp.klib.demo + +import kotlinx.cinterop.CArrayPointer + +actual class LibCommonMainExpect : LibCommonMainIface { + actual fun libCommonMainExpectFun(): Unit { + println("actualized in iosMain") + libCommonMainTopLevelFun() + println(CArrayPointer::class) + } + + fun additionalFunInIosActual() { + println("additional fun in lib iosMain") + } +} + +fun libIosMainFun(): LibCommonMainIface = LibCommonMainExpect() \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmAndJsMain/kotlin/LibJvmAndJsMain.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmAndJsMain/kotlin/LibJvmAndJsMain.kt new file mode 100755 index 00000000000..7b9211a8006 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmAndJsMain/kotlin/LibJvmAndJsMain.kt @@ -0,0 +1,12 @@ +package com.h0tk3y.hmpp.klib.demo + +actual class LibCommonMainExpect : LibCommonMainIface { + actual fun libCommonMainExpectFun(): Unit { + println("actualized in jvmAndJsMain") + libCommonMainTopLevelFun() + } + + fun additionalFunInJvmAndJsActual() { + println("additional fun from jvmAndJsMain") + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmMain/kotlin/LibJvmMain.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmMain/kotlin/LibJvmMain.kt new file mode 100755 index 00000000000..8f4481fd409 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/common-klib-lib-and-app/src/jvmMain/kotlin/LibJvmMain.kt @@ -0,0 +1,5 @@ +package com.h0tk3y.hmpp.klib.demo + +fun main() { + libCommonMainTopLevelFun() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 155e2a615a4..f74a246316b 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -52,29 +52,16 @@ val KOTLIN_DSL_NAME = "kotlin" val KOTLIN_JS_DSL_NAME = "kotlin2js" val KOTLIN_OPTIONS_DSL_NAME = "kotlinOptions" -internal abstract class KotlinSourceSetProcessor>( - val project: Project, - val tasksProvider: KotlinTasksProvider, - val taskDescription: String, - val kotlinCompilation: AbstractKotlinCompilation<*> +abstract class KotlinCompilationProcessor( + open val kotlinCompilation: AbstractKotlinCompilation<*> ) { - protected abstract fun doTargetSpecificProcessing() - protected val logger = Logging.getLogger(this.javaClass)!! + abstract val kotlinTask: TaskProvider + abstract fun run() - protected val sourceSetName: String = kotlinCompilation.compilationName + protected val project: Project + get() = kotlinCompilation.target.project - protected val kotlinTask: TaskProvider = registerKotlinCompileTask() - - protected val javaSourceSet: SourceSet? - get() = - (kotlinCompilation as? KotlinWithJavaCompilation<*>)?.javaSourceSet - ?: kotlinCompilation.target.let { - if (it is KotlinJvmTarget && it.withJavaEnabled) - project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.maybeCreate(kotlinCompilation.name) - else null - } - - private val defaultKotlinDestinationDir: File + protected val defaultKotlinDestinationDir: File get() { val kotlinExt = project.kotlinExtension val targetSubDirectory = @@ -84,6 +71,28 @@ internal abstract class KotlinSourceSetProcessor>( kotlinCompilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() return File(project.buildDir, "classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationName}") } +} + +internal abstract class KotlinSourceSetProcessor>( + val tasksProvider: KotlinTasksProvider, + val taskDescription: String, + kotlinCompilation: AbstractKotlinCompilation<*> +) : KotlinCompilationProcessor(kotlinCompilation) { + protected abstract fun doTargetSpecificProcessing() + protected val logger = Logging.getLogger(this.javaClass)!! + + protected val sourceSetName: String = kotlinCompilation.compilationName + + override val kotlinTask: TaskProvider = registerKotlinCompileTask() + + protected val javaSourceSet: SourceSet? + get() = + (kotlinCompilation as? KotlinWithJavaCompilation<*>)?.javaSourceSet + ?: kotlinCompilation.target.let { + if (it is KotlinJvmTarget && it.withJavaEnabled) + project.convention.getPlugin(JavaPluginConvention::class.java).sourceSets.maybeCreate(kotlinCompilation.name) + else null + } private fun registerKotlinCompileTask(): TaskProvider { val name = kotlinCompilation.compileKotlinTaskName @@ -103,7 +112,7 @@ internal abstract class KotlinSourceSetProcessor>( return result } - open fun run() { + override fun run() { addKotlinDirectoriesToJavaSourceSet() doTargetSpecificProcessing() @@ -165,12 +174,11 @@ internal abstract class KotlinSourceSetProcessor>( } internal class Kotlin2JvmSourceSetProcessor( - project: Project, tasksProvider: KotlinTasksProvider, kotlinCompilation: AbstractKotlinCompilation<*>, private val kotlinPluginVersion: String ) : KotlinSourceSetProcessor( - project, tasksProvider, "Compiles the $kotlinCompilation.", kotlinCompilation + tasksProvider, "Compiles the $kotlinCompilation.", kotlinCompilation ) { override fun doRegisterTask( project: Project, @@ -245,13 +253,11 @@ internal fun KotlinCompilationOutput.addClassesDir(classesDirProvider: () -> Fil } internal class Kotlin2JsSourceSetProcessor( - project: Project, tasksProvider: KotlinTasksProvider, kotlinCompilation: AbstractKotlinCompilation<*>, private val kotlinPluginVersion: String ) : KotlinSourceSetProcessor( - project, tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.", - kotlinCompilation = kotlinCompilation + tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.", kotlinCompilation = kotlinCompilation ) { override fun doRegisterTask( project: Project, @@ -311,13 +317,11 @@ internal class Kotlin2JsSourceSetProcessor( } internal class KotlinCommonSourceSetProcessor( - project: Project, compilation: AbstractKotlinCompilation<*>, tasksProvider: KotlinTasksProvider, private val kotlinPluginVersion: String ) : KotlinSourceSetProcessor( - project, tasksProvider, taskDescription = "Compiles the kotlin sources in $compilation to Metadata.", - kotlinCompilation = compilation + tasksProvider, taskDescription = "Compiles the kotlin sources in $compilation to Metadata.", kotlinCompilation = compilation ) { override fun doTargetSpecificProcessing() { project.tasks.findByName(kotlinCompilation.compileAllTaskName)!!.dependsOn(kotlinTask) @@ -581,7 +585,7 @@ internal open class KotlinPlugin( } override fun buildSourceSetProcessor(project: Project, compilation: AbstractKotlinCompilation<*>, kotlinPluginVersion: String) = - Kotlin2JvmSourceSetProcessor(project, tasksProvider, compilation, kotlinPluginVersion) + Kotlin2JvmSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion) override fun apply(project: Project) { val target = KotlinWithJavaTarget(project, KotlinPlatformType.jvm, targetName).apply { @@ -609,7 +613,7 @@ internal open class KotlinCommonPlugin( compilation: AbstractKotlinCompilation<*>, kotlinPluginVersion: String ): KotlinSourceSetProcessor<*> = - KotlinCommonSourceSetProcessor(project, compilation, tasksProvider, kotlinPluginVersion) + KotlinCommonSourceSetProcessor(compilation, tasksProvider, kotlinPluginVersion) override fun apply(project: Project) { val target = KotlinWithJavaTarget(project, KotlinPlatformType.common, targetName) @@ -634,7 +638,7 @@ internal open class Kotlin2JsPlugin( kotlinPluginVersion: String ): KotlinSourceSetProcessor<*> = Kotlin2JsSourceSetProcessor( - project, tasksProvider, compilation, kotlinPluginVersion + tasksProvider, compilation, kotlinPluginVersion ) override fun apply(project: Project) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt index 92ba9d675c3..a5d1ca2e5da 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt @@ -94,6 +94,9 @@ internal class PropertiesProvider private constructor(private val project: Proje val enableGranularSourceSetsMetadata: Boolean? get() = booleanProperty("kotlin.mpp.enableGranularSourceSetsMetadata") + val enableCommonKlibs: Boolean? + get() = booleanProperty("kotlin.mpp.enableCommonKlibs") + val ignoreDisabledNativeTargets: Boolean? get() = booleanProperty(DisabledNativeTargetsReporter.DISABLE_WARNING_PROPERTY_NAME) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt index d6c3496aaeb..d9fb3a26b23 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt @@ -63,7 +63,9 @@ abstract class AbstractKotlinTargetConfigurator cleanTask.delete(kotlinCompilation.output.allOutputs) } - protected open fun setupCompilationDependencyFiles(project: Project, compilation: KotlinCompilation) { + protected open fun setupCompilationDependencyFiles(compilation: KotlinCompilation) { + val project = compilation.target.project + compilation.compileDependencyFiles = project.configurations.maybeCreate(compilation.compileDependencyConfigurationName) if (compilation is KotlinCompilationToRunnableFiles) { compilation.runtimeDependencyFiles = project.configurations.maybeCreate(compilation.runtimeDependencyConfigurationName) @@ -76,7 +78,7 @@ abstract class AbstractKotlinTargetConfigurator target.compilations.all { project.registerOutputsForStaleOutputCleanup(it) - setupCompilationDependencyFiles(project, it) + setupCompilationDependencyFiles(it) } if (createTestCompilation) { @@ -322,7 +324,7 @@ abstract class KotlinOnlyTargetConfigurator + internal abstract fun buildCompilationProcessor(compilation: KotlinCompilationType): KotlinCompilationProcessor<*> override fun configureCompilations(target: KotlinTargetType) { super.configureCompilations(target) @@ -336,7 +338,7 @@ abstract class KotlinOnlyTargetConfigurator) { + protected open fun createJarTasks(target: KotlinTargetType) { val result = target.project.tasks.create(target.artifactsTaskName, Jar::class.java) result.description = "Assembles a jar archive containing the main classes." result.group = BasePlugin.BUILD_GROUP diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt index 8ff0afef16e..6a67da148ce 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GranularMetadataTransformation.kt @@ -8,13 +8,9 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.gradle.api.artifacts.* import org.gradle.api.file.FileCollection -import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_MAIN_SOURCE_SET_NAME -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.Companion.COMMON_TEST_SOURCE_SET_NAME import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope -import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope import java.io.File import java.util.* @@ -372,15 +368,22 @@ private class JarArtifactMppDependencyMetadataExtractor( val resultFiles = mutableMapOf() + val projectStructureMetadata = checkNotNull(getProjectStructureMetadata()) { + "can't extract metadata from a module without project structure metadata" + } + ZipFile(artifactJar).use { zip -> val entriesBySourceSet = zip.entries().asSequence() .groupBy { it.name.substringBefore("/") } .filterKeys { it in chooseSourceSetsByNames } entriesBySourceSet.forEach { (sourceSetName, entries) -> - // TODO: once IJ supports non-JAR metadata dependencies, extraact to a directory, not a JAR + // TODO: once IJ supports non-JAR metadata dependencies, extract to a directory, not a JAR // Also, if both IJ and the CLI compiler can read metadata from a path inside a JAR, then no operations will be needed - val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.jar") + val extension = + projectStructureMetadata.sourceSetBinaryLayout[sourceSetName]?.archiveExtension + ?: SourceSetMetadataLayout.METADATA.archiveExtension + val extractToJarFile = transformedModuleRoot.resolve("$moduleString-$sourceSetName.$extension") resultFiles[sourceSetName] = project.files(extractToJarFile) 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 index 8fc03bc03dc..249ad979f8f 100644 --- 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 @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptions import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation @@ -12,22 +13,12 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon +interface KotlinMetadataCompilation : KotlinCompilation + class KotlinCommonCompilation( target: KotlinTarget, name: String -) : AbstractKotlinCompilation(target, name) { +) : AbstractKotlinCompilation(target, name), KotlinMetadataCompilation { override val compileKotlinTask: KotlinCompileCommon get() = super.compileKotlinTask as KotlinCompileCommon - - private val commonSourceSetName by lazy { - when (compilationName) { - // Historically, a metadata target has a main compilation. We keep using it to compile just the commonMain source set: - KotlinCompilation.MAIN_COMPILATION_NAME -> KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME - // All other common source sets are compiled by compilations named according to the source sets: - else -> compilationName - } - } - - override val defaultSourceSet: KotlinSourceSet - get() = target.project.kotlinExtension.sourceSets.getByName(commonSourceSetName) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationFactory.kt index 3d6f96425b6..9c14a35133a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinCompilationFactory.kt @@ -14,7 +14,7 @@ interface KotlinCompilationFactory> : NamedDomainObject } class KotlinCommonCompilationFactory( - val target: KotlinOnlyTarget + val target: KotlinOnlyTarget<*> ) : KotlinCompilationFactory { override val itemClass: Class get() = KotlinCommonCompilation::class.java diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt index cb93f861a9b..510070b03af 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMetadataTarget.kt @@ -22,7 +22,8 @@ import javax.inject.Inject internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadataElements" open class KotlinMetadataTarget @Inject constructor(project: Project) : - KotlinOnlyTarget(project, KotlinPlatformType.common) { + KotlinOnlyTarget>(project, KotlinPlatformType.common) { + override val kotlinComponents: Set by lazy { if (!project.isKotlinGranularMetadataEnabled) super.kotlinComponents diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 84bf9ee47a2..b1c4bdd308f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -257,11 +257,11 @@ class KotlinMultiplatformPlugin( targets.all { target -> target.compilations.findByName(KotlinCompilation.MAIN_COMPILATION_NAME)?.let { mainCompilation -> - sourceSets.findByName(mainCompilation.defaultSourceSetName)?.dependsOn(production) + mainCompilation.defaultSourceSet.takeIf { it != production }?.dependsOn(production) } target.compilations.findByName(KotlinCompilation.TEST_COMPILATION_NAME)?.let { testCompilation -> - sourceSets.findByName(testCompilation.defaultSourceSetName)?.dependsOn(test) + testCompilation.defaultSourceSet.takeIf { it != test }?.dependsOn(test) } KotlinBuildStatsService.getInstance()?.report(StringMetrics.MPP_PLATFORMS, target.targetName) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt index 76459c97c58..1c465ad282e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinProjectStructureMetadata.kt @@ -8,7 +8,9 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project import org.gradle.api.tasks.Input import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.targets.metadata.getPublishedPlatformCompilations import org.w3c.dom.Document import org.w3c.dom.Element @@ -21,6 +23,28 @@ data class ModuleDependencyIdentifier( val moduleId: String ) +sealed class SourceSetMetadataLayout( + @get:Input + val name: String, + @get:Internal + val archiveExtension: String +) { + object METADATA : SourceSetMetadataLayout("metadata", "jar") + object KLIB : SourceSetMetadataLayout("klib", "klib") + + companion object { + private val values = listOf(METADATA, KLIB) + + fun byName(name: String): SourceSetMetadataLayout? = values.firstOrNull { it.name == name } + + fun chooseForProducingProject(project: Project) = + if (PropertiesProvider(project.rootProject).enableCommonKlibs == true) + KLIB + else + METADATA + } +} + data class KotlinProjectStructureMetadata( @Input val sourceSetNamesByVariantName: Map>, @@ -28,11 +52,14 @@ data class KotlinProjectStructureMetadata( @Input val sourceSetsDependsOnRelation: Map>, + @Nested + val sourceSetBinaryLayout: Map, + @Internal val sourceSetModuleDependencies: Map>, @Input - val formatVersion: String = FORMAT_VERSION_0_1 + val formatVersion: String = FORMAT_VERSION_0_2 ) { @Suppress("UNUSED") // Gradle input @get:Input @@ -41,6 +68,7 @@ data class KotlinProjectStructureMetadata( companion object { internal const val FORMAT_VERSION_0_1 = "0.1" + internal const val FORMAT_VERSION_0_2 = "0.2" } } @@ -63,6 +91,9 @@ internal fun buildKotlinProjectStructureMetadata(project: Project): KotlinProjec sourceSet.name to project.configurations.getByName(sourceSet.apiConfigurationName).allDependencies.map { ModuleDependencyIdentifier(it.group.orEmpty(), it.name) }.toSet() + }, + sourceSetBinaryLayout = sourceSetsWithMetadataCompilations.keys.associate { sourceSet -> + sourceSet.name to SourceSetMetadataLayout.chooseForProducingProject(project) } ) } @@ -96,6 +127,9 @@ internal fun KotlinProjectStructureMetadata.toXmlDocument(): Document { sourceSetModuleDependencies[sourceSet].orEmpty().forEach { moduleDependency -> textNode("moduleDependency", moduleDependency.groupId + ":" + moduleDependency.moduleId) } + sourceSetBinaryLayout[sourceSet]?.let { binaryLayout -> + textNode("binaryLayout", binaryLayout.name) + } } } } @@ -123,6 +157,7 @@ internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProj val sourceSetDependsOnRelation = mutableMapOf>() val sourceSetModuleDependencies = mutableMapOf>() + val sourceSetBinaryLayout = mutableMapOf() val sourceSetsNode = projectStructureNode.getElementsByTagName("sourceSets").item(0) ?: return null @@ -139,6 +174,11 @@ internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProj val (groupId, moduleId) = node.textContent.split(":") moduleDependencies.add(ModuleDependencyIdentifier(groupId, moduleId)) } + "binaryLayout" -> { + SourceSetMetadataLayout.byName(node.textContent)?.let { binaryLayout -> + sourceSetBinaryLayout[sourceSetName] = binaryLayout + } + } } } @@ -149,6 +189,7 @@ internal fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProj return KotlinProjectStructureMetadata( sourceSetsByVariant, sourceSetDependsOnRelation, + sourceSetBinaryLayout, sourceSetModuleDependencies, formatVersion ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt index 8a7f0ef2514..3f8609330ba 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt @@ -36,9 +36,6 @@ internal fun KotlinCompilation<*>.composeName(prefix: String? = null, suffix: St 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 @@ -70,6 +67,16 @@ abstract class AbstractKotlinCompilation( override val allKotlinSourceSets: Set get() = kotlinSourceSets.flatMapTo(mutableSetOf()) { it.getSourceSetHierarchy() } + override val defaultSourceSetName: String + get() = lowerCamelCaseName( + target.disambiguationClassifier.takeIf { target !is KotlinMetadataTarget }, + when { + compilationName == KotlinCompilation.MAIN_COMPILATION_NAME && target is KotlinMetadataTarget -> + KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME // corner case: main compilation of the metadata target compiles commonMain + else -> compilationName + } + ) + override val defaultSourceSet: KotlinSourceSet get() = target.project.kotlinExtension.sourceSets.getByName(defaultSourceSetName) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt index e9f587dec0e..015fca566fa 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTargetConfigurator.kt @@ -5,14 +5,12 @@ package org.jetbrains.kotlin.gradle.targets.js -import org.gradle.api.tasks.TaskProvider import org.jetbrains.kotlin.gradle.plugin.Kotlin2JsSourceSetProcessor import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor import org.jetbrains.kotlin.gradle.plugin.KotlinOnlyTargetConfigurator import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTestsConfigurator import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsCompilation import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider -import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestReport import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.testTaskName @@ -47,7 +45,7 @@ open class KotlinJsTargetConfigurator(kotlinPluginVersion: String) : override fun buildCompilationProcessor(compilation: KotlinJsCompilation): KotlinSourceSetProcessor<*> { val tasksProvider = KotlinTasksProvider(compilation.target.targetName) - return Kotlin2JsSourceSetProcessor(compilation.target.project, tasksProvider, compilation, kotlinPluginVersion) + return Kotlin2JsSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion) } override fun configureCompilations(target: KotlinJsTarget) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt index a2752ef48e0..827fed8030d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt @@ -71,6 +71,6 @@ class KotlinJvmTargetConfigurator(kotlinPluginVersion: String) : override fun buildCompilationProcessor(compilation: KotlinJvmCompilation): KotlinSourceSetProcessor<*> { val tasksProvider = KotlinTasksProvider(compilation.target.targetName) - return Kotlin2JvmSourceSetProcessor(compilation.target.project, tasksProvider, compilation, kotlinPluginVersion) + return Kotlin2JvmSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion) } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmWithJavaTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmWithJavaTargetPreset.kt index 478f1d73ee3..e8fd9bd8b68 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmWithJavaTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmWithJavaTargetPreset.kt @@ -35,7 +35,7 @@ class KotlinJvmWithJavaTargetPreset( } AbstractKotlinPlugin.configureTarget(target) { compilation -> - Kotlin2JvmSourceSetProcessor(project, KotlinTasksProvider(name), compilation, kotlinPluginVersion) + Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(name), compilation, kotlinPluginVersion) } target.compilations.getByName("test").run { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index 57458d683d6..6d5b117ba9e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.sources.* import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService +import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.tasks.locateTask @@ -38,7 +39,7 @@ internal val Project.isKotlinGranularMetadataEnabled: Boolean get() = PropertiesProvider(rootProject).enableGranularSourceSetsMetadata == true class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : - KotlinOnlyTargetConfigurator( + KotlinOnlyTargetConfigurator, KotlinMetadataTarget>( createDefaultSourceSets = false, createTestCompilation = false, kotlinPluginVersion = kotlinPluginVersion @@ -59,7 +60,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : } } - private val KotlinOnlyTarget.apiElementsConfiguration: Configuration + private val KotlinOnlyTarget<*>.apiElementsConfiguration: Configuration get() = project.configurations.getByName(apiElementsConfigurationName) override fun configureTarget(target: KotlinMetadataTarget) { @@ -67,7 +68,6 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : if (target.project.isKotlinGranularMetadataEnabled) { KotlinBuildStatsService.getInstance()?.report(BooleanMetrics.ENABLED_HMPP, true) - target as KotlinMetadataTarget createMergedAllSourceSetsConfigurations(target) @@ -81,20 +81,40 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : } } - override fun setupCompilationDependencyFiles(project: Project, compilation: KotlinCompilation) { + override fun setupCompilationDependencyFiles(compilation: KotlinCompilation) { + val project = compilation.target.project + /** See [createTransformedMetadataClasspath] and its usage. */ if (project.isKotlinGranularMetadataEnabled) compilation.compileDependencyFiles = project.files() else - super.setupCompilationDependencyFiles(project, compilation) + super.setupCompilationDependencyFiles(compilation) } - override fun buildCompilationProcessor(compilation: KotlinCommonCompilation): KotlinSourceSetProcessor<*> { - val tasksProvider = KotlinTasksProvider(compilation.target.targetName) - return KotlinCommonSourceSetProcessor(compilation.target.project, compilation, tasksProvider, kotlinPluginVersion) + override fun buildCompilationProcessor(compilation: AbstractKotlinCompilation<*>): KotlinCompilationProcessor<*> = when (compilation) { + is KotlinCommonCompilation -> { + val tasksProvider = KotlinTasksProvider(compilation.target.targetName) + KotlinCommonSourceSetProcessor(compilation, tasksProvider, kotlinPluginVersion) + } + is KotlinSharedNativeCompilation -> NativeSharedCompilationProcessor(compilation) + else -> error("unsupported compilation type ${compilation::class.qualifiedName}") } - override fun createJarTasks(target: KotlinOnlyTarget) { + private inner class NativeSharedCompilationProcessor( + override val kotlinCompilation: KotlinSharedNativeCompilation + ) : KotlinCompilationProcessor(kotlinCompilation) { + + private val nativeTargetConfigurator = KotlinNativeTargetConfigurator(kotlinPluginVersion) + + override val kotlinTask: TaskProvider = + with(nativeTargetConfigurator) { + project.createKlibCompilationTask(kotlinCompilation) + } + + override fun run() = Unit + } + + override fun createJarTasks(target: KotlinMetadataTarget) { super.createJarTasks(target) if (target.project.isKotlinGranularMetadataEnabled) { @@ -130,7 +150,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : val publishedCommonSourceSets: Set = getPublishedCommonSourceSets(project) - val sourceSetsWithMetadataCompilations: Map = + val sourceSetsWithMetadataCompilations: Map> = publishedCommonSourceSets.associate { sourceSet -> sourceSet to configureMetadataCompilation(target, sourceSet, allMetadataJar) } @@ -182,25 +202,41 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : target: KotlinMetadataTarget, sourceSet: KotlinSourceSet, allMetadataJar: Jar - ): KotlinCommonCompilation { + ): AbstractKotlinCompilation<*> { val project = target.project // With the metadata target, we publish all API dependencies of all the published source sets together: target.apiElementsConfiguration.extendsFrom(project.configurations.getByName(sourceSet.apiConfigurationName)) - val metadataCompilation = when (sourceSet.name) { - // Historically, we already had a 'main' compilation in metadata targets; TODO consider removing it instead - KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME -> target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME) - else -> target.compilations.create(sourceSet.name) { compilation -> - compilation.addExactSourceSetsEagerly(setOf(sourceSet)) + val compilationName = when (sourceSet.name) { + KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME -> KotlinCompilation.MAIN_COMPILATION_NAME + else -> sourceSet.name + } + + val metadataCompilation = run { + if (compilationName == KotlinCompilation.MAIN_COMPILATION_NAME) { + // It already exists. TODO Create it here? + return@run target.compilations.getByName(compilationName) + } + + val isNativeSourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project).getValue(sourceSet) + .all { compilation -> compilation.target is KotlinNativeTarget } + + val compilationFactory: KotlinCompilationFactory> = when { + isNativeSourceSet -> KotlinSharedNativeCompilationFactory(target) + else -> KotlinCommonCompilationFactory(target) + } + + compilationFactory.create(compilationName).apply { + target.compilations.add(this@apply) + addExactSourceSetsEagerly(setOf(sourceSet)) } } project.addExtendsFromRelation(metadataCompilation.compileDependencyConfigurationName, ALL_COMPILE_METADATA_CONFIGURATION_NAME) - allMetadataJar.from(metadataCompilation.output.allOutputs) { spec -> - spec.into(metadataCompilation.defaultSourceSet.name) - } + val metadataContent = project.filesWithUnpackedArchives(metadataCompilation.output.allOutputs, setOf("klib")) + allMetadataJar.from(metadataContent) { spec -> spec.into(metadataCompilation.defaultSourceSet.name) } project.registerTask(transformGranularMetadataTaskName(sourceSet), listOf(sourceSet)) { } @@ -338,7 +374,14 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) : // For now, we will only compile metadata from source sets used by multiple platforms // TODO once the compiler is able to analyze common code with platform-specific features and dependencies, lift this restriction val sourceSetsUsedInMultipleTargets = compilationsBySourceSet.filterValues { compilations -> - compilations.map { it.target.platformType }.distinct().size > 1 + compilations.map { it.target.platformType }.distinct().run { + size > 1 || ( + PropertiesProvider(project.rootProject).enableCommonKlibs == true && + singleOrNull() == KotlinPlatformType.native && + compilations.map { it.target }.distinct().size > 1 && + compilations.all { (it.target as? KotlinNativeTarget)?.konanTarget?.enabledOnCurrentHost == true } + ) + } } // We don't want to publish source set metadata from source sets that don't participate in any compilation that is published, @@ -373,4 +416,13 @@ internal fun getPublishedPlatformCompilations(project: Project): Map): FileCollection = + project.files(project.provider { + from.map { + if (it.extension in extensions) + project.zipTree(it) + else it + } + }).builtBy(from) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt index 04e06db002d..ab8bb398c34 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask @@ -16,16 +15,24 @@ import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigur class KotlinMetadataTargetPreset( project: Project, kotlinPluginVersion: String -) : KotlinOnlyTargetPreset( +) : KotlinOnlyTargetPreset>( project, kotlinPluginVersion ) { override fun getName(): String = PRESET_NAME override fun createCompilationFactory( - forTarget: KotlinOnlyTarget - ): KotlinCompilationFactory = - KotlinCommonCompilationFactory(forTarget) + forTarget: KotlinOnlyTarget> + ): KotlinCompilationFactory> = + object : KotlinCompilationFactory> { + override val itemClass: Class> + get() = AbstractKotlinCompilation::class.java + + override fun create(name: String): AbstractKotlinCompilation<*> = when (name) { + KotlinCompilation.MAIN_COMPILATION_NAME -> KotlinCommonCompilationFactory(forTarget).create(name) + else -> error("Can't create custom metadata compilations by name") + } + } override val platformType: KotlinPlatformType get() = KotlinPlatformType.common @@ -34,7 +41,7 @@ class KotlinMetadataTargetPreset( const val PRESET_NAME = "metadata" } - override fun createKotlinTargetConfigurator(): KotlinOnlyTargetConfigurator = + override fun createKotlinTargetConfigurator(): KotlinOnlyTargetConfigurator, KotlinMetadataTarget> = KotlinMetadataTargetConfigurator(kotlinPluginVersion) override fun instantiateTarget(): KotlinMetadataTarget { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt index 6bef86618f0..8fbf801b57a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt @@ -17,17 +17,19 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationWithResources import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget import java.util.concurrent.Callable -class KotlinNativeCompilation( - override val target: KotlinNativeTarget, +abstract class AbstractKotlinNativeCompilation( + target: KotlinTarget, val konanTarget: KonanTarget, - name: String -) : AbstractKotlinCompilation(target, name), KotlinCompilationWithResources { + compilationName: String +) : AbstractKotlinCompilation(target, compilationName) { override val kotlinOptions: KotlinCommonOptions get() = compileKotlinTask.kotlinOptions @@ -35,9 +37,6 @@ class KotlinNativeCompilation( 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. @@ -45,65 +44,32 @@ class KotlinNativeCompilation( internal val allSources: MutableSet = mutableSetOf() // TODO: Move into the compilation task when the linking task does klib linking instead of compilation. - internal val commonSources: ConfigurableFileCollection = project.files() + internal val commonSources: ConfigurableFileCollection = target.project.files() - @Deprecated("Use associateWith(...) to add a friend compilation and associateWith to get all of them.") - var friendCompilationName: String? = null - set(value) { - SingleWarningPerBuild.show( - project, - "Property `friendCompilationName` of `KotlinNativeCompilation` has been deprecated and will be removed. " + - "Use `associateWith(...)` instead." - ) - field = value - } - - internal val friendCompilations: List - get() = mutableListOf().apply { - @Suppress("DEPRECATION") - friendCompilationName?.let { - add(target.compilations.getByName(it)) - } - addAll(associateWithTransitiveClosure.filterIsInstance()) - } - - // Native-specific DSL. - private fun showDeprecationWarning() = SingleWarningPerBuild.show( - project, - "The compilation.extraOpts method used in this build is deprecated. Use compilation.kotlinOptions.freeCompilerArgs instead." - ) - - internal var extraOptsNoWarn: MutableList = mutableListOf() - - @Deprecated("Use kotlinOptions.freeCompilerArgs instead", ReplaceWith("kotlinOptions.freeCompilerArgs")) - var extraOpts: MutableList - get() { - showDeprecationWarning() - return extraOptsNoWarn - } - set(value) { - showDeprecationWarning() - extraOptsNoWarn = value - } - - @Deprecated("Use kotlinOptions.freeCompilerArgs instead", ReplaceWith("kotlinOptions.freeCompilerArgs += values as Array")) - @Suppress("Deprecation") - fun extraOpts(vararg values: Any) = extraOpts(values.toList()) - - @Deprecated("Use kotlinOptions.freeCompilerArgs instead", ReplaceWith("kotlinOptions.freeCompilerArgs += values as List")) - @Suppress("Deprecation") - fun extraOpts(values: List) { - extraOpts.addAll(values.map { it.toString() }) + override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy) { + allSources.add(sourceSet.kotlin) + commonSources.from(target.project.files(Callable { if (addAsCommonSources.value) sourceSet.kotlin else emptyList() })) } + // Endorsed library controller. + var enableEndorsedLibs: Boolean = false +} + +class KotlinNativeCompilation( + override val target: KotlinNativeTarget, + konanTarget: KonanTarget, + name: String +) : AbstractKotlinNativeCompilation(target, konanTarget, name), + KotlinCompilationWithResources { + + private val project: Project + get() = target.project + // Interop DSL. val cinterops = project.container(DefaultCInteropSettings::class.java) { cinteropName -> DefaultCInteropSettings(project, cinteropName, this) } - // Endorsed library controller. - var enableEndorsedLibs = false - fun cinterops(action: Closure) = cinterops(ConfigureUtil.configureUsing(action)) fun cinterops(action: Action>) = action.execute(cinterops) @@ -124,8 +90,10 @@ class KotlinNativeCompilation( val binariesTaskName: String get() = lowerCamelCaseName(target.disambiguationClassifier, compilationName, "binaries") - override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Lazy) { - allSources.add(sourceSet.kotlin) - commonSources.from(project.files(Callable { if (addAsCommonSources.value) sourceSet.kotlin else emptyList() })) - } -} \ No newline at end of file + override val kotlinOptions: KotlinCommonOptions + get() = compileKotlinTask.kotlinOptions +} + +class KotlinSharedNativeCompilation(override val target: KotlinMetadataTarget, name: String) : + AbstractKotlinNativeCompilation(target, HostManager.host, name), + KotlinMetadataCompilation \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt index 3869d6d93ac..df2dc901138 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt @@ -6,10 +6,9 @@ @file:Suppress("PackageDirectoryMismatch") // Old package for compatibility package org.jetbrains.kotlin.gradle.plugin.mpp -import org.gradle.api.Project +import org.jetbrains.kotlin.konan.target.HostManager class KotlinNativeCompilationFactory( - val project: Project, val target: KotlinNativeTarget ) : KotlinCompilationFactory { @@ -22,4 +21,14 @@ class KotlinNativeCompilationFactory( // Note: such validation should be done in the whenEvaluate block because // a user can change args during project configuration. KotlinNativeCompilation(target, target.konanTarget, name) +} + +class KotlinSharedNativeCompilationFactory( + val target: KotlinMetadataTarget +): KotlinCompilationFactory { + override val itemClass: Class + get() = KotlinSharedNativeCompilation::class.java + + override fun create(name: String): KotlinSharedNativeCompilation = + KotlinSharedNativeCompilation(target, name) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index 196d998e788..20b83e2ccde 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -17,6 +17,7 @@ import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet import org.gradle.api.plugins.BasePlugin import org.gradle.api.tasks.Copy import org.gradle.api.tasks.Exec +import org.gradle.api.tasks.TaskProvider import org.gradle.language.base.plugins.LifecycleBasePlugin import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME @@ -41,7 +42,7 @@ open class KotlinNativeTargetConfigurator( createTestCompilation = true ) { private fun Project.klibOutputDirectory( - compilation: KotlinNativeCompilation + compilation: AbstractKotlinNativeCompilation ): File { val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() return buildDir.resolve("classes/kotlin/$targetSubDirectory${compilation.name}") @@ -148,35 +149,39 @@ open class KotlinNativeTargetConfigurator( } } - private fun Project.createKlibCompilationTask(compilation: KotlinNativeCompilation) { - val compileTask = tasks.create( + internal fun Project.createKlibCompilationTask(compilation: AbstractKotlinNativeCompilation): TaskProvider { + val compileTask = project.registerTask( compilation.compileKotlinTaskName, KotlinNativeCompile::class.java - ).apply { - this.compilation = compilation - group = BasePlugin.BUILD_GROUP - description = "Compiles a klibrary from the '${compilation.name}' " + + ) { task -> + task.compilation = compilation + task.group = BasePlugin.BUILD_GROUP + task.description = "Compiles a klibrary from the '${compilation.name}' " + "compilation for target '${compilation.platformType.name}'." - enabled = compilation.konanTarget.enabledOnCurrentHost + task.enabled = compilation.konanTarget.enabledOnCurrentHost - destinationDir = klibOutputDirectory(compilation) - addCompilerPlugins() + task.destinationDir = klibOutputDirectory(compilation) + task.addCompilerPlugins() compilation.output.addClassesDir { - project.files(this.outputFile).builtBy(this) + project.files(task.outputFile).builtBy(task) } } project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTask) if (compilation.compilationName == MAIN_COMPILATION_NAME) { + compilation as? KotlinNativeCompilation ?: error("Main shared-Native compilation is not yet supported!") + project.tasks.getByName(compilation.target.artifactsTaskName).apply { dependsOn(compileTask) } project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply { dependsOn(compileTask) } - createRegularKlibArtifact(compilation, compileTask) + createRegularKlibArtifact(compilation, compileTask.get() /*TODO don't instantiate the task eagerly*/) } + + return compileTask } private fun Project.createCInteropTasks(compilation: KotlinNativeCompilation) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt index cf16cd4ae11..ef358813e13 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt @@ -87,7 +87,7 @@ abstract class AbstractKotlinNativeTargetPreset( disambiguationClassifier = name preset = this@AbstractKotlinNativeTargetPreset - val compilationFactory = KotlinNativeCompilationFactory(project, this) + val compilationFactory = KotlinNativeCompilationFactory(this) compilations = project.container(compilationFactory.itemClass, compilationFactory) } @@ -209,5 +209,5 @@ internal val KonanTarget.isCurrentHost: Boolean internal val KonanTarget.enabledOnCurrentHost get() = HostManager().isEnabled(this) -internal val KotlinNativeCompilation.isMainCompilation: Boolean +internal val AbstractKotlinNativeCompilation.isMainCompilation: Boolean get() = name == KotlinCompilation.MAIN_COMPILATION_NAME diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index e2928fe0712..0dc1ac05b23 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -90,7 +90,8 @@ private fun FileCollection.filterOutPublishableInteropLibs(project: Project): Fi /** * We pass to the compiler: * - * - Only *.klib files. A dependency configuration may contain jar files + * - Only *.klib files and directories (normally containing an unpacked klib). + * A dependency configuration may contain jar files * (e.g. when a common artifact was directly added to commonMain source set). * So, we need to filter out such artifacts. * @@ -103,7 +104,7 @@ private fun FileCollection.filterOutPublishableInteropLibs(project: Project): Fi * uses them by default so we don't pass them to the compiler explicitly. */ private fun Collection.filterKlibsPassedToCompiler(project: Project) = filter { - it.extension == "klib" && it.exists() && !it.providedByCompiler(project) + (it.extension == "klib" || it.isDirectory) && it.exists() && !it.providedByCompiler(project) } // endregion @@ -115,7 +116,7 @@ abstract class AbstractKotlinNativeCompile : Abstra } @get:Internal - abstract val compilation: KotlinNativeCompilation + abstract val compilation: AbstractKotlinNativeCompilation // region inputs/outputs @get:Input @@ -245,6 +246,11 @@ abstract class AbstractKotlinNativeCompile : Abstra addArg("-target", target) addArg("-p", outputKind.name.toLowerCase()) + if (compilation is KotlinSharedNativeCompilation) { + add("-Xklib-mpp") + add("-Xmetadata-klib") + } + addArg("-o", outputFile.get().absolutePath) // Libraries. @@ -273,7 +279,7 @@ abstract class AbstractKotlinNativeCompile : Abstra */ open class KotlinNativeCompile : AbstractKotlinNativeCompile(), KotlinCompile { @Internal - override lateinit var compilation: KotlinNativeCompilation + final override lateinit var compilation: AbstractKotlinNativeCompilation @get:Input override val outputKind = LIBRARY @@ -300,7 +306,7 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile - get() = compilation.extraOptsNoWarn - set(value) { - compilation.extraOptsNoWarn = value.toMutableList() - } + override var freeCompilerArgs: List = listOf() } @get:Input @@ -582,7 +582,7 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile().apply { - val friendCompilations = compilation.friendCompilations + val friendCompilations = compilation.associateWithTransitiveClosure.toList() val friendFiles = if (friendCompilations.isNotEmpty()) project.files( project.provider { friendCompilations.map { it.output.allOutputs } + compilation.friendArtifacts } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index 411ae10531b..f90339f4ac2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformCommonOptionsImpl import org.jetbrains.kotlin.gradle.dsl.fillDefaultValues import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.incremental.ChangedFiles import java.io.File @@ -52,6 +53,10 @@ open class KotlinCompileCommon : AbstractKotlinCompile) { associateWith += other }