From 9f15cc11a7d4cc4350ca9f2e0f7c7479724ad1bb Mon Sep 17 00:00:00 2001 From: Pavel Kirpichenkov Date: Wed, 11 Jan 2023 17:55:15 +0200 Subject: [PATCH] [MPP] Fix import of cinterops for non-leaf single target source sets KT-54975 --- .../gradle/MppIdeDependencyResolutionIT.kt | 44 ++++++++++++++++++- .../build.gradle.kts | 40 +++++++++++++++++ .../libs/include/w/w.h | 0 .../src/nativeInterop/cinterop/w.def | 2 + .../cinteropImport/settings.gradle.kts | 1 + .../plugin/ide/IdeMultiplatformImport.kt | 3 ++ .../ide/IdeMultiplatformImportFactory.kt | 6 +-- .../KotlinMetadataTargetConfigurator.kt | 5 +++ 8 files changed, 97 insertions(+), 4 deletions(-) create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/build.gradle.kts create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/libs/include/w/w.h create mode 100644 libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/src/nativeInterop/cinterop/w.def diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/MppIdeDependencyResolutionIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/MppIdeDependencyResolutionIT.kt index d1c38400ae0..1dc832a4b05 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/MppIdeDependencyResolutionIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/MppIdeDependencyResolutionIT.kt @@ -110,7 +110,8 @@ class MppIdeDependencyResolutionIT : KGPBaseTest() { dependencies["commonTest"].cinteropDependencies() .assertMatches(binaryCoordinates(Regex("a:dep.*\\(linux_arm64, linux_x64\\)"))) - // TODO (kirpichenkov): consider extracting cinterops from platform libraries (they are library roots currently) + // CInterops are currently imported as extra roots of a platform publication, not as separate libraries + // This is a bit inconsistent with other CInterop dependencies, but correctly represents the published artifacts dependencies["linuxX64Main"].cinteropDependencies().assertMatches() dependencies["linuxX64Test"].cinteropDependencies().assertMatches() dependencies["linuxArm64Main"].cinteropDependencies().assertMatches() @@ -132,6 +133,47 @@ class MppIdeDependencyResolutionIT : KGPBaseTest() { dependencies["linuxArm64Test"].cinteropDependencies() .assertMatches(binaryCoordinates(Regex("a:dep-with-cinterop-cinterop-dep.*linux_arm64"))) } + + resolveIdeDependencies("client-with-complex-hierarchy") { dependencies -> + dependencies["commonMain"].cinteropDependencies().assertMatches() + dependencies["commonTest"].cinteropDependencies().assertMatches() + dependencies["nativeMain"].cinteropDependencies().assertMatches( + binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*\\(ios_arm64, ios_x64, linux_x64\\)")) + ) + dependencies["nativeTest"].cinteropDependencies().assertMatches( + binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*\\(ios_arm64, ios_x64, linux_x64\\)")) + ) + + dependencies["iosMain"].cinteropDependencies() + .assertMatches(binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*\\(ios_arm64, ios_x64\\)"))) + dependencies["iosTest"].cinteropDependencies() + .assertMatches(binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*\\(ios_arm64, ios_x64\\)"))) + dependencies["iosX64Main"].cinteropDependencies() + .assertMatches(binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:ios_x64$"))) + dependencies["iosX64Test"].cinteropDependencies() + .assertMatches(binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:ios_x64$"))) + dependencies["iosArm64Main"].cinteropDependencies() + .assertMatches(binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:ios_arm64$"))) + dependencies["iosArm64Test"].cinteropDependencies() + .assertMatches(binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:ios_arm64$"))) + + dependencies["linuxOtherMain"].cinteropDependencies().assertMatches( + binaryCoordinates(Regex("a:dep-with-cinterop-cinterop-dep.*:linux_x64$")), + binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:linux_x64$")), + ) + dependencies["linuxOtherTest"].cinteropDependencies().assertMatches( + binaryCoordinates(Regex("a:dep-with-cinterop-cinterop-dep.*:linux_x64$")), + binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:linux_x64$")), + ) + dependencies["linuxMain"].cinteropDependencies().assertMatches( + binaryCoordinates(Regex("a:dep-with-cinterop-cinterop-dep.*:linux_x64$")), + binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:linux_x64$")), + ) + dependencies["linuxTest"].cinteropDependencies().assertMatches( + binaryCoordinates(Regex("a:dep-with-cinterop-cinterop-dep.*:linux_x64$")), + binaryCoordinates(Regex("a:client-with-complex-hierarchy-cinterop-w.*:linux_x64$")) + ) + } } } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/build.gradle.kts new file mode 100644 index 00000000000..f5a182e1dd1 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/build.gradle.kts @@ -0,0 +1,40 @@ +plugins { + kotlin("multiplatform") +} + +kotlin { + jvm() + ios { + compilations.getByName("main").cinterops.create("w") + } + linuxX64("linux").compilations.getByName("main").cinterops.create("w") + + sourceSets { + val commonMain by getting + val commonTest by getting + val linuxMain by getting + val linuxTest by getting + + val nativeMain by creating { + this.dependsOn(commonMain) + getByName("iosMain").dependsOn(this) + } + val nativeTest by creating { + this.dependsOn(commonTest) + getByName("iosTest").dependsOn(this) + } + + val linuxOtherMain by creating { + this.dependsOn(nativeMain) + linuxMain.dependsOn(this) + + dependencies { + implementation(project(":dep-with-cinterop")) + } + } + val linuxOtherTest by creating { + this.dependsOn(nativeTest) + linuxTest.dependsOn(this) + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/libs/include/w/w.h b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/libs/include/w/w.h new file mode 100644 index 00000000000..e69de29bb2d diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/src/nativeInterop/cinterop/w.def b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/src/nativeInterop/cinterop/w.def new file mode 100644 index 00000000000..88e8245e229 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/client-with-complex-hierarchy/src/nativeInterop/cinterop/w.def @@ -0,0 +1,2 @@ +headers = w/w.h +compilerOpts = -Ilibs/include \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/settings.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/settings.gradle.kts index 47d69c4fa9c..cdeb86b0643 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/settings.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/cinteropImport/settings.gradle.kts @@ -4,3 +4,4 @@ rootProject.name = "cinterops" include(":dep-with-cinterop") include(":client-for-binary-dep") include(":client-for-project-to-project-dep") +include(":client-with-complex-hierarchy") diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImport.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImport.kt index 787a6acea1f..df35676e228 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImport.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImport.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.gradle.plugin.ide.IdeMultiplatformImport.SourceSetCo import org.jetbrains.kotlin.gradle.plugin.sources.internal import org.jetbrains.kotlin.gradle.plugin.sources.project import org.jetbrains.kotlin.gradle.targets.metadata.isNativeSourceSet +import org.jetbrains.kotlin.gradle.targets.metadata.isSingleKotlinTargetSourceSet import org.jetbrains.kotlin.gradle.targets.metadata.isSinglePlatformTypeSourceSet import org.jetbrains.kotlin.gradle.utils.getOrPut import org.jetbrains.kotlin.tooling.core.Extras @@ -170,6 +171,8 @@ interface IdeMultiplatformImport { val isSinglePlatformType = SourceSetConstraint { isSinglePlatformTypeSourceSet(it) } + val isSingleKotlinTarget = SourceSetConstraint { isSingleKotlinTargetSourceSet(it) } + val isLeaf = SourceSetConstraint { sourceSet -> (sourceSet.project.multiplatformExtensionOrNull ?: return@SourceSetConstraint true).sourceSets .none { otherSourceSet -> sourceSet in otherSourceSet.dependsOn } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt index c10062e4d88..32a659eef69 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/ide/IdeMultiplatformImportFactory.kt @@ -88,7 +88,7 @@ internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMulti registerDependencyResolver( resolver = IdePlatformCinteropDependencyResolver, - constraint = { sourceSet -> SourceSetConstraint.isLeaf(sourceSet) && SourceSetConstraint.isNative(sourceSet) }, + constraint = { sourceSet -> SourceSetConstraint.isSingleKotlinTarget(sourceSet) && SourceSetConstraint.isNative(sourceSet) }, phase = IdeMultiplatformImport.DependencyResolutionPhase.BinaryDependencyResolution, level = IdeMultiplatformImport.DependencyResolutionLevel.Default, ) @@ -102,14 +102,14 @@ internal fun IdeMultiplatformImport(extension: KotlinProjectExtension): IdeMulti registerDependencyResolver( resolver = IdeCInteropMetadataDependencyClasspathResolver, - constraint = { SourceSetConstraint.isNative(it) && !SourceSetConstraint.isLeaf(it) }, + constraint = { SourceSetConstraint.isNative(it) && !SourceSetConstraint.isSingleKotlinTarget(it) }, phase = IdeMultiplatformImport.DependencyResolutionPhase.BinaryDependencyResolution, level = IdeMultiplatformImport.DependencyResolutionLevel.Default, ) registerDependencyResolver( resolver = IdeProjectToProjectCInteropDependencyResolver, - constraint = { SourceSetConstraint.isNative(it) && SourceSetConstraint.isLeaf(it) }, + constraint = { SourceSetConstraint.isNative(it) && SourceSetConstraint.isSingleKotlinTarget(it) }, phase = IdeMultiplatformImport.DependencyResolutionPhase.BinaryDependencyResolution, level = IdeMultiplatformImport.DependencyResolutionLevel.Default, ) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index 094dc390d3e..6a9a1f549cc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -534,6 +534,11 @@ internal fun isSinglePlatformTypeSourceSet(sourceSet: KotlinSourceSet): Boolean return platformCompilations.map { it.platformType }.toSet().size == 1 } +internal fun isSingleKotlinTargetSourceSet(sourceSet: KotlinSourceSet): Boolean { + val platformCompilations = sourceSet.internal.compilations.filterNot { it.platformType == KotlinPlatformType.common } + return platformCompilations.map { it.target }.toSet().size == 1 +} + internal fun dependsOnClosureWithInterCompilationDependencies(sourceSet: KotlinSourceSet): Set = sourceSet.internal.dependsOnClosure.toMutableSet().apply { addAll(getVisibleSourceSetsFromAssociateCompilations(sourceSet))