diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/GeneralNativeIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/GeneralNativeIT.kt index d196b25d5da..259c7448f97 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/GeneralNativeIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/GeneralNativeIT.kt @@ -51,6 +51,7 @@ class GeneralNativeIT : BaseGradleIT() { assertTasksExecuted(":two:compileKotlinLinux") assertNotContains("Parallel in-process execution of the Kotlin/Native compiler detected.") } - } + + // TODO: Move native specific tests from NewMultiplatformIT here. } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index e4a91267de7..b008be9a210 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -21,10 +21,13 @@ import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.util.* import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.HostManager +import org.jetbrains.kotlin.library.KLIB_PROPERTY_SHORT_NAME +import org.jetbrains.kotlin.library.KLIB_PROPERTY_UNIQUE_NAME import org.junit.Assert import org.junit.Ignore import org.junit.Test import java.io.File +import java.util.* import java.util.jar.JarFile import java.util.zip.ZipFile import kotlin.test.assertEquals @@ -2530,4 +2533,41 @@ class NewMultiplatformIT : BaseGradleIT() { } } } + + @Test + fun testKlibsWithTheSameProjectName() = with(transformProjectWithPluginsDsl("new-mpp-klibs-with-same-name")) { + // KT-36721. + build("assemble") { + assertSuccessful() + assertTasksExecuted( + ":foo:foo:compileKotlinJs", + ":foo:foo:compileKotlinLinux", + ":foo:compileKotlinJs", + ":foo:compileKotlinLinux", + ":compileKotlinJs", + ":compileKotlinLinux" + ) + + fun getManifest(relativePath: String): Properties = + with(ZipFile(projectDir.resolve(relativePath))) { + return this.getInputStream(getEntry("default/manifest")).use { stream -> + Properties().apply { load(stream) } + } + } + + val interopManifest = getManifest("foo/build/classes/kotlin/linux/main/foo-cinterop-bar.klib") + assertEquals("org.sample.one.foo-cinterop-bar", interopManifest[KLIB_PROPERTY_UNIQUE_NAME]) + + val nativeManifest = getManifest("foo/build/classes/kotlin/linux/main/foo.klib") + assertEquals("org.sample.one.foo", nativeManifest[KLIB_PROPERTY_UNIQUE_NAME]) + // Check the short name that is used as a prefix in generated ObjC headers. + assertEquals("foo", nativeManifest[KLIB_PROPERTY_SHORT_NAME]) + + val jsManifest = projectDir.resolve("foo/build/classes/kotlin/js/main/default/manifest") + .inputStream().use { stream -> + Properties().apply { load(stream) } + } + assertEquals("org.sample.one.foo", jsManifest[KLIB_PROPERTY_UNIQUE_NAME]) + } + } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/build.gradle.kts new file mode 100644 index 00000000000..8b2bdaa7f9f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/build.gradle.kts @@ -0,0 +1,28 @@ +plugins { + kotlin("multiplatform").version("") +} + +group = "org.sample.root" + +allprojects { + repositories { + mavenLocal() + jcenter() + } +} + +kotlin { + linuxX64("linux") + js { + nodejs() + } + + sourceSets["commonMain"].dependencies { + implementation(kotlin("stdlib-common")) + implementation(project(":foo")) + } + + sourceSets["jsMain"].dependencies { + implementation(kotlin("stdlib-js")) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/build.gradle.kts new file mode 100644 index 00000000000..6833bfa723e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/build.gradle.kts @@ -0,0 +1,25 @@ +plugins { + kotlin("multiplatform") +} + +group="org.sample.one" + +kotlin { + linuxX64("linux") { + val bar by compilations["main"].cinterops.creating + } + js { + nodejs() + } + + sourceSets["commonMain"].dependencies { + implementation(kotlin("stdlib-common")) + implementation(project(":foo:foo")) + } + + sourceSets["jsMain"].dependencies { + implementation(kotlin("stdlib-js")) + } +} + + diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/build.gradle.kts new file mode 100644 index 00000000000..fad615393a2 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/build.gradle.kts @@ -0,0 +1,22 @@ +plugins { + kotlin("multiplatform") +} + +group="org.sample.two" + +kotlin { + linuxX64("linux") { + val bar by compilations["main"].cinterops.creating + } + js { + nodejs() + } + + sourceSets["commonMain"].dependencies { + implementation(kotlin("stdlib-common")) + } + + sourceSets["jsMain"].dependencies { + implementation(kotlin("stdlib-js")) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/jsMain/kotlin/foofoo.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/jsMain/kotlin/foofoo.kt new file mode 100644 index 00000000000..7c7f6a04fda --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/jsMain/kotlin/foofoo.kt @@ -0,0 +1,3 @@ +fun foofoo() { + println("foofoo") +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/linuxMain/kotlin/foofoo.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/linuxMain/kotlin/foofoo.kt new file mode 100644 index 00000000000..2ade0e138ef --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/linuxMain/kotlin/foofoo.kt @@ -0,0 +1,5 @@ +import foo.* + +fun foofoo() { + println("foofoo: ${answer()}") +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/nativeInterop/cinterop/bar.def b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/nativeInterop/cinterop/bar.def new file mode 100644 index 00000000000..841902a153d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/foo/src/nativeInterop/cinterop/bar.def @@ -0,0 +1,8 @@ +language = C +package = foo + +--- + +int answer() { + return 42; +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/commonMain/kotlin/foo.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/commonMain/kotlin/foo.kt new file mode 100644 index 00000000000..ad824a81414 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/commonMain/kotlin/foo.kt @@ -0,0 +1 @@ +expect fun foo() \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/jsMain/kotlin/foo.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/jsMain/kotlin/foo.kt new file mode 100644 index 00000000000..e35e9cd0d76 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/jsMain/kotlin/foo.kt @@ -0,0 +1,4 @@ +actual fun foo() { + println("foo") + foofoo() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/linuxMain/kotlin/foo.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/linuxMain/kotlin/foo.kt new file mode 100644 index 00000000000..19eb42cfa83 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/linuxMain/kotlin/foo.kt @@ -0,0 +1,6 @@ +import foo.* + +actual fun foo() { + println("foo: ${question()}") + foofoo() +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/nativeInterop/cinterop/bar.def b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/nativeInterop/cinterop/bar.def new file mode 100644 index 00000000000..19c43e0959f --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/foo/src/nativeInterop/cinterop/bar.def @@ -0,0 +1,8 @@ +language = C +package = foo + +--- + +const char* question() { + return "To be, or not to be"; +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/gradle.properties b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/gradle.properties new file mode 100644 index 00000000000..511353c7f9b --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/gradle.properties @@ -0,0 +1,2 @@ +kotlin.native.disableCompilerDaemon=true +kotlin.js.compiler=ir diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/settings.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/settings.gradle.kts new file mode 100644 index 00000000000..1c2f6bede5d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/settings.gradle.kts @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + mavenLocal() + jcenter() + gradlePluginPortal() + } +} + +include("foo") +include("foo:foo") diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/src/commonMain/kotlin/main.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/src/commonMain/kotlin/main.kt new file mode 100644 index 00000000000..b585ff88912 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-klibs-with-same-name/src/commonMain/kotlin/main.kt @@ -0,0 +1,3 @@ +fun main() { + println("main") +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt index 701ecec2ff9..fabca44594d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/CompilerFlags.kt @@ -17,4 +17,6 @@ internal const val ENABLE_DCE = "-Xir-dce" internal const val GENERATE_D_TS = "-Xgenerate-dts" internal const val PRODUCE_JS = "-Xir-produce-js" -internal const val PRODUCE_UNZIPPED_KLIB = "-Xir-produce-klib-dir" \ No newline at end of file +internal const val PRODUCE_UNZIPPED_KLIB = "-Xir-produce-klib-dir" + +internal const val MODULE_NAME = "-Xir-module-name" \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt index 26bd552d7cd..8a89d395ae8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt @@ -7,14 +7,15 @@ package org.jetbrains.kotlin.gradle.targets.js.ir import org.gradle.api.tasks.bundling.Zip import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.KotlinJsIrSourceSetProcessor -import org.jetbrains.kotlin.gradle.plugin.KotlinOnlyTargetConfigurator import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTestsConfigurator import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.testTaskName +import org.jetbrains.kotlin.gradle.utils.klibModuleName open class KotlinJsIrTargetConfigurator(kotlinPluginVersion: String) : KotlinOnlyTargetConfigurator(true, true, kotlinPluginVersion), @@ -63,17 +64,25 @@ open class KotlinJsIrTargetConfigurator(kotlinPluginVersion: String) : override fun configureCompilations(target: KotlinJsIrTarget) { super.configureCompilations(target) - target.compilations.all { - it.compileKotlinTask.kotlinOptions { + target.compilations.all { compilation -> + compilation.compileKotlinTask.kotlinOptions { configureOptions() freeCompilerArgs += listOf( DISABLE_PRE_IR, PRODUCE_UNZIPPED_KLIB ) + + // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). + val baseName = if (compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME) { + target.project.name + } else { + "${target.project.name}_${compilation.name}" + } + freeCompilerArgs += listOf("$MODULE_NAME=${target.project.klibModuleName(baseName)}") } - it.binaries + compilation.binaries .withType(JsIrBinary::class.java) .all { it.linkTask.configure { linkTask -> 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 83b1a2fe7df..8e8b427a843 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 @@ -24,6 +24,8 @@ import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.utils.getValue +import org.jetbrains.kotlin.gradle.utils.klibModuleName import org.jetbrains.kotlin.konan.library.KLIB_INTEROP_IR_PROVIDER_IDENTIFIER import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind.* @@ -297,6 +299,14 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile = mutableListOf().apply { addAll(super.buildCompilerArgs()) + // Configure FQ module name to avoid cyclic dependencies in klib manifests (see KT-36721). + addArg("-module-name", moduleName) + add("-Xshort-module-name=$shortModuleName") val friends = friendModule?.files if (friends != null && friends.isNotEmpty()) { addArg("-friend-modules", friends.map { it.absolutePath }.joinToString(File.pathSeparator)) @@ -885,15 +898,22 @@ open class CInteropProcess : DefaultTask() { val interopName: String @Internal get() = settings.name - val outputFileName: String - @Internal get() = with(CompilerOutputKind.LIBRARY) { - val baseName = settings.compilation.let { + val baseKlibName: String + @Internal get() { + val compilationPrefix = settings.compilation.let { if (it.isMainCompilation) project.name else it.name } - val suffix = suffix(konanTarget) - return "$baseName-cinterop-$interopName$suffix" + return "$compilationPrefix-cinterop-$interopName" } + val outputFileName: String + @Internal get() = with(CompilerOutputKind.LIBRARY) { + "$baseKlibName${suffix(konanTarget)}" + } + + val moduleName: String + @Input get() = project.klibModuleName(baseKlibName) + @get:Internal val outputFile: File get() = outputFileProvider.get() @@ -961,6 +981,10 @@ open class CInteropProcess : DefaultTask() { addArgs("-compiler-option", allHeadersDirs.map { "-I${it.absolutePath}" }) addArgs("-headerFilterAdditionalSearchPrefix", headerFilterDirs.map { it.absolutePath }) + if (project.konanVersion.isAtLeast(1, 4, 0)) { + addArg("-Xmodule-name", moduleName) + } + addAll(extraOpts) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/klibUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/klibUtils.kt new file mode 100644 index 00000000000..d9b78b28228 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/klibUtils.kt @@ -0,0 +1,11 @@ +/* + * 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.utils + +import org.gradle.api.Project + +internal fun Project.klibModuleName(baseName: String = project.name): String = + if (group.toString().isNotEmpty()) "$group.$baseName" else baseName \ No newline at end of file