[Gradle, Native/JS] Specify FQ module name for klibs
By default, a unique name for a klibrary equals to a klib file name. In the MPP plugin, the file name equals to a Gradle project name. But the project name is not unique enough. E.g. there is a situation when there are several projects with the same simple name inside a single Gradle build. If one of these projects depends on another, the compiler will report a false cyclic dependency error. This patch partially fixes this problem by specifying a custom unique name for produced klibs based on project group and name. We still can get a unique name clash in a case of equal groups and project names. But in this case the cyclic dependency error looks much more logical for user. Also this patch specifies short names for native klibs to avoid long declaration prefixes in framework headers. Issue #KT-36721 Fixed Issue #KT-38220 Fixed
This commit is contained in:
+2
-1
@@ -51,6 +51,7 @@ class GeneralNativeIT : BaseGradleIT() {
|
|||||||
assertTasksExecuted(":two:compileKotlinLinux")
|
assertTasksExecuted(":two:compileKotlinLinux")
|
||||||
assertNotContains("Parallel in-process execution of the Kotlin/Native compiler detected.")
|
assertNotContains("Parallel in-process execution of the Kotlin/Native compiler detected.")
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: Move native specific tests from NewMultiplatformIT here.
|
||||||
}
|
}
|
||||||
+40
@@ -21,10 +21,13 @@ import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
|
|||||||
import org.jetbrains.kotlin.gradle.util.*
|
import org.jetbrains.kotlin.gradle.util.*
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
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.Assert
|
||||||
import org.junit.Ignore
|
import org.junit.Ignore
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.util.*
|
||||||
import java.util.jar.JarFile
|
import java.util.jar.JarFile
|
||||||
import java.util.zip.ZipFile
|
import java.util.zip.ZipFile
|
||||||
import kotlin.test.assertEquals
|
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])
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+28
@@ -0,0 +1,28 @@
|
|||||||
|
plugins {
|
||||||
|
kotlin("multiplatform").version("<pluginMarkerVersion>")
|
||||||
|
}
|
||||||
|
|
||||||
|
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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
+25
@@ -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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
+22
@@ -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"))
|
||||||
|
}
|
||||||
|
}
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun foofoo() {
|
||||||
|
println("foofoo")
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
import foo.*
|
||||||
|
|
||||||
|
fun foofoo() {
|
||||||
|
println("foofoo: ${answer()}")
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
language = C
|
||||||
|
package = foo
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
int answer() {
|
||||||
|
return 42;
|
||||||
|
}
|
||||||
+1
@@ -0,0 +1 @@
|
|||||||
|
expect fun foo()
|
||||||
+4
@@ -0,0 +1,4 @@
|
|||||||
|
actual fun foo() {
|
||||||
|
println("foo")
|
||||||
|
foofoo()
|
||||||
|
}
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
import foo.*
|
||||||
|
|
||||||
|
actual fun foo() {
|
||||||
|
println("foo: ${question()}")
|
||||||
|
foofoo()
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
language = C
|
||||||
|
package = foo
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
const char* question() {
|
||||||
|
return "To be, or not to be";
|
||||||
|
}
|
||||||
+2
@@ -0,0 +1,2 @@
|
|||||||
|
kotlin.native.disableCompilerDaemon=true
|
||||||
|
kotlin.js.compiler=ir
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
jcenter()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
include("foo")
|
||||||
|
include("foo:foo")
|
||||||
+3
@@ -0,0 +1,3 @@
|
|||||||
|
fun main() {
|
||||||
|
println("main")
|
||||||
|
}
|
||||||
+3
-1
@@ -17,4 +17,6 @@ internal const val ENABLE_DCE = "-Xir-dce"
|
|||||||
internal const val GENERATE_D_TS = "-Xgenerate-dts"
|
internal const val GENERATE_D_TS = "-Xgenerate-dts"
|
||||||
|
|
||||||
internal const val PRODUCE_JS = "-Xir-produce-js"
|
internal const val PRODUCE_JS = "-Xir-produce-js"
|
||||||
internal const val PRODUCE_UNZIPPED_KLIB = "-Xir-produce-klib-dir"
|
internal const val PRODUCE_UNZIPPED_KLIB = "-Xir-produce-klib-dir"
|
||||||
|
|
||||||
|
internal const val MODULE_NAME = "-Xir-module-name"
|
||||||
+13
-4
@@ -7,14 +7,15 @@ package org.jetbrains.kotlin.gradle.targets.js.ir
|
|||||||
|
|
||||||
import org.gradle.api.tasks.bundling.Zip
|
import org.gradle.api.tasks.bundling.Zip
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions
|
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.KotlinJsIrSourceSetProcessor
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinOnlyTargetConfigurator
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTestsConfigurator
|
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTestsConfigurator
|
||||||
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
|
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
||||||
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
|
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
|
||||||
import org.jetbrains.kotlin.gradle.testing.testTaskName
|
import org.jetbrains.kotlin.gradle.testing.testTaskName
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.klibModuleName
|
||||||
|
|
||||||
open class KotlinJsIrTargetConfigurator(kotlinPluginVersion: String) :
|
open class KotlinJsIrTargetConfigurator(kotlinPluginVersion: String) :
|
||||||
KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true, true, kotlinPluginVersion),
|
KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true, true, kotlinPluginVersion),
|
||||||
@@ -63,17 +64,25 @@ open class KotlinJsIrTargetConfigurator(kotlinPluginVersion: String) :
|
|||||||
override fun configureCompilations(target: KotlinJsIrTarget) {
|
override fun configureCompilations(target: KotlinJsIrTarget) {
|
||||||
super.configureCompilations(target)
|
super.configureCompilations(target)
|
||||||
|
|
||||||
target.compilations.all {
|
target.compilations.all { compilation ->
|
||||||
it.compileKotlinTask.kotlinOptions {
|
compilation.compileKotlinTask.kotlinOptions {
|
||||||
configureOptions()
|
configureOptions()
|
||||||
|
|
||||||
freeCompilerArgs += listOf(
|
freeCompilerArgs += listOf(
|
||||||
DISABLE_PRE_IR,
|
DISABLE_PRE_IR,
|
||||||
PRODUCE_UNZIPPED_KLIB
|
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)
|
.withType(JsIrBinary::class.java)
|
||||||
.all {
|
.all {
|
||||||
it.linkTask.configure { linkTask ->
|
it.linkTask.configure { linkTask ->
|
||||||
|
|||||||
+29
-5
@@ -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.cocoapods.asValidFrameworkName
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
|
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.library.KLIB_INTEROP_IR_PROVIDER_IDENTIFIER
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind.*
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind.*
|
||||||
@@ -297,6 +299,14 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
|||||||
override val baseName: String
|
override val baseName: String
|
||||||
get() = if (compilation.isMainCompilation) project.name else "${project.name}_${compilation.name}"
|
get() = if (compilation.isMainCompilation) project.name else "${project.name}_${compilation.name}"
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
val moduleName: String by project.provider {
|
||||||
|
project.klibModuleName(baseName)
|
||||||
|
}
|
||||||
|
|
||||||
|
@get:Input
|
||||||
|
val shortModuleName: String by project.provider { baseName }
|
||||||
|
|
||||||
// Inputs and outputs.
|
// Inputs and outputs.
|
||||||
// region Sources.
|
// region Sources.
|
||||||
@InputFiles
|
@InputFiles
|
||||||
@@ -378,6 +388,9 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
|||||||
override fun buildCompilerArgs(): List<String> = mutableListOf<String>().apply {
|
override fun buildCompilerArgs(): List<String> = mutableListOf<String>().apply {
|
||||||
addAll(super.buildCompilerArgs())
|
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
|
val friends = friendModule?.files
|
||||||
if (friends != null && friends.isNotEmpty()) {
|
if (friends != null && friends.isNotEmpty()) {
|
||||||
addArg("-friend-modules", friends.map { it.absolutePath }.joinToString(File.pathSeparator))
|
addArg("-friend-modules", friends.map { it.absolutePath }.joinToString(File.pathSeparator))
|
||||||
@@ -885,15 +898,22 @@ open class CInteropProcess : DefaultTask() {
|
|||||||
val interopName: String
|
val interopName: String
|
||||||
@Internal get() = settings.name
|
@Internal get() = settings.name
|
||||||
|
|
||||||
val outputFileName: String
|
val baseKlibName: String
|
||||||
@Internal get() = with(CompilerOutputKind.LIBRARY) {
|
@Internal get() {
|
||||||
val baseName = settings.compilation.let {
|
val compilationPrefix = settings.compilation.let {
|
||||||
if (it.isMainCompilation) project.name else it.name
|
if (it.isMainCompilation) project.name else it.name
|
||||||
}
|
}
|
||||||
val suffix = suffix(konanTarget)
|
return "$compilationPrefix-cinterop-$interopName"
|
||||||
return "$baseName-cinterop-$interopName$suffix"
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val outputFileName: String
|
||||||
|
@Internal get() = with(CompilerOutputKind.LIBRARY) {
|
||||||
|
"$baseKlibName${suffix(konanTarget)}"
|
||||||
|
}
|
||||||
|
|
||||||
|
val moduleName: String
|
||||||
|
@Input get() = project.klibModuleName(baseKlibName)
|
||||||
|
|
||||||
@get:Internal
|
@get:Internal
|
||||||
val outputFile: File
|
val outputFile: File
|
||||||
get() = outputFileProvider.get()
|
get() = outputFileProvider.get()
|
||||||
@@ -961,6 +981,10 @@ open class CInteropProcess : DefaultTask() {
|
|||||||
addArgs("-compiler-option", allHeadersDirs.map { "-I${it.absolutePath}" })
|
addArgs("-compiler-option", allHeadersDirs.map { "-I${it.absolutePath}" })
|
||||||
addArgs("-headerFilterAdditionalSearchPrefix", headerFilterDirs.map { it.absolutePath })
|
addArgs("-headerFilterAdditionalSearchPrefix", headerFilterDirs.map { it.absolutePath })
|
||||||
|
|
||||||
|
if (project.konanVersion.isAtLeast(1, 4, 0)) {
|
||||||
|
addArg("-Xmodule-name", moduleName)
|
||||||
|
}
|
||||||
|
|
||||||
addAll(extraOpts)
|
addAll(extraOpts)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
@@ -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
|
||||||
Reference in New Issue
Block a user