[Gradle] Implement CInteropCommonizerDependent factories as safe suspend functions

^KT-34662 Verification Pending
This commit is contained in:
Sebastian Sellmair
2023-03-13 14:48:00 +01:00
committed by Space Team
parent 9517667081
commit b064493c7b
12 changed files with 109 additions and 108 deletions
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerDep
import org.jetbrains.kotlin.gradle.targets.native.internal.from
import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer
import org.jetbrains.kotlin.gradle.utils.findAppliedAndroidPluginIdOrNull
import org.jetbrains.kotlin.gradle.utils.future
import org.jetbrains.kotlin.gradle.utils.runProjectConfigurationHealthCheck
private class KotlinMultiplatformProjectConfigurationException(message: String) : Exception(message)
@@ -77,7 +78,10 @@ internal fun Project.runDisabledCInteropCommonizationOnHmppProjectConfigurationH
val sharedCompilationsWithInterops = multiplatformExtension.targets.flatMap { it.compilations }
.filterIsInstance<KotlinSharedNativeCompilation>()
.mapNotNull { compilation -> compilation to (CInteropCommonizerDependent.from(compilation) ?: return@mapNotNull null) }
.mapNotNull { compilation ->
val cinteropDependent = future { CInteropCommonizerDependent.from(compilation) }.getOrThrow() ?: return@mapNotNull null
compilation to cinteropDependent
}
.toMap()
val affectedCompilations = sharedCompilationsWithInterops.keys
@@ -21,6 +21,7 @@ import org.jetbrains.kotlin.gradle.plugin.extraProperties
import org.jetbrains.kotlin.gradle.plugin.mpp.MetadataDependencyResolution.ChooseVisibleSourceSets.MetadataProvider.ArtifactMetadataProvider
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.utils.LazyResolvedConfiguration
import org.jetbrains.kotlin.gradle.utils.future
import org.jetbrains.kotlin.gradle.utils.getOrPut
import java.util.*
@@ -143,7 +144,7 @@ internal class GranularMetadataTransformation(
params.resolvedMetadataConfiguration
.root
.dependencies
.filter { !it.isConstraint}
.filter { !it.isConstraint }
.filterIsInstance<ResolvedDependencyResult>()
)
}
@@ -332,15 +333,18 @@ internal val ResolvedComponentResult.currentBuildProjectIdOrNull
}
}
private val Project.allProjectsData: Map<String, GranularMetadataTransformation.ProjectData> get() = rootProject
.extraProperties
.getOrPut("all${GranularMetadataTransformation.ProjectData::class.java.simpleName}") { collectAllProjectsData() }
private val Project.allProjectsData: Map<String, GranularMetadataTransformation.ProjectData>
get() = rootProject
.extraProperties
.getOrPut("all${GranularMetadataTransformation.ProjectData::class.java.simpleName}") {
future { collectAllProjectsData() }.getOrThrow()
}
private fun Project.collectAllProjectsData(): Map<String, GranularMetadataTransformation.ProjectData> {
return rootProject.allprojects.associateBy { it.path }.mapValues { (path, subProject) ->
GranularMetadataTransformation.ProjectData(
path = path,
sourceSetMetadataOutputsProvider = { subProject.collectSourceSetMetadataOutputs() },
sourceSetMetadataOutputsProvider = future { subProject.collectSourceSetMetadataOutputs() }::getOrThrow,
moduleIdProvider = { ModuleIds.idOfRootModule(subProject) }
)
}
@@ -48,7 +48,7 @@ private class ProjectMetadataProviderImpl(
}
}
internal fun Project.collectSourceSetMetadataOutputs(): Map<SourceSetName, SourceSetMetadataOutputs> {
internal suspend fun Project.collectSourceSetMetadataOutputs(): Map<SourceSetName, SourceSetMetadataOutputs> {
val multiplatformExtension = multiplatformExtensionOrNull ?: return emptyMap()
val sourceSetMetadata = multiplatformExtension.sourceSetsMetadataOutputs()
@@ -82,7 +82,7 @@ private fun KotlinMultiplatformExtension.sourceSetsMetadataOutputs(): Map<Kotlin
}.toMap()
}
private fun KotlinMultiplatformExtension.cInteropMetadataOfSourceSets(
private suspend fun KotlinMultiplatformExtension.cInteropMetadataOfSourceSets(
sourceSets: Iterable<KotlinSourceSet>
): Map<KotlinSourceSet, SourceSetMetadataOutputs.CInterop?> {
val taskForCLI = project.commonizeCInteropTask ?: return emptyMap()
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.base64Hash
import org.jetbrains.kotlin.commonizer.CommonizerOutputFileLayout.ensureMaxFileNameLength
import org.jetbrains.kotlin.commonizer.identityString
import org.jetbrains.kotlin.gradle.utils.changing
import org.jetbrains.kotlin.gradle.utils.future
import org.jetbrains.kotlin.gradle.utils.outputFilesProvider
import java.io.File
@@ -20,7 +21,7 @@ internal abstract class AbstractCInteropCommonizerTask : DefaultTask() {
@get:OutputDirectory
abstract val outputDirectory: File
internal abstract fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup?
internal abstract suspend fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup?
}
internal fun AbstractCInteropCommonizerTask.outputDirectory(group: CInteropCommonizerGroup): File {
@@ -35,14 +36,15 @@ internal fun AbstractCInteropCommonizerTask.outputDirectory(group: CInteropCommo
internal fun AbstractCInteropCommonizerTask.commonizedOutputLibraries(dependent: CInteropCommonizerDependent): FileCollection {
return outputFilesProvider {
val outputDirectory = commonizedOutputDirectory(dependent) ?: return@outputFilesProvider emptySet<File>()
val outputDirectory = project.future { commonizedOutputDirectory(dependent) }.getOrThrow()
?: return@outputFilesProvider emptySet<File>()
project.providers.changing {
outputDirectory.listFiles().orEmpty().toSet()
}
}
}
internal fun AbstractCInteropCommonizerTask.commonizedOutputDirectory(dependent: CInteropCommonizerDependent): File? {
internal suspend fun AbstractCInteropCommonizerTask.commonizedOutputDirectory(dependent: CInteropCommonizerDependent): File? {
val group = findInteropsGroup(dependent) ?: return null
return CommonizerOutputFileLayout
.resolveCommonizedDirectory(outputDirectory(group), dependent.target)
@@ -9,16 +9,19 @@ import org.gradle.api.Project
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Zip
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.launch
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerCompositeMetadataJarBundling.cinteropMetadataDirectoryPath
internal fun Project.includeCommonizedCInteropMetadata(
metadataKlib: TaskProvider<out Zip>, compilation: KotlinSharedNativeCompilation
) {
metadataKlib.configure { jar -> includeCommonizedCInteropMetadata(jar, compilation) }
metadataKlib.configure { jar ->
launch { includeCommonizedCInteropMetadata(jar, compilation) }
}
}
internal fun Project.includeCommonizedCInteropMetadata(metadataKlib: Zip, compilation: KotlinSharedNativeCompilation) {
internal suspend fun Project.includeCommonizedCInteropMetadata(metadataKlib: Zip, compilation: KotlinSharedNativeCompilation) {
val commonizerTask = commonizeCInteropTask?.get() ?: return
val commonizerDependencyToken = CInteropCommonizerDependent.from(compilation) ?: return
val outputDirectory = commonizerTask.commonizedOutputDirectory(commonizerDependencyToken) ?: return
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.internal
import org.jetbrains.kotlin.gradle.utils.filesProvider
import org.jetbrains.kotlin.gradle.utils.future
import java.io.File
internal fun Project.setupCInteropCommonizerDependencies() {
@@ -33,7 +34,8 @@ private fun Project.setupCInteropCommonizerDependenciesForCompilation(compilatio
val cinteropCommonizerTask = project.commonizeCInteropTask ?: return
compilation.compileDependencyFiles += filesProvider {
val cinteropCommonizerDependent = CInteropCommonizerDependent.from(compilation) ?: return@filesProvider emptySet<File>()
val cinteropCommonizerDependent = future { CInteropCommonizerDependent.from(compilation) }.getOrThrow()
?: return@filesProvider emptySet<File>()
cinteropCommonizerTask.get().commonizedOutputLibraries(cinteropCommonizerDependent)
}
}
@@ -51,12 +53,14 @@ internal fun Project.cinteropCommonizerDependencies(sourceSet: DefaultKotlinSour
val cinteropCommonizerTask = project.copyCommonizeCInteropForIdeTask ?: return project.files()
return filesProvider {
val directlyDependent = CInteropCommonizerDependent.from(sourceSet)
val associateDependent = CInteropCommonizerDependent.fromAssociateCompilations(sourceSet)
future {
val directlyDependent = CInteropCommonizerDependent.from(sourceSet)
val associateDependent = CInteropCommonizerDependent.fromAssociateCompilations(sourceSet)
listOfNotNull(directlyDependent, associateDependent).map { cinteropCommonizerDependent ->
cinteropCommonizerTask.get().commonizedOutputLibraries(cinteropCommonizerDependent)
}
listOfNotNull(directlyDependent, associateDependent).map { cinteropCommonizerDependent ->
cinteropCommonizerTask.get().commonizedOutputLibraries(cinteropCommonizerDependent)
}
}.getOrThrow()
}
}
@@ -72,24 +72,24 @@ internal fun CInteropCommonizerDependent.Factory.from(
return CInteropCommonizerDependent(target, scopes, interops)
}
internal fun CInteropCommonizerDependent.Factory.from(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent? {
internal suspend fun CInteropCommonizerDependent.Factory.from(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent? {
return from(
compilation.commonizerTarget.getOrThrow() as? SharedCommonizerTarget ?: return null,
compilation.commonizerTarget.await() as? SharedCommonizerTarget ?: return null,
compilation.getImplicitlyDependingNativeCompilations()
)
}
internal fun CInteropCommonizerDependent.Factory.from(sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
internal suspend fun CInteropCommonizerDependent.Factory.from(sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
return from(
target = sourceSet.commonizerTarget.getOrThrow() as? SharedCommonizerTarget ?: return null,
target = sourceSet.commonizerTarget.await() as? SharedCommonizerTarget ?: return null,
compilations = sourceSet.internal.compilations
.filterIsInstance<KotlinNativeCompilation>().toSet()
)
}
internal fun CInteropCommonizerDependent.Factory.fromAssociateCompilations(sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
internal suspend fun CInteropCommonizerDependent.Factory.fromAssociateCompilations(sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
return from(
target = sourceSet.commonizerTarget.getOrThrow() as? SharedCommonizerTarget ?: return null,
target = sourceSet.commonizerTarget.await() as? SharedCommonizerTarget ?: return null,
compilations = sourceSet.internal.compilations
.filterIsInstance<KotlinNativeCompilation>()
.flatMap { compilation -> compilation.associateWithClosure }
@@ -27,9 +27,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.DefaultKotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.sources.withDependsOnClosure
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerTask.CInteropGist
import org.jetbrains.kotlin.gradle.tasks.CInteropProcess
import org.jetbrains.kotlin.gradle.utils.chainedFinalizeValueOnRead
import org.jetbrains.kotlin.gradle.utils.listProperty
import org.jetbrains.kotlin.gradle.utils.property
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
import javax.inject.Inject
@@ -123,14 +121,14 @@ internal open class CInteropCommonizerTask
* For Gradle Configuration Cache support the Group-to-Dependencies relation should be pre-cached.
* It is used during execution phase.
*/
private val groupedCommonizerDependencies: Map<CInteropCommonizerGroup, List<CInteropCommonizerDependencies>> by lazy {
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return@lazy emptyMap()
private val groupedCommonizerDependencies: Future<Map<CInteropCommonizerGroup, List<CInteropCommonizerDependencies>>> = project.future {
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return@future emptyMap()
val sourceSetsByTarget = multiplatformExtension.sourceSets.groupBy { sourceSet -> sourceSet.commonizerTarget.getOrThrow() }
val sourceSetsByGroup = multiplatformExtension.sourceSets.groupBy { sourceSet ->
CInteropCommonizerDependent.from(sourceSet)?.let { findInteropsGroup(it) }
}
getAllInteropsGroups().associateWith { group ->
allInteropGroups.await().associateWith { group ->
(group.targets + group.targets.allLeaves()).map { target ->
val externalDependencyFiles: List<FileCollection> = when (target) {
is LeafCommonizerTarget -> {
@@ -165,7 +163,7 @@ internal open class CInteropCommonizerTask
@get:Classpath
protected val commonizerDependenciesClasspath: FileCollection
get() = project.files(
groupedCommonizerDependencies.values.flatten().map { it.dependencies }
groupedCommonizerDependencies.getOrThrow().values.flatten().map { it.dependencies }
)
@get:Nested
@@ -174,7 +172,7 @@ internal open class CInteropCommonizerTask
@get:OutputDirectories
val allOutputDirectories: Set<File>
get() = getAllInteropsGroups().map { outputDirectory(it) }.toSet()
get() = allInteropGroups.getOrThrow().map { outputDirectory(it) }.toSet()
fun from(vararg tasks: CInteropProcess) = from(
tasks.toList()
@@ -192,7 +190,7 @@ internal open class CInteropCommonizerTask
@TaskAction
protected fun commonizeCInteropLibraries() {
getAllInteropsGroups().forEach(::commonize)
allInteropGroups.getOrThrow().forEach(::commonize)
}
private fun commonize(group: CInteropCommonizerGroup) {
@@ -217,7 +215,7 @@ internal open class CInteropCommonizerTask
}
private fun getCInteropCommonizerGroupDependencies(group: CInteropCommonizerGroup): Set<CommonizerDependency> {
val dependencies = groupedCommonizerDependencies[group]
val dependencies = groupedCommonizerDependencies.getOrThrow()[group]
?.flatMap { (target, dependencies) ->
dependencies.files
.filter { file -> file.exists() && (file.isDirectory || file.extension == "klib") }
@@ -229,15 +227,15 @@ internal open class CInteropCommonizerTask
return dependencies
}
@Nested
internal fun getAllInteropsGroups(): Set<CInteropCommonizerGroup> {
val dependents = allDependents
@get:Internal
internal val allInteropGroups: Future<Set<CInteropCommonizerGroup>> = project.future {
val dependents = allDependents.await()
val allScopeSets = dependents.map { it.scopes }.toSet()
val rootScopeSets = allScopeSets.filter { scopeSet ->
allScopeSets.none { otherScopeSet -> otherScopeSet != scopeSet && otherScopeSet.containsAll(scopeSet) }
}
return rootScopeSets.map { scopeSet ->
rootScopeSets.map { scopeSet ->
val dependentsForScopes = dependents.filter { dependent ->
scopeSet.containsAll(dependent.scopes)
}
@@ -249,8 +247,12 @@ internal open class CInteropCommonizerTask
}.toSet()
}
override fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup? {
val suitableGroups = getAllInteropsGroups().filter { group ->
@get:Nested
@Suppress("unused") // UP-TO-DATE check
protected val allInteropGroupsOrThrow get() = allInteropGroups.getOrThrow()
override suspend fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup? {
val suitableGroups = allInteropGroups.await().filter { group ->
group.interops.containsAll(dependent.interops) && group.targets.contains(dependent.target)
}
@@ -261,8 +263,8 @@ internal open class CInteropCommonizerTask
return suitableGroups.firstOrNull()
}
private val allDependents: Set<CInteropCommonizerDependent> by lazy {
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return@lazy emptySet()
private val allDependents: Future<Set<CInteropCommonizerDependent>> = project.future {
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return@future emptySet()
val fromSharedNativeCompilations = multiplatformExtension
.targets.flatMap { target -> target.compilations }
@@ -278,7 +280,7 @@ internal open class CInteropCommonizerTask
.mapNotNull { sourceSet -> CInteropCommonizerDependent.fromAssociateCompilations(sourceSet) }
.toSet()
return@lazy (fromSharedNativeCompilations + fromSourceSets + fromSourceSetsAssociateCompilations)
(fromSharedNativeCompilations + fromSourceSets + fromSourceSetsAssociateCompilations)
}
}
@@ -26,14 +26,14 @@ internal open class CopyCommonizeCInteropForIdeTask : AbstractCInteropCommonizer
override val outputDirectory: File = project.rootDir.resolve(".gradle/kotlin/commonizer")
.resolve(project.path.removePrefix(":").replace(":", "/"))
override fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup? {
override suspend fun findInteropsGroup(dependent: CInteropCommonizerDependent): CInteropCommonizerGroup? {
return commonizeCInteropTask.get().findInteropsGroup(dependent)
}
@TaskAction
protected fun copy() {
outputDirectory.mkdirs()
for (group in commonizeCInteropTask.get().getAllInteropsGroups()) {
for (group in commonizeCInteropTask.get().allInteropGroups.getOrThrow()) {
val source = commonizeCInteropTask.get().outputDirectory(group)
if (!source.exists()) continue
val target = outputDirectory(group)
@@ -16,6 +16,8 @@ import org.jetbrains.kotlin.gradle.plugin.kotlinPluginLifecycle
import org.jetbrains.kotlin.tooling.core.ExtrasLazyProperty
import org.jetbrains.kotlin.tooling.core.HasMutableExtras
import org.jetbrains.kotlin.tooling.core.extrasLazyProperty
import java.io.Serializable
import kotlin.reflect.KProperty
/**
* See [KotlinPluginLifecycle]:
@@ -62,45 +64,31 @@ internal inline fun <Receiver, reified T> lazyFuture(
internal fun <T> Project.future(block: suspend Project.() -> T): Future<T> = kotlinPluginLifecycle.future { block() }
@OptIn(ExperimentalCoroutinesApi::class)
internal fun <T> KotlinPluginLifecycle.future(block: suspend () -> T): Future<T> {
val deferred = CompletableDeferred<T>()
launch {
deferred.completeWith(runCatching { block() })
}
return object : Future<T> {
override suspend fun await(): T {
return deferred.await()
}
override fun getOrThrow(): T {
return if (deferred.isCompleted) deferred.getCompleted() else throw IllegalLifecycleException(
"Future was not completed yet. Stage: '${stage}'"
)
}
return FutureImpl<T>(CompletableDeferred()).also { future ->
launch { future.completeWith(runCatching { block() }) }
}
}
@OptIn(ExperimentalCoroutinesApi::class)
internal fun <T> CompletableFuture(): CompletableFuture<T> {
val deferred = CompletableDeferred<T>()
return FutureImpl()
}
@OptIn(ExperimentalCoroutinesApi::class)
private class FutureImpl<T>(private val deferred: CompletableDeferred<T> = CompletableDeferred()) : CompletableFuture<T>, Serializable {
fun completeWith(result: Result<T>) = deferred.completeWith(result)
return object : CompletableFuture<T> {
override fun complete(value: T) {
deferred.complete(value)
}
override suspend fun await(): T {
return deferred.await()
}
override fun getOrThrow(): T {
return if (deferred.isCompleted) deferred.getCompleted() else throw IllegalLifecycleException(
"Future was not completed yet"
)
}
override fun complete(value: T) {
deferred.complete(value)
}
}
override suspend fun await(): T {
return deferred.await()
}
override fun getOrThrow(): T {
return if (deferred.isCompleted) deferred.getCompleted() else throw IllegalLifecycleException(
"Future was not completed yet"
)
}
}
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
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.util.runLifecycleAwareTest
import org.jetbrains.kotlin.konan.target.KonanTarget.*
import kotlin.test.*
@@ -30,7 +31,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
}
@Test
fun `nativeMain linux macos`() {
fun `nativeMain linux macos`() = project.runLifecycleAwareTest {
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName")
val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName")
@@ -43,9 +44,8 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
linuxMain.dependsOn(nativeMain)
macosMain.dependsOn(nativeMain)
project.evaluate()
val groups = task.getAllInteropsGroups()
val groups = task.allInteropGroups.await()
assertEquals(1, groups.size, "Expected only one InteropsGroup")
assertCInteropDependentEqualsForSourceSetAndCompilation(nativeMain)
@@ -60,7 +60,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
}
@Test
fun `nativeMain linux macos (no macos interop defined)`() {
fun `nativeMain linux macos (no macos interop defined)`() = project.runLifecycleAwareTest {
kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName")
kotlin.macosX64("macos")
@@ -73,8 +73,6 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
linuxMain.dependsOn(nativeMain)
macosMain.dependsOn(nativeMain)
project.evaluate()
assertNull(
findCInteropCommonizerDependent(nativeMain),
"Expected no CInteropCommonizerTarget from nativeMain, since one target has not defined any cinterop"
@@ -87,7 +85,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
}
@Test
fun `nativeMain iosMain linux macos iosX64 iosArm64`() {
fun `nativeMain iosMain linux macos iosX64 iosArm64`() = project.runLifecycleAwareTest {
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 iosX64Interop = kotlin.iosX64("iosX64").compilations.getByName("main").cinterops.create("anyInteropName").identifier
@@ -108,10 +106,8 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
iosX64Main.dependsOn(iosMain)
iosArm64Main.dependsOn(iosMain)
project.evaluate()
assertEquals(
1, task.getAllInteropsGroups().size,
1, task.allInteropGroups.await().size,
"Expected exactly one InteropsGroup for task"
)
@@ -144,7 +140,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
private fun `nativeTest nativeMain linux macos`(
nativeTestDependsOnNativeMain: Boolean
) {
) = project.runLifecycleAwareTest {
val linuxInterop = kotlin.linuxX64("linux").compilations.getByName("main").cinterops.create("anyInteropName").identifier
val macosInterop = kotlin.macosX64("macos").compilations.getByName("main").cinterops.create("anyInteropName").identifier
@@ -169,10 +165,8 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
nativeTest.dependsOn(nativeMain)
}
project.evaluate()
assertEquals(
1, task.getAllInteropsGroups().size,
1, task.allInteropGroups.await().size,
"Expected exactly 1 'SharedInteropsGroup' for task"
)
@@ -209,7 +203,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
private fun `nativeTest nativeMain linux macos - test compilation defines custom cinterop`(
nativeTestDependsOnNativeMain: Boolean
) {
) = project.runLifecycleAwareTest {
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
@@ -235,10 +229,9 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
nativeTest.dependsOn(nativeMain)
}
project.evaluate()
assertEquals(
1, task.getAllInteropsGroups().size,
1, task.allInteropGroups.await().size,
"Expected exactly 1 'SharedInteropsGroup' for task"
)
@@ -271,7 +264,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
`hierarchical project`(testSourceSetsDependOnMainSourceSets = false)
}
private fun `hierarchical project`(testSourceSetsDependOnMainSourceSets: Boolean) {
private fun `hierarchical project`(testSourceSetsDependOnMainSourceSets: Boolean) = project.runLifecycleAwareTest {
/* Define targets */
val linux = kotlin.linuxX64("linux")
val macos = kotlin.macosX64("macos")
@@ -368,14 +361,13 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
target.compilations.getByName("test").defaultSourceSet.dependsOn(nativeTest)
}
project.evaluate()
assertCInteropDependentEqualsForSourceSetAndCompilation(nativeMain)
assertCInteropDependentEqualsForSourceSetAndCompilation(unixMain)
assertCInteropDependentEqualsForSourceSetAndCompilation(appleMain)
assertCInteropDependentEqualsForSourceSetAndCompilation(iosMain)
val groups = task.getAllInteropsGroups()
val groups = task.allInteropGroups.await()
assertEquals(2, groups.size, "Expected exactly two interop groups: main and test")
val nativeCommonizerTarget = SharedCommonizerTarget(nativeTargets.map { it.konanTarget })
@@ -462,7 +454,7 @@ class CInteropCommonizerTaskTest : MultiplatformExtensionTest() {
}
}
private fun assertCInteropDependentEqualsForSourceSetAndCompilation(sourceSet: KotlinSourceSet) {
private suspend fun assertCInteropDependentEqualsForSourceSetAndCompilation(sourceSet: KotlinSourceSet) {
assertEquals(
expectCInteropCommonizerDependent(sourceSet),
expectCInteropCommonizerDependent(expectSharedNativeCompilation(sourceSet)),
@@ -15,11 +15,13 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
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.targets.metadata.findMetadataCompilation
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
import kotlin.test.fail
abstract class MultiplatformExtensionTest {
@@ -39,29 +41,29 @@ abstract class MultiplatformExtensionTest {
project.enableCInteropCommonization()
}
internal fun expectCInteropCommonizerDependent(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent {
internal suspend fun expectCInteropCommonizerDependent(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent {
return assertNotNull(
CInteropCommonizerDependent.from(compilation), "Can't find SharedInterops for ${compilation.name} compilation"
)
}
internal fun expectCInteropCommonizerDependent(sourceSet: KotlinSourceSet): CInteropCommonizerDependent {
internal suspend fun expectCInteropCommonizerDependent(sourceSet: KotlinSourceSet): CInteropCommonizerDependent {
return assertNotNull(
CInteropCommonizerDependent.from(sourceSet), "Can't find SharedInterops for ${sourceSet.name} source set"
)
}
internal fun findCInteropCommonizerDependent(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent? {
internal suspend fun findCInteropCommonizerDependent(compilation: KotlinSharedNativeCompilation): CInteropCommonizerDependent? {
return CInteropCommonizerDependent.from(compilation)
}
internal fun findCInteropCommonizerDependent(sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
internal suspend fun findCInteropCommonizerDependent(sourceSet: KotlinSourceSet): CInteropCommonizerDependent? {
return CInteropCommonizerDependent.from(sourceSet)
}
internal fun expectSharedNativeCompilation(sourceSet: KotlinSourceSet): KotlinSharedNativeCompilation {
return kotlin.targets.flatMap { it.compilations }.filterIsInstance<KotlinSharedNativeCompilation>()
.single { it.defaultSourceSet == sourceSet }
internal suspend fun expectSharedNativeCompilation(sourceSet: KotlinSourceSet): KotlinSharedNativeCompilation {
val compilation = project.findMetadataCompilation(sourceSet) ?: fail("Missing metadata compilation for $sourceSet")
return assertIsInstance<KotlinSharedNativeCompilation>(compilation)
}
internal fun KotlinNativeTarget.mainCinteropIdentifier(name: String): CInteropIdentifier {