[Gradle] CInterop commonization: Improve grouping and dependency management
^KT-47775 Verification Pending This implementation will be lenient toward the common *Test.dependsOn(*Main) mistake. ^KT-47053 Verification Pending Support source sets that do not have a dedicated shared native compilation. Also support additional visible source sets coming from associate compilations.
This commit is contained in:
committed by
Space
parent
a7e81d5154
commit
02d4c866ca
+1
-1
@@ -135,10 +135,10 @@ class CommonizerIT : BaseGradleIT() {
|
|||||||
val expectedOutputDirectoryForBuild = projectDir.resolve("build/classes/kotlin/commonizer")
|
val expectedOutputDirectoryForBuild = projectDir.resolve("build/classes/kotlin/commonizer")
|
||||||
|
|
||||||
build(":copyCommonizeCInteropForIde") {
|
build(":copyCommonizeCInteropForIde") {
|
||||||
|
assertSuccessful()
|
||||||
assertTasksExecuted(":cinteropCurlTargetA")
|
assertTasksExecuted(":cinteropCurlTargetA")
|
||||||
assertTasksExecuted(":cinteropCurlTargetB")
|
assertTasksExecuted(":cinteropCurlTargetB")
|
||||||
assertTasksExecuted(":commonizeCInterop")
|
assertTasksExecuted(":commonizeCInterop")
|
||||||
assertSuccessful()
|
|
||||||
|
|
||||||
assertTrue(expectedOutputDirectoryForIde.isDirectory, "Missing output directory for IDE")
|
assertTrue(expectedOutputDirectoryForIde.isDirectory, "Missing output directory for IDE")
|
||||||
assertTrue(expectedOutputDirectoryForBuild.isDirectory, "Missing output directory for build")
|
assertTrue(expectedOutputDirectoryForBuild.isDirectory, "Missing output directory for build")
|
||||||
|
|||||||
+380
-48
@@ -8,36 +8,27 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
import org.gradle.api.internal.project.ProjectInternal
|
|
||||||
import org.gradle.api.plugins.ExtraPropertiesExtension
|
|
||||||
import org.gradle.testfixtures.ProjectBuilder
|
|
||||||
import org.jetbrains.kotlin.commonizer.CommonizerTarget
|
import org.jetbrains.kotlin.commonizer.CommonizerTarget
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizationParameters
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerTask
|
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerTask
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerGroup
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask
|
import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.supports
|
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||||
import kotlin.test.*
|
import kotlin.test.*
|
||||||
|
|
||||||
class CInteropCommonizerTaskTest {
|
class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
|
||||||
|
|
||||||
private lateinit var project: ProjectInternal
|
|
||||||
private lateinit var kotlin: KotlinMultiplatformExtension
|
|
||||||
private val task: CInteropCommonizerTask get() = project.commonizeCInteropTask?.get() ?: fail("Missing commonizeCInteropTask")
|
private val task: CInteropCommonizerTask get() = project.commonizeCInteropTask?.get() ?: fail("Missing commonizeCInteropTask")
|
||||||
|
|
||||||
@BeforeTest
|
@BeforeTest
|
||||||
fun setup() {
|
override fun setup() {
|
||||||
project = ProjectBuilder.builder().build() as ProjectInternal
|
enableGranularSourceSetsMetadata()
|
||||||
project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableGranularSourceSetsMetadata", "true")
|
enableCInteropCommonization()
|
||||||
project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableCInteropCommonization", "true")
|
super.setup()
|
||||||
project.plugins.apply("kotlin-multiplatform")
|
|
||||||
kotlin = project.extensions.getByName("kotlin") as KotlinMultiplatformExtension
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `nativeMain linux macos`() {
|
fun `nativeMain linux macos`() {
|
||||||
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName")
|
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName")
|
||||||
@@ -53,15 +44,18 @@ class CInteropCommonizerTaskTest {
|
|||||||
macosMain.dependsOn(nativeMain)
|
macosMain.dependsOn(nativeMain)
|
||||||
|
|
||||||
project.evaluate()
|
project.evaluate()
|
||||||
val nativeMainCompilation = kotlin.targets.flatMap { it.compilations }
|
|
||||||
.filterIsInstance<KotlinSharedNativeCompilation>()
|
val groups = task.getAllInteropsGroups()
|
||||||
.single { it.defaultSourceSet == nativeMain }
|
assertEquals(1, groups.size, "Expected only one InteropsGroup")
|
||||||
|
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(nativeMain)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
CInteropCommonizationParameters(
|
CInteropCommonizerGroup(
|
||||||
setOf(CommonizerTarget(LINUX_X64, MACOS_X64)), setOf(linuxInterop.identifier, macosInterop.identifier)
|
setOf(CommonizerTarget(LINUX_X64, MACOS_X64)),
|
||||||
|
setOf(linuxInterop.identifier, macosInterop.identifier)
|
||||||
),
|
),
|
||||||
task.getCommonizationParameters(nativeMainCompilation)
|
task.findInteropsGroup(expectCInteropCommonizerDependent(nativeMain))
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -80,17 +74,18 @@ class CInteropCommonizerTaskTest {
|
|||||||
macosMain.dependsOn(nativeMain)
|
macosMain.dependsOn(nativeMain)
|
||||||
|
|
||||||
project.evaluate()
|
project.evaluate()
|
||||||
val nativeMainCompilation = kotlin.targets.flatMap { it.compilations }
|
|
||||||
.filterIsInstance<KotlinSharedNativeCompilation>()
|
|
||||||
.single { it.defaultSourceSet == nativeMain }
|
|
||||||
|
|
||||||
assertNull(
|
assertNull(
|
||||||
task.getCommonizationParameters(nativeMainCompilation),
|
findCInteropCommonizerDependent(nativeMain),
|
||||||
|
"Expected no CInteropCommonizerTarget from nativeMain, since one target has not defined any cinterop"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertNull(
|
||||||
|
findCInteropCommonizerDependent(expectSharedNativeCompilation(nativeMain)),
|
||||||
"Expected no CInteropCommonizerTarget from nativeMain, since one target has not defined any cinterop"
|
"Expected no CInteropCommonizerTarget from nativeMain, since one target has not defined any cinterop"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `nativeMain iosMain linux macos iosX64 iosArm64`() {
|
fun `nativeMain iosMain linux macos iosX64 iosArm64`() {
|
||||||
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier
|
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier
|
||||||
@@ -116,33 +111,370 @@ class CInteropCommonizerTaskTest {
|
|||||||
project.evaluate()
|
project.evaluate()
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
CInteropCommonizationParameters(
|
1, task.getAllInteropsGroups().size,
|
||||||
setOf(
|
"Expected exactly one InteropsGroup for task"
|
||||||
CommonizerTarget(IOS_X64, IOS_ARM64),
|
)
|
||||||
CommonizerTarget(IOS_X64, IOS_ARM64, MACOS_X64, LINUX_X64)
|
|
||||||
),
|
val group = CInteropCommonizerGroup(
|
||||||
setOf(linuxInterop, macosInterop, iosX64Interop, iosArm64Interop)
|
setOf(
|
||||||
), task.getCommonizationParameters(sharedNativeCompilation(nativeMain))
|
CommonizerTarget(IOS_X64, IOS_ARM64, MACOS_X64, LINUX_X64),
|
||||||
|
CommonizerTarget(IOS_X64, IOS_ARM64)
|
||||||
|
),
|
||||||
|
setOf(
|
||||||
|
linuxInterop, macosInterop, iosX64Interop, iosArm64Interop
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(nativeMain)
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(iosMain)
|
||||||
|
|
||||||
|
assertEquals(group, task.findInteropsGroup(expectCInteropCommonizerDependent(nativeMain)))
|
||||||
|
assertEquals(group, task.findInteropsGroup(expectCInteropCommonizerDependent(iosMain)))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `nativeTest nativeMain linux macos`() {
|
||||||
|
`nativeTest nativeMain linux macos`(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `nativeTest nativeMain linux macos - nativeTest dependsOn nativeMain`() {
|
||||||
|
`nativeTest nativeMain linux macos`(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun `nativeTest nativeMain linux macos`(
|
||||||
|
nativeTestDependsOnNativeMain: Boolean
|
||||||
|
) {
|
||||||
|
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier
|
||||||
|
val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName").identifier
|
||||||
|
|
||||||
|
val commonMain = kotlin.sourceSets.getByName("commonMain")
|
||||||
|
val nativeMain = kotlin.sourceSets.create("nativeMain")
|
||||||
|
val linuxMain = kotlin.sourceSets.getByName("linuxMain")
|
||||||
|
val macosMain = kotlin.sourceSets.getByName("macosMain")
|
||||||
|
|
||||||
|
val nativeTest = kotlin.sourceSets.create("nativeTest")
|
||||||
|
val linuxTest = kotlin.sourceSets.getByName("linuxTest")
|
||||||
|
val macosTest = kotlin.sourceSets.getByName("macosTest")
|
||||||
|
|
||||||
|
linuxTest.dependsOn(nativeTest)
|
||||||
|
macosTest.dependsOn(nativeTest)
|
||||||
|
|
||||||
|
linuxMain.dependsOn(nativeMain)
|
||||||
|
macosMain.dependsOn(nativeMain)
|
||||||
|
|
||||||
|
nativeMain.dependsOn(commonMain)
|
||||||
|
|
||||||
|
if (nativeTestDependsOnNativeMain) {
|
||||||
|
nativeTest.dependsOn(nativeMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.evaluate()
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
1, task.getAllInteropsGroups().size,
|
||||||
|
"Expected exactly 1 'SharedInteropsGroup' for task"
|
||||||
|
)
|
||||||
|
|
||||||
|
val group = CInteropCommonizerGroup(
|
||||||
|
setOf(CommonizerTarget(LINUX_X64, MACOS_X64)),
|
||||||
|
setOf(linuxInterop, macosInterop)
|
||||||
)
|
)
|
||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
CInteropCommonizationParameters(
|
expectCInteropCommonizerDependent(nativeMain),
|
||||||
setOf(
|
expectCInteropCommonizerDependent(expectSharedNativeCompilation(nativeMain)),
|
||||||
CommonizerTarget(IOS_X64, IOS_ARM64),
|
"Expected same dependent from 'nativeMain' source set and 'nativeMain' compilation"
|
||||||
CommonizerTarget(IOS_X64, IOS_ARM64, MACOS_X64, LINUX_X64)
|
|
||||||
),
|
|
||||||
setOf(linuxInterop, macosInterop, iosX64Interop, iosArm64Interop)
|
|
||||||
), task.getCommonizationParameters(sharedNativeCompilation(iosMain))
|
|
||||||
)
|
)
|
||||||
|
|
||||||
assertTrue(
|
assertEquals(
|
||||||
task.getCommonizationParameters(sharedNativeCompilation(nativeMain))!!.supports(sharedNativeCompilation(nativeMain)),
|
group, task.findInteropsGroup(expectCInteropCommonizerDependent(nativeMain))
|
||||||
"Expected CInteropCommonizerTarget of nativeMain to support iosMain"
|
)
|
||||||
|
|
||||||
|
assertNull(
|
||||||
|
findCInteropCommonizerDependent(nativeTest),
|
||||||
|
"Expected nativeTest to not depend on CInteropCommonizer"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun sharedNativeCompilation(sourceSet: KotlinSourceSet): KotlinSharedNativeCompilation {
|
@Test
|
||||||
return kotlin.targets.flatMap { it.compilations }.filterIsInstance<KotlinSharedNativeCompilation>()
|
fun `nativeTest nativeMain linux macos - test compilation defines custom cinterop`() {
|
||||||
.single { it.defaultSourceSet == sourceSet }
|
`nativeTest nativeMain linux macos - test compilation defines custom cinterop`(false)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `nativeTest nativeMain linux macos - test compilation defines custom cinterop - nativeTest dependsOn nativeMain`() {
|
||||||
|
`nativeTest nativeMain linux macos - test compilation defines custom cinterop`(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun `nativeTest nativeMain linux macos - test compilation defines custom cinterop`(
|
||||||
|
nativeTestDependsOnNativeMain: Boolean
|
||||||
|
) {
|
||||||
|
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier
|
||||||
|
val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName").identifier
|
||||||
|
kotlin.linuxX64("linux").compilations.getByName("test").cinterops.create("anyOtherName").identifier
|
||||||
|
|
||||||
|
val commonMain = kotlin.sourceSets.getByName("commonMain")
|
||||||
|
val nativeMain = kotlin.sourceSets.create("nativeMain")
|
||||||
|
val linuxMain = kotlin.sourceSets.getByName("linuxMain")
|
||||||
|
val macosMain = kotlin.sourceSets.getByName("macosMain")
|
||||||
|
|
||||||
|
val nativeTest = kotlin.sourceSets.create("nativeTest")
|
||||||
|
val linuxTest = kotlin.sourceSets.getByName("linuxTest")
|
||||||
|
val macosTest = kotlin.sourceSets.getByName("macosTest")
|
||||||
|
|
||||||
|
linuxTest.dependsOn(nativeTest)
|
||||||
|
macosTest.dependsOn(nativeTest)
|
||||||
|
|
||||||
|
linuxMain.dependsOn(nativeMain)
|
||||||
|
macosMain.dependsOn(nativeMain)
|
||||||
|
|
||||||
|
nativeMain.dependsOn(commonMain)
|
||||||
|
|
||||||
|
if (nativeTestDependsOnNativeMain) {
|
||||||
|
nativeTest.dependsOn(nativeMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.evaluate()
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
1, task.getAllInteropsGroups().size,
|
||||||
|
"Expected exactly 1 'SharedInteropsGroup' for task"
|
||||||
|
)
|
||||||
|
|
||||||
|
val group = CInteropCommonizerGroup(
|
||||||
|
setOf(CommonizerTarget(LINUX_X64, MACOS_X64)),
|
||||||
|
setOf(linuxInterop, macosInterop)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
group, task.findInteropsGroup(expectCInteropCommonizerDependent(nativeMain))
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
group, task.findInteropsGroup(expectCInteropCommonizerDependent(expectSharedNativeCompilation(nativeMain)))
|
||||||
|
)
|
||||||
|
|
||||||
|
assertNull(
|
||||||
|
findCInteropCommonizerDependent(nativeTest),
|
||||||
|
"Expected 'nativeTest' to not be CInteropCommonizer dependent"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `hierarchical project - testSourceSetsDependOnMainSourceSets = true`() {
|
||||||
|
`hierarchical project`(testSourceSetsDependOnMainSourceSets = true)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `hierarchical project - testSourceSetsDependOnMainSourceSets = false`() {
|
||||||
|
`hierarchical project`(testSourceSetsDependOnMainSourceSets = false)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun `hierarchical project`(testSourceSetsDependOnMainSourceSets: Boolean) {
|
||||||
|
/* Define targets */
|
||||||
|
val linux = kotlin.linuxX64("linux")
|
||||||
|
val macos = kotlin.macosX64("macos")
|
||||||
|
val iosX64 = kotlin.iosX64()
|
||||||
|
val iosArm64 = kotlin.iosArm64()
|
||||||
|
val windows64 = kotlin.mingwX64("windows64")
|
||||||
|
val windows32 = kotlin.mingwX86("windows32")
|
||||||
|
kotlin.jvm()
|
||||||
|
kotlin.js().browser()
|
||||||
|
|
||||||
|
val nativeTargets = listOf(linux, macos, iosX64, iosArm64, windows64, windows32)
|
||||||
|
val windowsTargets = listOf(windows64, windows32)
|
||||||
|
val unixLikeTargets = listOf(linux, macos, iosX64, iosArm64)
|
||||||
|
val appleTargets = listOf(macos, iosX64, iosArm64)
|
||||||
|
val iosTargets = listOf(iosX64, iosArm64)
|
||||||
|
|
||||||
|
/* Define interops */
|
||||||
|
nativeTargets.map { target ->
|
||||||
|
target.compilations.getByName("main").cinterops.create("nativeHelper").identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeTargets.map { target ->
|
||||||
|
target.compilations.getByName("test").cinterops.create("nativeTestHelper").identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
windowsTargets.map { target ->
|
||||||
|
target.compilations.getByName("main").cinterops.create("windowsHelper").identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
unixLikeTargets.map { target ->
|
||||||
|
target.compilations.getByName("main").cinterops.create("unixHelper").identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
appleTargets.map { target ->
|
||||||
|
target.compilations.getByName("main").cinterops.create("appleHelper").identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
appleTargets.map { target ->
|
||||||
|
target.compilations.getByName("test").cinterops.create("appleTestHelper").identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
iosTargets.map { target ->
|
||||||
|
target.compilations.getByName("main").cinterops.create("iosHelper").identifier
|
||||||
|
}
|
||||||
|
|
||||||
|
iosX64.compilations.getByName("main").cinterops.create("iosX64Helper").identifier
|
||||||
|
iosX64.compilations.getByName("test").cinterops.create("iosX64TestHelper").identifier
|
||||||
|
|
||||||
|
/* Define source set hierarchy */
|
||||||
|
val commonMain = kotlin.sourceSets.getByName("commonMain")
|
||||||
|
val commonTest = kotlin.sourceSets.getByName("commonTest")
|
||||||
|
val nativeMain = kotlin.sourceSets.create("nativeMain")
|
||||||
|
val nativeTest = kotlin.sourceSets.create("nativeTest")
|
||||||
|
val unixMain = kotlin.sourceSets.create("unixMain")
|
||||||
|
val appleMain = kotlin.sourceSets.create("appleMain")
|
||||||
|
val appleTest = kotlin.sourceSets.create("appleTest")
|
||||||
|
val windowsMain = kotlin.sourceSets.create("windowsMain")
|
||||||
|
val iosMain = kotlin.sourceSets.create("iosMain")
|
||||||
|
val iosTest = kotlin.sourceSets.create("iosTest")
|
||||||
|
|
||||||
|
nativeMain.dependsOn(commonMain)
|
||||||
|
nativeTest.dependsOn(commonTest)
|
||||||
|
unixMain.dependsOn(nativeMain)
|
||||||
|
appleMain.dependsOn(nativeMain)
|
||||||
|
appleTest.dependsOn(nativeTest)
|
||||||
|
windowsMain.dependsOn(nativeMain)
|
||||||
|
iosMain.dependsOn(appleMain)
|
||||||
|
|
||||||
|
if (testSourceSetsDependOnMainSourceSets) {
|
||||||
|
nativeTest.dependsOn(nativeMain)
|
||||||
|
appleTest.dependsOn(appleMain)
|
||||||
|
iosTest.dependsOn(iosMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
windowsTargets.forEach { target ->
|
||||||
|
target.compilations.getByName("main").defaultSourceSet.dependsOn(windowsMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
iosTargets.forEach { target ->
|
||||||
|
target.compilations.getByName("main").defaultSourceSet.dependsOn(iosMain)
|
||||||
|
target.compilations.getByName("test").defaultSourceSet.dependsOn(iosTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
appleTargets.forEach { target ->
|
||||||
|
target.compilations.getByName("main").defaultSourceSet.dependsOn(appleMain)
|
||||||
|
target.compilations.getByName("test").defaultSourceSet.dependsOn(appleTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
unixLikeTargets.forEach { target ->
|
||||||
|
target.compilations.getByName("main").defaultSourceSet.dependsOn(unixMain)
|
||||||
|
}
|
||||||
|
|
||||||
|
nativeTargets.forEach { target ->
|
||||||
|
target.compilations.getByName("main").defaultSourceSet.dependsOn(nativeMain)
|
||||||
|
target.compilations.getByName("test").defaultSourceSet.dependsOn(nativeTest)
|
||||||
|
}
|
||||||
|
|
||||||
|
project.evaluate()
|
||||||
|
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(nativeMain)
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(unixMain)
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(windowsMain)
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(appleMain)
|
||||||
|
assertCInteropDependentEqualsForSourceSetAndCompilation(iosMain)
|
||||||
|
|
||||||
|
val groups = task.getAllInteropsGroups()
|
||||||
|
assertEquals(2, groups.size, "Expected exactly two interop groups: main and test")
|
||||||
|
|
||||||
|
val nativeCommonizerTarget = SharedCommonizerTarget(nativeTargets.map { it.konanTarget })
|
||||||
|
val unixLikeCommonizerTarget = SharedCommonizerTarget(unixLikeTargets.map { it.konanTarget })
|
||||||
|
val windowsCommonizerTarget = SharedCommonizerTarget(windowsTargets.map { it.konanTarget })
|
||||||
|
val appleCommonizerTarget = SharedCommonizerTarget(appleTargets.map { it.konanTarget })
|
||||||
|
val iosCommonizerTarget = SharedCommonizerTarget(iosTargets.map { it.konanTarget })
|
||||||
|
|
||||||
|
val expectedMainGroup = CInteropCommonizerGroup(
|
||||||
|
targets = setOf(
|
||||||
|
nativeCommonizerTarget, unixLikeCommonizerTarget, windowsCommonizerTarget,
|
||||||
|
appleCommonizerTarget, iosCommonizerTarget
|
||||||
|
),
|
||||||
|
interops = nativeTargets.map { target -> target.mainCinteropIdentifier("nativeHelper") }.toSet() +
|
||||||
|
unixLikeTargets.map { target -> target.mainCinteropIdentifier("unixHelper") } +
|
||||||
|
windowsTargets.map { target -> target.mainCinteropIdentifier("windowsHelper") } +
|
||||||
|
appleTargets.map { target -> target.mainCinteropIdentifier("appleHelper") } +
|
||||||
|
iosTargets.map { target -> target.mainCinteropIdentifier("iosHelper") } +
|
||||||
|
iosX64.mainCinteropIdentifier("iosX64Helper")
|
||||||
|
)
|
||||||
|
|
||||||
|
val expectedTestGroup = CInteropCommonizerGroup(
|
||||||
|
targets = setOf(nativeCommonizerTarget, appleCommonizerTarget, iosCommonizerTarget),
|
||||||
|
interops = nativeTargets.map { target -> target.testCinteropIdentifier("nativeTestHelper") }.toSet() +
|
||||||
|
appleTargets.map { target -> target.testCinteropIdentifier("appleTestHelper") } +
|
||||||
|
iosX64.testCinteropIdentifier("iosX64TestHelper")
|
||||||
|
)
|
||||||
|
|
||||||
|
val mainGroup = groups.maxBy { it.targets.size }!!
|
||||||
|
val testGroup = groups.minBy { it.targets.size }!!
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
expectedMainGroup, mainGroup,
|
||||||
|
"mainGroup does not match"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
expectedTestGroup, testGroup,
|
||||||
|
"testGroup does not match"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
mainGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(nativeMain)),
|
||||||
|
"Expected nativeMain being part of the mainGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
mainGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(unixMain)),
|
||||||
|
"Expected unixMain being part of the mainGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
mainGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(windowsMain)),
|
||||||
|
"Expected windowsMain being part of the mainGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
mainGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(appleMain)),
|
||||||
|
"Expected appleMain being part of the mainGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
mainGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(iosMain)),
|
||||||
|
"Expected iosMain being part of the mainGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
testGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(nativeTest)),
|
||||||
|
"Expected nativeTest being part of the testGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
testGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(appleTest)),
|
||||||
|
"Expected appleTest being part of the testGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
testGroup, task.findInteropsGroup(expectCInteropCommonizerDependent(iosTest)),
|
||||||
|
"Expected iosTest being part of the testGroup"
|
||||||
|
)
|
||||||
|
|
||||||
|
kotlin.targets
|
||||||
|
/* Shared K/N targets still are considered type common */
|
||||||
|
.filter { it.platformType != KotlinPlatformType.common }
|
||||||
|
.flatMap { it.compilations }.map { it.defaultSourceSet }.forEach { targetDefaultSourceSet ->
|
||||||
|
assertNull(
|
||||||
|
findCInteropCommonizerDependent(targetDefaultSourceSet),
|
||||||
|
"Expected target source set ${targetDefaultSourceSet.name} not be CInteropCommonizerDependent"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun assertCInteropDependentEqualsForSourceSetAndCompilation(sourceSet: KotlinSourceSet) {
|
||||||
|
assertEquals(
|
||||||
|
expectCInteropCommonizerDependent(sourceSet),
|
||||||
|
expectCInteropCommonizerDependent(expectSharedNativeCompilation(sourceSet)),
|
||||||
|
"Expected found CInteropCommonizerDependent for source set '$sourceSet and it's shared native compilation to be equal"
|
||||||
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+79
@@ -0,0 +1,79 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/* Associate compilations are not yet supported by the IDE. KT-34102 */
|
||||||
|
@file:Suppress("invisible_reference", "invisible_member", "FunctionName", "DuplicatedCode")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
|
import org.gradle.api.internal.project.ProjectInternal
|
||||||
|
import org.gradle.api.plugins.ExtraPropertiesExtension
|
||||||
|
import org.gradle.testfixtures.ProjectBuilder
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerDependent
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropIdentifier
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.internal.from
|
||||||
|
import kotlin.test.BeforeTest
|
||||||
|
import kotlin.test.assertNotNull
|
||||||
|
|
||||||
|
abstract class MultiplatformExtensionTest {
|
||||||
|
protected val project: ProjectInternal = ProjectBuilder.builder().build() as ProjectInternal
|
||||||
|
protected lateinit var kotlin: KotlinMultiplatformExtension
|
||||||
|
|
||||||
|
@BeforeTest
|
||||||
|
open fun setup() {
|
||||||
|
project.plugins.apply("kotlin-multiplatform")
|
||||||
|
kotlin = project.extensions.getByName("kotlin") as KotlinMultiplatformExtension
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun enableGranularSourceSetsMetadata() {
|
||||||
|
project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableGranularSourceSetsMetadata", "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
protected fun enableCInteropCommonization() {
|
||||||
|
project.extensions.getByType(ExtraPropertiesExtension::class.java).set("kotlin.mpp.enableCInteropCommonization", "true")
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun expectCInteropCommonizerDependent(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent {
|
||||||
|
return assertNotNull(
|
||||||
|
CInteropCommonizerDependent.from(compilation), "Can't find SharedInterops for ${compilation.name} compilation"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun expectCInteropCommonizerDependent(sourceSet: KotlinSourceSet): CInteropCommonizerDependent {
|
||||||
|
return assertNotNull(
|
||||||
|
CInteropCommonizerDependent.from(project, sourceSet), "Can't find SharedInterops for ${sourceSet.name} source set"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun findCInteropCommonizerDependent(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent? {
|
||||||
|
return CInteropCommonizerDependent.from(compilation)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun findCInteropCommonizerDependent(sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
|
||||||
|
return CInteropCommonizerDependent.from(project, sourceSet)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun expectSharedNativeCompilation(sourceSet: KotlinSourceSet): KotlinSharedNativeCompilation {
|
||||||
|
return kotlin.targets.flatMap { it.compilations }.filterIsInstance<KotlinSharedNativeCompilation>()
|
||||||
|
.single { it.defaultSourceSet == sourceSet }
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinNativeTarget.mainCinteropIdentifier(name: String): CInteropIdentifier {
|
||||||
|
return compilations.getByName("main").cinteropIdentifier(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinNativeTarget.testCinteropIdentifier(name: String): CInteropIdentifier {
|
||||||
|
return compilations.getByName("test").cinteropIdentifier(name)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun KotlinCompilationData<*>.cinteropIdentifier(name: String): CInteropIdentifier {
|
||||||
|
return CInteropIdentifier(CInteropIdentifier.Scope.create(this), name)
|
||||||
|
}
|
||||||
|
}
|
||||||
-18
@@ -27,9 +27,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinPm20ProjectExtension
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.sources.*
|
import org.jetbrains.kotlin.gradle.plugin.sources.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.*
|
import org.jetbrains.kotlin.gradle.targets.native.internal.*
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.commonizeCInteropTask
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.copyCommonizeCInteropForIdeTask
|
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.getLibraries
|
|
||||||
import org.jetbrains.kotlin.gradle.tasks.*
|
import org.jetbrains.kotlin.gradle.tasks.*
|
||||||
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
|
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
|
||||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||||
@@ -318,21 +315,6 @@ class KotlinMetadataTargetConfigurator :
|
|||||||
compileDependencyFiles = project.files()
|
compileDependencyFiles = project.files()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this is KotlinSharedNativeCompilation) {
|
|
||||||
project.commonizeCInteropTask?.let { task ->
|
|
||||||
compileDependencyFiles = compileDependencyFiles.plus(task.getLibraries(this))
|
|
||||||
}
|
|
||||||
project.copyCommonizeCInteropForIdeTask?.let { task ->
|
|
||||||
val libraries = task.getLibraries(this)
|
|
||||||
kotlinSourceSetsIncludingDefault.filterIsInstance<DefaultKotlinSourceSet>().forEach { sourceSet ->
|
|
||||||
val dependencyConfigurationName =
|
|
||||||
if (project.isIntransitiveMetadataConfigurationEnabled) sourceSet.intransitiveMetadataConfigurationName
|
|
||||||
else sourceSet.implementationMetadataConfigurationName
|
|
||||||
project.dependencies.add(dependencyConfigurationName, libraries)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+5
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
|||||||
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
|
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.NativeDistributionTypeProvider
|
import org.jetbrains.kotlin.gradle.targets.native.internal.NativeDistributionTypeProvider
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGenerator
|
import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGenerator
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.internal.setupCInteropCommonizerDependencies
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.setupKotlinNativePlatformDependencies
|
import org.jetbrains.kotlin.gradle.targets.native.internal.setupKotlinNativePlatformDependencies
|
||||||
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
|
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
|
||||||
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
import org.jetbrains.kotlin.gradle.utils.SingleActionPerProject
|
||||||
@@ -91,6 +92,10 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SingleActionPerProject.run(project, "setupCInteropCommonizerDependencies") {
|
||||||
|
project.setupCInteropCommonizerDependencies()
|
||||||
|
}
|
||||||
|
|
||||||
if (!konanTarget.enabledOnCurrentHost) {
|
if (!konanTarget.enabledOnCurrentHost) {
|
||||||
with(HostManager()) {
|
with(HostManager()) {
|
||||||
val supportedHosts = enabledByHost.filterValues { konanTarget in it }.keys
|
val supportedHosts = enabledByHost.filterValues { konanTarget in it }.keys
|
||||||
|
|||||||
+14
-15
@@ -8,10 +8,10 @@ package org.jetbrains.kotlin.gradle.targets.native.internal
|
|||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
import org.gradle.api.tasks.OutputDirectory
|
import org.gradle.api.tasks.OutputDirectory
|
||||||
import org.gradle.api.tasks.TaskProvider
|
|
||||||
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout
|
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout
|
||||||
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.fileName
|
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.base64Hash
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
|
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.ensureMaxFileNameLength
|
||||||
|
import org.jetbrains.kotlin.commonizer.identityString
|
||||||
import org.jetbrains.kotlin.gradle.utils.filesProvider
|
import org.jetbrains.kotlin.gradle.utils.filesProvider
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
@@ -19,27 +19,26 @@ internal abstract class AbstractCInteropCommonizerTask : DefaultTask() {
|
|||||||
@get:OutputDirectory
|
@get:OutputDirectory
|
||||||
abstract val outputDirectory: File
|
abstract val outputDirectory: File
|
||||||
|
|
||||||
internal fun outputDirectory(parameters: CInteropCommonizationParameters): File {
|
internal fun outputDirectory(group: CInteropCommonizerGroup): File {
|
||||||
|
val interopsDirectoryName = group.interops.map { it.interopName }.toSet().joinToString(";")
|
||||||
|
val groupDisambiguation = group.targets.joinToString { it.identityString } +
|
||||||
|
group.interops.joinToString { it.uniqueName }
|
||||||
|
|
||||||
return outputDirectory
|
return outputDirectory
|
||||||
.resolve(parameters.targets.fileName)
|
.resolve(ensureMaxFileNameLength(interopsDirectoryName))
|
||||||
.resolve(parameters.interops.map { it.interopName }.distinct().joinToString("-"))
|
.resolve(base64Hash(groupDisambiguation))
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract fun getCommonizationParameters(compilation: KotlinSharedNativeCompilation): CInteropCommonizationParameters?
|
internal abstract fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup?
|
||||||
|
|
||||||
internal fun getLibraries(compilation: KotlinSharedNativeCompilation): FileCollection {
|
internal fun commonizedOutputLibraries(dependent: CInteropCommonizerDependent): FileCollection {
|
||||||
val compilationCommonizerTarget = project.getCommonizerTarget(compilation) ?: return project.files()
|
|
||||||
val fileProvider = project.filesProvider {
|
val fileProvider = project.filesProvider {
|
||||||
val parameters = getCommonizationParameters(compilation) ?: return@filesProvider emptySet<File>()
|
val group = findInteropsGroup(dependent) ?: return@filesProvider emptySet<File>()
|
||||||
CommonizerOutputFileLayout
|
CommonizerOutputFileLayout
|
||||||
.resolveCommonizedDirectory(outputDirectory(parameters), compilationCommonizerTarget)
|
.resolveCommonizedDirectory(outputDirectory(group), dependent.target)
|
||||||
.listFiles().orEmpty().toSet()
|
.listFiles().orEmpty().toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
return fileProvider.builtBy(this)
|
return fileProvider.builtBy(this)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun TaskProvider<out AbstractCInteropCommonizerTask>.getLibraries(compilation: KotlinSharedNativeCompilation): FileCollection {
|
|
||||||
return compilation.target.project.files(map { it.getLibraries(compilation) })
|
|
||||||
}
|
|
||||||
|
|||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.targets.native.internal
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.file.FileCollection
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.filesProvider
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
// TODO NOW: Integration tests!
|
||||||
|
|
||||||
|
internal fun Project.setupCInteropCommonizerDependencies() {
|
||||||
|
val kotlin = this.multiplatformExtensionOrNull ?: return
|
||||||
|
|
||||||
|
kotlin.targets.withType(KotlinMetadataTarget::class.java).all { target ->
|
||||||
|
target.compilations.withType(KotlinSharedNativeCompilation::class.java).all { compilation ->
|
||||||
|
setupCInteropCommonizerDependenciesForCompilation(compilation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin.sourceSets.withType(DefaultKotlinSourceSet::class.java).all { sourceSet ->
|
||||||
|
setupCInteropCommonizerDependenciesForIde(sourceSet)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun Project.setupCInteropCommonizerDependenciesForCompilation(compilation: KotlinSharedNativeCompilation) {
|
||||||
|
val cinteropCommonizerTask = project.commonizeCInteropTask ?: return
|
||||||
|
|
||||||
|
compilation.compileDependencyFiles += filesProvider {
|
||||||
|
val cinteropCommonizerDependent = CInteropCommonizerDependent.from(compilation) ?: return@filesProvider emptySet<File>()
|
||||||
|
cinteropCommonizerTask.get().commonizedOutputLibraries(cinteropCommonizerDependent)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* IDE will resolve the dependencies provided on source sets.
|
||||||
|
* This will use the [Project.copyCommonizeCInteropForIdeTask] over the regular cinterop commonization task.
|
||||||
|
* The copying task prevent red code within the IDE after cleaning the build output.
|
||||||
|
*/
|
||||||
|
private fun Project.setupCInteropCommonizerDependenciesForIde(sourceSet: DefaultKotlinSourceSet) {
|
||||||
|
val cinteropCommonizerTask = project.copyCommonizeCInteropForIdeTask ?: return
|
||||||
|
|
||||||
|
addDependency(sourceSet, filesProvider files@{
|
||||||
|
val sourceSetCommonizerTarget = getCommonizerTarget(sourceSet)
|
||||||
|
|
||||||
|
val additionalVisibleSourceSets = sourceSet.getAdditionalVisibleSourceSets()
|
||||||
|
.filter { sourceSet -> getCommonizerTarget(sourceSet) == sourceSetCommonizerTarget }
|
||||||
|
|
||||||
|
val cinteropCommonizerDependents = (additionalVisibleSourceSets + sourceSet).toSet()
|
||||||
|
.mapNotNull { sourceSet -> CInteropCommonizerDependent.from(this, sourceSet) }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
|
cinteropCommonizerDependents.map { cinteropCommonizerDependent ->
|
||||||
|
cinteropCommonizerTask.get().commonizedOutputLibraries(cinteropCommonizerDependent)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Dependencies here are using a special configuration called 'intransitiveMetadataConfiguration'.
|
||||||
|
* This special configuration can tell the IDE that this dependencies shall *not* be transitively be visible
|
||||||
|
* to dependsOn edges. This is necessary for the way the commonizer handles it's "expect refinement" approach.
|
||||||
|
* In this mode, every source set will receive exactly one commonized library to analyze its source code with.
|
||||||
|
*/
|
||||||
|
private fun Project.addDependency(sourceSet: DefaultKotlinSourceSet, dependency: FileCollection) {
|
||||||
|
val dependencyConfigurationName =
|
||||||
|
if (project.isIntransitiveMetadataConfigurationEnabled) sourceSet.intransitiveMetadataConfigurationName
|
||||||
|
else sourceSet.implementationMetadataConfigurationName
|
||||||
|
project.dependencies.add(dependencyConfigurationName, dependency)
|
||||||
|
}
|
||||||
+117
@@ -0,0 +1,117 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.targets.native.internal
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.CompilationSourceSetUtil.compilationsBySourceSets
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
|
||||||
|
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropIdentifier.Scope
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.UnsafeApi
|
||||||
|
|
||||||
|
internal class CInteropCommonizerDependent @UnsafeApi constructor(
|
||||||
|
val target: SharedCommonizerTarget,
|
||||||
|
val scopes: Set<Scope>,
|
||||||
|
val interops: Set<CInteropIdentifier>
|
||||||
|
) {
|
||||||
|
|
||||||
|
override fun equals(other: Any?): Boolean {
|
||||||
|
if (other !is CInteropCommonizerDependent) return false
|
||||||
|
if (this.target != other.target) return false
|
||||||
|
if (this.scopes != other.scopes) return false
|
||||||
|
if (this.interops != other.interops) return false
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun hashCode(): Int {
|
||||||
|
var result = target.hashCode()
|
||||||
|
result = 31 * result + scopes.hashCode()
|
||||||
|
result = 31 * result + interops.hashCode()
|
||||||
|
return result
|
||||||
|
}
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(target.targets.isNotEmpty()) { "CInteropCommonizerDependent.target.targets.size can't be empty" }
|
||||||
|
require(scopes.isNotEmpty()) { "CInteropCommonizerDependent.scopes can't be empty" }
|
||||||
|
require(interops.isNotEmpty()) { "CInteropCommonizerDependent.interops can't be empty" }
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object Factory
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(UnsafeApi::class)
|
||||||
|
internal fun CInteropCommonizerDependent.Factory.from(
|
||||||
|
target: SharedCommonizerTarget,
|
||||||
|
compilations: Set<KotlinNativeCompilation>
|
||||||
|
): CInteropCommonizerDependent? {
|
||||||
|
target.targets.ifEmpty { return null }
|
||||||
|
|
||||||
|
/*
|
||||||
|
Filter out compilations that have their associate also in the set of compilations
|
||||||
|
e.g. do not include '*test' if their main counterpart is also present.
|
||||||
|
*test and *main compilations will be included when build authors declare a *Test dependsOn *Main source set relationship.
|
||||||
|
This relationship should not be declared, but we try to be lenient towards it here.
|
||||||
|
*/
|
||||||
|
val filteredCompilations = compilations.filter { compilation ->
|
||||||
|
compilation.associateWithTransitiveClosure.none { associateCompilation -> associateCompilation in compilations }
|
||||||
|
}.ifEmpty { return null }.toSet()
|
||||||
|
|
||||||
|
val scopes: Set<Scope> = filteredCompilations
|
||||||
|
.map { compilation -> Scope.create(compilation) }.toSet()
|
||||||
|
.ifEmpty { return null }
|
||||||
|
|
||||||
|
val interops: Set<CInteropIdentifier> = filteredCompilations
|
||||||
|
.flatMap { compilation -> compilation.cinterops.ifEmpty { return null } }
|
||||||
|
.map { cinterop -> cinterop.identifier }.toSet()
|
||||||
|
|
||||||
|
return CInteropCommonizerDependent(target, scopes, interops)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun CInteropCommonizerDependent.Factory.from(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent? {
|
||||||
|
return from(
|
||||||
|
compilation.project.getCommonizerTarget(compilation) as? SharedCommonizerTarget ?: return null,
|
||||||
|
compilation.findDependingNativeCompilations()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun CInteropCommonizerDependent.Factory.from(project: Project, sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
|
||||||
|
val target = project.getCommonizerTarget(sourceSet) as? SharedCommonizerTarget ?: return null
|
||||||
|
val compilations = compilationsBySourceSets(project)[sourceSet] ?: return null
|
||||||
|
|
||||||
|
/* Non-native or non 'shared native' source sets can return eagerly */
|
||||||
|
if (compilations.any { compilation -> compilation !is AbstractKotlinNativeCompilation }) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
|
||||||
|
return from(
|
||||||
|
target = target,
|
||||||
|
compilations = compilations.filterIsInstance<KotlinNativeCompilation>().toSet()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun KotlinSharedNativeCompilation.findDependingNativeCompilations(): Set<KotlinNativeCompilation> {
|
||||||
|
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return emptySet()
|
||||||
|
val allParticipatingSourceSetsOfCompilation = allParticipatingSourceSets()
|
||||||
|
|
||||||
|
return multiplatformExtension.targets
|
||||||
|
.flatMap { target -> target.compilations }
|
||||||
|
.filterIsInstance<KotlinNativeCompilation>()
|
||||||
|
.filter { nativeCompilation -> nativeCompilation.allParticipatingSourceSets().containsAll(allParticipatingSourceSetsOfCompilation) }
|
||||||
|
.toSet()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Some implementations of [KotlinCompilation] do not contain the default source set in
|
||||||
|
* [KotlinCompilation.kotlinSourceSets] or [KotlinCompilation.allKotlinSourceSets]
|
||||||
|
* see KT-45412
|
||||||
|
*/
|
||||||
|
private fun KotlinCompilation<*>.allParticipatingSourceSets(): Set<KotlinSourceSet> {
|
||||||
|
return kotlinSourceSetsIncludingDefault + kotlinSourceSetsIncludingDefault.resolveAllDependsOnSourceSets()
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.targets.native.internal
|
||||||
|
|
||||||
|
import org.gradle.api.tasks.Input
|
||||||
|
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.utils.appendLine
|
||||||
|
|
||||||
|
internal data class CInteropCommonizerGroup(
|
||||||
|
@get:Input val targets: Set<SharedCommonizerTarget>,
|
||||||
|
@get:Input val interops: Set<CInteropIdentifier>
|
||||||
|
) {
|
||||||
|
@Suppress("deprecation")
|
||||||
|
override fun toString(): String {
|
||||||
|
return buildString {
|
||||||
|
appendln("InteropsGroup {")
|
||||||
|
appendln("targets: ")
|
||||||
|
targets.sortedBy { it.targets.size }.forEach { target ->
|
||||||
|
appendln(" $target")
|
||||||
|
}
|
||||||
|
appendln()
|
||||||
|
appendln("interops: ")
|
||||||
|
interops.sortedBy { it.toString() }.forEach { interop ->
|
||||||
|
appendln(" $interop")
|
||||||
|
}
|
||||||
|
appendLine("}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+57
-135
@@ -5,19 +5,18 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.gradle.targets.native.internal
|
package org.jetbrains.kotlin.gradle.targets.native.internal
|
||||||
|
|
||||||
import org.gradle.api.Project
|
|
||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.jetbrains.kotlin.commonizer.*
|
import org.jetbrains.kotlin.commonizer.CommonizerDependency
|
||||||
|
import org.jetbrains.kotlin.commonizer.NonTargetedCommonizerDependency
|
||||||
|
import org.jetbrains.kotlin.commonizer.TargetedCommonizerDependency
|
||||||
|
import org.jetbrains.kotlin.commonizer.allLeaves
|
||||||
import org.jetbrains.kotlin.compilerRunner.GradleCliCommonizer
|
import org.jetbrains.kotlin.compilerRunner.GradleCliCommonizer
|
||||||
import org.jetbrains.kotlin.compilerRunner.konanHome
|
import org.jetbrains.kotlin.compilerRunner.konanHome
|
||||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
|
||||||
import org.jetbrains.kotlin.gradle.plugin.CInteropSettings
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultCInteropSettings
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.kotlinSourceSetsIncludingDefault
|
import org.jetbrains.kotlin.gradle.plugin.mpp.kotlinSourceSetsIncludingDefault
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
|
import org.jetbrains.kotlin.gradle.plugin.sources.resolveAllDependsOnSourceSets
|
||||||
@@ -48,12 +47,12 @@ internal open class CInteropCommonizerTask : AbstractCInteropCommonizerTask() {
|
|||||||
|
|
||||||
@get:OutputDirectories
|
@get:OutputDirectories
|
||||||
val allOutputDirectories: Set<File>
|
val allOutputDirectories: Set<File>
|
||||||
get() = getCommonizationParameters().map { outputDirectory(it) }.toSet()
|
get() = getAllInteropsGroups().map { outputDirectory(it) }.toSet()
|
||||||
|
|
||||||
@Suppress("unused") // Used for UP-TO-DATE check
|
@Suppress("unused") // Used for UP-TO-DATE check
|
||||||
@get:Classpath
|
@get:Classpath
|
||||||
val commonizedNativeDistributionDependencies: Set<File>
|
val commonizedNativeDistributionDependencies: Set<File>
|
||||||
get() = getCommonizationParameters().flatMap { parameters -> parameters.targets }
|
get() = getAllInteropsGroups().flatMap { group -> group.targets }
|
||||||
.flatMap { target -> project.getNativeDistributionDependencies(target) }
|
.flatMap { target -> project.getNativeDistributionDependencies(target) }
|
||||||
.toSet()
|
.toSet()
|
||||||
|
|
||||||
@@ -71,102 +70,80 @@ internal open class CInteropCommonizerTask : AbstractCInteropCommonizerTask() {
|
|||||||
this.cinterops += cinterops
|
this.cinterops += cinterops
|
||||||
}
|
}
|
||||||
|
|
||||||
fun exclude(vararg tasks: CInteropProcess) {
|
|
||||||
exclude(tasks.map { it.settings.identifier })
|
|
||||||
}
|
|
||||||
|
|
||||||
fun exclude(vararg settings: CInteropSettings) {
|
|
||||||
exclude(settings.mapNotNull { (it as? DefaultCInteropSettings)?.identifier })
|
|
||||||
}
|
|
||||||
|
|
||||||
internal fun exclude(interopIdentifiers: List<CInteropIdentifier>) {
|
|
||||||
this.cinterops = this.cinterops.filterTo(mutableSetOf()) { it.identifier !in interopIdentifiers }
|
|
||||||
}
|
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
internal fun commonizeCInteropLibraries() {
|
internal fun commonizeCInteropLibraries() {
|
||||||
getCommonizationParameters().forEach(::commonize)
|
getAllInteropsGroups().forEach(::commonize)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun commonize(parameters: CInteropCommonizationParameters) {
|
private fun commonize(group: CInteropCommonizerGroup) {
|
||||||
val cinteropsForTarget = cinterops.filter { cinterop -> cinterop.identifier in parameters.interops }
|
val cinteropsForTarget = cinterops.filter { cinterop -> cinterop.identifier in group.interops }
|
||||||
outputDirectory(parameters).deleteRecursively()
|
outputDirectory(group).deleteRecursively()
|
||||||
if (cinteropsForTarget.isEmpty()) return
|
if (cinteropsForTarget.isEmpty()) return
|
||||||
|
|
||||||
GradleCliCommonizer(project).commonizeLibraries(
|
GradleCliCommonizer(project).commonizeLibraries(
|
||||||
konanHome = project.file(project.konanHome),
|
konanHome = project.file(project.konanHome),
|
||||||
outputTargets = parameters.targets,
|
outputTargets = group.targets,
|
||||||
inputLibraries = cinteropsForTarget.map { it.libraryFile.get() }.filter { it.exists() }.toSet(),
|
inputLibraries = cinteropsForTarget.map { it.libraryFile.get() }.filter { it.exists() }.toSet(),
|
||||||
dependencyLibraries = getNativeDistributionDependencies(parameters),
|
dependencyLibraries = getNativeDistributionDependencies(group),
|
||||||
outputDirectory = outputDirectory(parameters),
|
outputDirectory = outputDirectory(group),
|
||||||
logLevel = project.commonizerLogLevel
|
logLevel = project.commonizerLogLevel
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getNativeDistributionDependencies(parameters: CInteropCommonizationParameters): Set<CommonizerDependency> {
|
private fun getNativeDistributionDependencies(group: CInteropCommonizerGroup): Set<CommonizerDependency> {
|
||||||
return (parameters.targets + parameters.targets.allLeaves()).flatMapTo(mutableSetOf()) { target ->
|
return (group.targets + group.targets.allLeaves()).flatMapTo(mutableSetOf()) { target ->
|
||||||
project.getNativeDistributionDependencies(target).map { dependency -> TargetedCommonizerDependency(target, dependency) }
|
project.getNativeDistributionDependencies(target).map { dependency -> TargetedCommonizerDependency(target, dependency) }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun getSharedNativeCInterops(): Set<SharedNativeCInterops> {
|
|
||||||
val sharedNativeCompilations = (project.multiplatformExtensionOrNull ?: return emptySet())
|
|
||||||
.targets.flatMap { it.compilations }
|
|
||||||
.filterIsInstance<KotlinSharedNativeCompilation>()
|
|
||||||
|
|
||||||
fun buildSharedNativeCInterops(compilation: KotlinSharedNativeCompilation): SharedNativeCInterops? {
|
|
||||||
return SharedNativeCInterops(
|
|
||||||
target = project.getCommonizerTarget(compilation) as? SharedCommonizerTarget ?: return null,
|
|
||||||
interops = project.getDependingNativeCompilations(compilation)
|
|
||||||
/* If any dependee native compilation has no interop, then commonization is useless */
|
|
||||||
.flatMap { nativeCompilation -> nativeCompilation.cinterops.ifEmpty { return null } }
|
|
||||||
.map { interop -> interop.identifier }
|
|
||||||
.toSet()
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
return sharedNativeCompilations.mapNotNull(::buildSharedNativeCInterops).toSet()
|
|
||||||
.run(::removeNotRegisteredInterops)
|
|
||||||
.run(::removeEmptyInterops)
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@Nested
|
@Nested
|
||||||
internal fun getCommonizationParameters(): Set<CInteropCommonizationParameters> {
|
internal fun getAllInteropsGroups(): Set<CInteropCommonizerGroup> {
|
||||||
val sharedNativeCInterops = getSharedNativeCInterops()
|
val dependents = getAllDependents()
|
||||||
if (sharedNativeCInterops.isEmpty()) return emptySet()
|
val allScopes = dependents.map { it.scopes }.toSet()
|
||||||
|
val rootScopes = allScopes.filter { scopes ->
|
||||||
return sharedNativeCInterops.distinct()
|
allScopes.none { otherScopes -> otherScopes != scopes && otherScopes.containsAll(scopes) }
|
||||||
.filter { potentialRoot -> sharedNativeCInterops.none { other -> potentialRoot isProperSubsetOf other } }
|
|
||||||
.map { root -> root to sharedNativeCInterops.filter { other -> other isProperSubsetOf root } }
|
|
||||||
.mapTo(mutableSetOf()) { (root, subsets) ->
|
|
||||||
CInteropCommonizationParameters(
|
|
||||||
targets = subsets.mapTo(mutableSetOf()) { it.target } + root.target,
|
|
||||||
interops = root.interops
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun getCommonizationParameters(compilation: KotlinSharedNativeCompilation): CInteropCommonizationParameters? {
|
|
||||||
val supportedParameters = getCommonizationParameters().filter { parameters -> parameters.supports(compilation) }
|
|
||||||
if (supportedParameters.isEmpty()) return null
|
|
||||||
assert(supportedParameters.size == 1) {
|
|
||||||
"Unnecessary work detected: Multiple commonization parameters seem to be doing redundant work"
|
|
||||||
}
|
}
|
||||||
return supportedParameters.first()
|
|
||||||
|
return rootScopes.map { scopes ->
|
||||||
|
val dependentsForScopes = dependents.filter { dependent ->
|
||||||
|
scopes.containsAll(dependent.scopes)
|
||||||
|
}
|
||||||
|
|
||||||
|
CInteropCommonizerGroup(
|
||||||
|
targets = dependentsForScopes.map { it.target }.toSet(),
|
||||||
|
interops = dependentsForScopes.flatMap { it.interops }.toSet()
|
||||||
|
)
|
||||||
|
}.toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
override fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup? {
|
||||||
|
val suitableGroups = getAllInteropsGroups().filter { group ->
|
||||||
|
group.interops.containsAll(dependent.interops) && group.targets.contains(dependent.target)
|
||||||
|
}
|
||||||
|
|
||||||
internal fun CInteropCommonizationParameters.supports(
|
assert(suitableGroups.size <= 1) {
|
||||||
compilation: KotlinSharedNativeCompilation
|
"CInteropCommonizerTask: Unnecessary work detected: More than one suitable group found for cinterop dependent."
|
||||||
): Boolean {
|
}
|
||||||
val project = compilation.project
|
|
||||||
val commonizerTargetOfCompilation = project.getCommonizerTarget(compilation) ?: return false
|
|
||||||
val interopsOfCompilation = project.getDependingNativeCompilations(compilation)
|
|
||||||
.flatMap { it.cinterops }.map { it.identifier }
|
|
||||||
|
|
||||||
return targets.contains(commonizerTargetOfCompilation) && interops.containsAll(interopsOfCompilation)
|
return suitableGroups.firstOrNull()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Internal
|
||||||
|
internal fun getAllDependents(): Set<CInteropCommonizerDependent> {
|
||||||
|
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return emptySet()
|
||||||
|
|
||||||
|
val fromSharedNativeCompilations = multiplatformExtension
|
||||||
|
.targets.flatMap { target -> target.compilations }
|
||||||
|
.filterIsInstance<KotlinSharedNativeCompilation>()
|
||||||
|
.mapNotNull { compilation -> CInteropCommonizerDependent.from(compilation) }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
|
val fromSourceSets = multiplatformExtension.sourceSets
|
||||||
|
.mapNotNull { sourceSet -> CInteropCommonizerDependent.from(project, sourceSet) }
|
||||||
|
.toSet()
|
||||||
|
|
||||||
|
return (fromSharedNativeCompilations + fromSourceSets)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun CInteropProcess.toGist(): CInteropGist {
|
private fun CInteropProcess.toGist(): CInteropGist {
|
||||||
@@ -178,58 +155,3 @@ private fun CInteropProcess.toGist(): CInteropGist {
|
|||||||
libraryFile = outputFileProvider
|
libraryFile = outputFileProvider
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a single shared native compilation / shared native source set
|
|
||||||
* that would rely on given [interops]
|
|
||||||
*/
|
|
||||||
internal data class SharedNativeCInterops(
|
|
||||||
val target: SharedCommonizerTarget,
|
|
||||||
val interops: Set<CInteropIdentifier>
|
|
||||||
)
|
|
||||||
|
|
||||||
internal infix fun SharedNativeCInterops.isProperSubsetOf(other: SharedNativeCInterops): Boolean {
|
|
||||||
return target.allLeaves() != other.target.allLeaves() && other.target.allLeaves().containsAll(target.allLeaves())
|
|
||||||
&& interops != other.interops && other.interops.containsAll(interops)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Represents a single invocation to the commonizer
|
|
||||||
*/
|
|
||||||
internal data class CInteropCommonizationParameters(
|
|
||||||
@get:Input val targets: Set<SharedCommonizerTarget>,
|
|
||||||
@get:Input val interops: Set<CInteropIdentifier>
|
|
||||||
)
|
|
||||||
|
|
||||||
private fun CInteropCommonizerTask.removeNotRegisteredInterops(
|
|
||||||
parameters: Set<SharedNativeCInterops>
|
|
||||||
): Set<SharedNativeCInterops> {
|
|
||||||
val registeredInterops = this.cinterops.map { it.identifier }
|
|
||||||
return parameters.mapTo(mutableSetOf()) { params ->
|
|
||||||
params.copy(interops = params.interops.filterTo(mutableSetOf()) { interop -> interop in registeredInterops })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removeEmptyInterops(parameters: Set<SharedNativeCInterops>): Set<SharedNativeCInterops> {
|
|
||||||
return parameters.filterTo(mutableSetOf()) { it.interops.isNotEmpty() }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun Project.getDependingNativeCompilations(compilation: KotlinSharedNativeCompilation): Set<KotlinNativeCompilation> {
|
|
||||||
/**
|
|
||||||
* Some implementations of [KotlinCompilation] do not contain the default source set in
|
|
||||||
* [KotlinCompilation.kotlinSourceSets] or [KotlinCompilation.allKotlinSourceSets]
|
|
||||||
* see KT-45412
|
|
||||||
*/
|
|
||||||
fun KotlinCompilation<*>.allParticipatingSourceSets(): Set<KotlinSourceSet> {
|
|
||||||
return kotlinSourceSetsIncludingDefault + kotlinSourceSetsIncludingDefault.resolveAllDependsOnSourceSets()
|
|
||||||
}
|
|
||||||
|
|
||||||
val multiplatformExtension = multiplatformExtensionOrNull ?: return emptySet()
|
|
||||||
val allParticipatingSourceSetsOfCompilation = compilation.allParticipatingSourceSets()
|
|
||||||
|
|
||||||
return multiplatformExtension.targets
|
|
||||||
.flatMap { target -> target.compilations }
|
|
||||||
.filterIsInstance<KotlinNativeCompilation>()
|
|
||||||
.filter { nativeCompilation -> nativeCompilation.allParticipatingSourceSets().containsAll(allParticipatingSourceSetsOfCompilation) }
|
|
||||||
.toSet()
|
|
||||||
}
|
|
||||||
|
|||||||
+5
-1
@@ -11,6 +11,7 @@ import org.gradle.api.tasks.Delete
|
|||||||
import org.gradle.api.tasks.TaskProvider
|
import org.gradle.api.tasks.TaskProvider
|
||||||
import org.jetbrains.kotlin.gradle.internal.isInIdeaSync
|
import org.jetbrains.kotlin.gradle.internal.isInIdeaSync
|
||||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
|
||||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||||
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
import org.jetbrains.kotlin.gradle.tasks.locateTask
|
||||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||||
@@ -50,8 +51,11 @@ internal val Project.commonizeCInteropTask: TaskProvider<CInteropCommonizerTask>
|
|||||||
return locateOrRegisterTask(
|
return locateOrRegisterTask(
|
||||||
"commonizeCInterop",
|
"commonizeCInterop",
|
||||||
invokeWhenRegistered = {
|
invokeWhenRegistered = {
|
||||||
|
val task = this
|
||||||
commonizeTask.dependsOn(this)
|
commonizeTask.dependsOn(this)
|
||||||
commonizeNativeDistributionTask?.let(this::dependsOn)
|
whenEvaluated {
|
||||||
|
commonizeNativeDistributionTask?.let(task::dependsOn)
|
||||||
|
}
|
||||||
},
|
},
|
||||||
configureTask = {
|
configureTask = {
|
||||||
group = "interop"
|
group = "interop"
|
||||||
|
|||||||
+5
-6
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.targets.native.internal
|
|||||||
|
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal open class CopyCommonizeCInteropForIdeTask : AbstractCInteropCommonizerTask() {
|
internal open class CopyCommonizeCInteropForIdeTask : AbstractCInteropCommonizerTask() {
|
||||||
@@ -25,17 +24,17 @@ internal open class CopyCommonizeCInteropForIdeTask : AbstractCInteropCommonizer
|
|||||||
override val outputDirectory: File = project.rootDir.resolve(".gradle/kotlin/commonizer")
|
override val outputDirectory: File = project.rootDir.resolve(".gradle/kotlin/commonizer")
|
||||||
.resolve(project.path.removePrefix(":").replace(":", "/"))
|
.resolve(project.path.removePrefix(":").replace(":", "/"))
|
||||||
|
|
||||||
override fun getCommonizationParameters(compilation: KotlinSharedNativeCompilation): CInteropCommonizationParameters? {
|
override fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup? {
|
||||||
return commonizeCInteropTask.get().getCommonizationParameters(compilation)
|
return commonizeCInteropTask.get().findInteropsGroup(dependent)
|
||||||
}
|
}
|
||||||
|
|
||||||
@TaskAction
|
@TaskAction
|
||||||
protected fun copy() {
|
protected fun copy() {
|
||||||
outputDirectory.mkdirs()
|
outputDirectory.mkdirs()
|
||||||
for (parameters in commonizeCInteropTask.get().getCommonizationParameters()) {
|
for (group in commonizeCInteropTask.get().getAllInteropsGroups()) {
|
||||||
val source = commonizeCInteropTask.get().outputDirectory(parameters)
|
val source = commonizeCInteropTask.get().outputDirectory(group)
|
||||||
if (!source.exists()) continue
|
if (!source.exists()) continue
|
||||||
val target = outputDirectory(parameters)
|
val target = outputDirectory(group)
|
||||||
if (target.exists()) target.deleteRecursively()
|
if (target.exists()) target.deleteRecursively()
|
||||||
source.copyRecursively(target, true)
|
source.copyRecursively(target, true)
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -85,6 +85,7 @@ private val Project.isNativeDependencyPropagationEnabled: Boolean
|
|||||||
internal fun Project.isAllowCommonizer(
|
internal fun Project.isAllowCommonizer(
|
||||||
kotlinVersion: String = getKotlinPluginVersion()
|
kotlinVersion: String = getKotlinPluginVersion()
|
||||||
): Boolean {
|
): Boolean {
|
||||||
|
assert(state.executed) { "'isAllowCommonizer' can only be called after project evaluation" }
|
||||||
multiplatformExtensionOrNull ?: return false
|
multiplatformExtensionOrNull ?: return false
|
||||||
|
|
||||||
//register commonizer only for 1.4+, only for HMPP projects
|
//register commonizer only for 1.4+, only for HMPP projects
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ public inline fun <reified T> transitiveClosure(seed: T, edges: T.() -> Iterable
|
|||||||
val initialEdges = seed.edges()
|
val initialEdges = seed.edges()
|
||||||
if (initialEdges is Collection && initialEdges.isEmpty()) return emptySet()
|
if (initialEdges is Collection && initialEdges.isEmpty()) return emptySet()
|
||||||
|
|
||||||
val queue = deque<T>()
|
val queue = deque<T>(initialEdges.count() * 2)
|
||||||
val results = mutableSetOf<T>()
|
val results = mutableSetOf<T>()
|
||||||
queue.addAll(initialEdges)
|
queue.addAll(initialEdges)
|
||||||
while (queue.isNotEmpty()) {
|
while (queue.isNotEmpty()) {
|
||||||
@@ -34,7 +34,7 @@ public inline fun <reified T> transitiveClosure(seed: T, edges: T.() -> Iterable
|
|||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
@PublishedApi
|
@PublishedApi
|
||||||
internal inline fun <reified T> deque(): MutableList<T> {
|
internal inline fun <reified T> deque(initialSize: Int): MutableList<T> {
|
||||||
return if (KotlinVersion.CURRENT.isAtLeast(1, 4)) ArrayDeque()
|
return if (KotlinVersion.CURRENT.isAtLeast(1, 4)) ArrayDeque(initialSize)
|
||||||
else mutableListOf()
|
else ArrayList(initialSize)
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user