[KT-51517] Pass external cinterop dependencies to Commonizer.
This commit is contained in:
committed by
Space
parent
a209098a6c
commit
c9184c6781
+14
@@ -700,6 +700,20 @@ class CommonizerIT : BaseGradleIT() {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test KT-51517 commonization with transitive cinterop`() {
|
||||
with(Project("commonize-kt-51517-transitive-cinterop")) {
|
||||
build(":app:assemble") {
|
||||
assertSuccessful()
|
||||
assertTasksExecuted(":lib:transformCommonMainCInteropDependenciesMetadata")
|
||||
assertTasksExecuted(":lib:commonizeCInterop")
|
||||
assertTasksExecuted(":lib:compileCommonMainKotlinMetadata")
|
||||
assertTasksExecuted(":app:commonizeCInterop")
|
||||
assertTasksExecuted(":app:compileNativeMainKotlinMetadata")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun preparedProject(name: String): Project {
|
||||
return Project(name).apply {
|
||||
setupWorkingDir()
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
jvm()
|
||||
listOf(linuxX64(), linuxArm64(), mingwX64()).forEach {
|
||||
it.compilations.getByName("main") {
|
||||
cinterops.create("yummy") {
|
||||
val nativeLibs = rootDir.resolve("native-libs")
|
||||
defFile = nativeLibs.resolve("yummy.def")
|
||||
compilerOpts += "-I" + nativeLibs.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
val commonMain by getting
|
||||
val linuxX64Main by getting
|
||||
val linuxArm64Main by getting
|
||||
val mingwX64Main by getting
|
||||
|
||||
val linuxMain by creating {
|
||||
linuxX64Main.dependsOn(this)
|
||||
linuxArm64Main.dependsOn(this)
|
||||
}
|
||||
val nativeMain by creating {
|
||||
this.dependsOn(commonMain)
|
||||
linuxMain.dependsOn(this)
|
||||
mingwX64Main.dependsOn(this)
|
||||
dependencies {
|
||||
implementation(project(":lib"))
|
||||
}
|
||||
}
|
||||
val commonTest by getting
|
||||
val linuxX64Test by getting
|
||||
val linuxArm64Test by getting
|
||||
val mingwX64Test by getting
|
||||
|
||||
val linuxTest by creating {
|
||||
linuxX64Test.dependsOn(this)
|
||||
linuxArm64Test.dependsOn(this)
|
||||
}
|
||||
val nativeTest by creating {
|
||||
this.dependsOn(commonTest)
|
||||
linuxTest.dependsOn(this)
|
||||
mingwX64Test.dependsOn(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
+16
@@ -0,0 +1,16 @@
|
||||
import dummy.LENGTH
|
||||
import dummy.Y
|
||||
import dummy.foo
|
||||
import kotlinx.cinterop.cValue
|
||||
import yummy.sel
|
||||
import yummy.yummy
|
||||
|
||||
fun nativeMain() {
|
||||
val y = cValue<Y> {
|
||||
n = 42
|
||||
}
|
||||
yummy(y)
|
||||
foo()
|
||||
sel(LENGTH)
|
||||
dummyMain()
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
plugins {
|
||||
kotlin("multiplatform").apply(false)
|
||||
}
|
||||
|
||||
allprojects {
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
kotlin.mpp.enableCInteropCommonization=true
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
plugins {
|
||||
kotlin("multiplatform")
|
||||
}
|
||||
|
||||
kotlin {
|
||||
listOf(linuxX64(), linuxArm64(), mingwX64()).forEach {
|
||||
it.compilations.getByName("main") {
|
||||
cinterops.create("dummy") {
|
||||
val nativeLibs = rootDir.resolve("native-libs")
|
||||
defFile = nativeLibs.resolve("dummy.def")
|
||||
compilerOpts += "-I" + nativeLibs.absolutePath
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
import dummy.foo
|
||||
|
||||
fun dummyMain() {
|
||||
foo()
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
headers = dummy.h
|
||||
+3
@@ -0,0 +1,3 @@
|
||||
#define LENGTH 10
|
||||
struct Y { int n; };
|
||||
int foo();
|
||||
+1
@@ -0,0 +1 @@
|
||||
headers = yummy.h
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
#include "dummy.h"
|
||||
|
||||
void yummy(struct Y * ee);
|
||||
void sel(int i);
|
||||
+2
@@ -0,0 +1,2 @@
|
||||
include(":app")
|
||||
include(":lib")
|
||||
+65
-12
@@ -6,6 +6,7 @@
|
||||
package org.jetbrains.kotlin.gradle.targets.native.internal
|
||||
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.ProjectLayout
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.ListProperty
|
||||
@@ -13,21 +14,21 @@ import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.ExecOperations
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerDependency
|
||||
import org.jetbrains.kotlin.commonizer.TargetedCommonizerDependency
|
||||
import org.jetbrains.kotlin.commonizer.allLeaves
|
||||
import org.jetbrains.kotlin.compilerRunner.*
|
||||
import org.jetbrains.kotlin.commonizer.*
|
||||
import org.jetbrains.kotlin.compilerRunner.GradleCliCommonizer
|
||||
import org.jetbrains.kotlin.compilerRunner.KotlinNativeCommonizerToolRunner
|
||||
import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner
|
||||
import org.jetbrains.kotlin.compilerRunner.konanHome
|
||||
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.KotlinSharedNativeCompilation
|
||||
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.filesProvider
|
||||
import org.jetbrains.kotlin.gradle.utils.listProperty
|
||||
import org.jetbrains.kotlin.gradle.utils.property
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
@@ -48,7 +49,10 @@ internal open class CInteropCommonizerTask
|
||||
sourceSets: Provider<Set<KotlinSourceSet>>,
|
||||
|
||||
@get:Classpath
|
||||
val libraryFile: Provider<File>
|
||||
val libraryFile: Provider<File>,
|
||||
|
||||
@get:Classpath
|
||||
val dependencies: FileCollection
|
||||
) {
|
||||
@Suppress("unused") // Used for UP-TO-DATE check
|
||||
@get:Input
|
||||
@@ -65,6 +69,7 @@ internal open class CInteropCommonizerTask
|
||||
if (identifier != other.identifier) return false
|
||||
if (konanTarget != other.konanTarget) return false
|
||||
if (libraryFile != other.libraryFile) return false
|
||||
if (dependencies != other.dependencies) return false
|
||||
if (allSourceSetNames != other.allSourceSetNames) return false
|
||||
|
||||
return true
|
||||
@@ -75,6 +80,7 @@ internal open class CInteropCommonizerTask
|
||||
var result = identifier.hashCode()
|
||||
result = 31 * result + konanTarget.hashCode()
|
||||
result = 31 * result + libraryFile.hashCode()
|
||||
result = 31 * result + dependencies.hashCode()
|
||||
result = 31 * result + allSourceSetNames.hashCode()
|
||||
return result
|
||||
}
|
||||
@@ -109,18 +115,58 @@ internal open class CInteropCommonizerTask
|
||||
private val commonizerLogLevel = project.commonizerLogLevel
|
||||
private val additionalCommonizerSettings = project.additionalCommonizerSettings
|
||||
|
||||
data class CInteropCommonizerDependencies(
|
||||
val commonizerTarget: CommonizerTarget,
|
||||
val dependencies: FileCollection
|
||||
)
|
||||
|
||||
/**
|
||||
* For Gradle Configuration Cache support the Group-to-Dependencies relation should be pre-cached.
|
||||
* It is used during execution phase.
|
||||
*/
|
||||
private val nativeDistributionDependenciesMap: Map<CInteropCommonizerGroup, Set<CommonizerDependency>> by lazy {
|
||||
private val groupedCommonizerDependencies: Map<CInteropCommonizerGroup, List<CInteropCommonizerDependencies>> by lazy {
|
||||
val multiplatformExtension = project.multiplatformExtensionOrNull ?: return@lazy emptyMap()
|
||||
|
||||
val sourceSetsByTarget = multiplatformExtension.sourceSets.groupBy { sourceSet ->
|
||||
project.getCommonizerTarget(sourceSet)
|
||||
}
|
||||
val sourceSetsByGroup = multiplatformExtension.sourceSets.groupBy { sourceSet ->
|
||||
CInteropCommonizerDependent.from(project, sourceSet)?.let { findInteropsGroup(it) }
|
||||
}
|
||||
getAllInteropsGroups().associateWith { group ->
|
||||
(group.targets + group.targets.allLeaves()).flatMapTo(mutableSetOf()) { target ->
|
||||
project.getNativeDistributionDependencies(target).map { dependency -> TargetedCommonizerDependency(target, dependency) }
|
||||
(group.targets + group.targets.allLeaves()).map { target ->
|
||||
val externalDependencyFiles = when (target) {
|
||||
is LeafCommonizerTarget -> {
|
||||
cinterops
|
||||
.filter { cinterop -> cinterop.identifier in group.interops && cinterop.konanTarget == target.konanTarget }
|
||||
.map { cinterop -> cinterop.dependencies }
|
||||
}
|
||||
|
||||
is SharedCommonizerTarget -> {
|
||||
val targetSourceSets = sourceSetsByTarget[target].orEmpty()
|
||||
val groupSourceSets = sourceSetsByGroup[group].orEmpty().toSet()
|
||||
targetSourceSets.intersect(groupSourceSets)
|
||||
.filterIsInstance<DefaultKotlinSourceSet>()
|
||||
.map { sourceSet -> project.createCInteropMetadataDependencyClasspath(sourceSet) }
|
||||
}
|
||||
}
|
||||
val nativeDistributionDependencyFiles = project.getNativeDistributionDependencies(target)
|
||||
|
||||
CInteropCommonizerDependencies(
|
||||
target,
|
||||
project.files(externalDependencyFiles + nativeDistributionDependencyFiles)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Suppress("unused") // Used for UP-TO-DATE check
|
||||
@get:Classpath
|
||||
protected val commonizerDependenciesClasspath: FileCollection
|
||||
get() = project.files(
|
||||
groupedCommonizerDependencies.values.flatten().map { it.dependencies }
|
||||
)
|
||||
|
||||
@get:Nested
|
||||
internal var cinterops = setOf<CInteropGist>()
|
||||
private set
|
||||
@@ -169,15 +215,21 @@ internal open class CInteropCommonizerTask
|
||||
konanHome = konanHome,
|
||||
outputTargets = group.targets,
|
||||
inputLibraries = cinteropsForTarget.map { it.libraryFile.get() }.filter { it.exists() }.toSet(),
|
||||
dependencyLibraries = getNativeDistributionDependencies(group),
|
||||
dependencyLibraries = getCInteropCommonizerGroupDependencies(group),
|
||||
outputDirectory = outputDirectory(group),
|
||||
logLevel = commonizerLogLevel,
|
||||
additionalSettings = additionalCommonizerSettings,
|
||||
)
|
||||
}
|
||||
|
||||
private fun getNativeDistributionDependencies(group: CInteropCommonizerGroup): Set<CommonizerDependency> {
|
||||
val dependencies = nativeDistributionDependenciesMap[group]
|
||||
private fun getCInteropCommonizerGroupDependencies(group: CInteropCommonizerGroup): Set<CommonizerDependency> {
|
||||
val dependencies = groupedCommonizerDependencies[group]
|
||||
?.flatMap { (target, dependencies) ->
|
||||
dependencies.files
|
||||
.filter { file -> file.exists() && (file.isDirectory || file.extension == "klib") }
|
||||
.map { file -> TargetedCommonizerDependency(target, file) }
|
||||
}
|
||||
?.toSet()
|
||||
requireNotNull(dependencies) { "Unexpected $group" }
|
||||
|
||||
return dependencies
|
||||
@@ -242,6 +294,7 @@ private fun CInteropProcess.toGist(): CInteropGist {
|
||||
konanTarget = konanTarget,
|
||||
// FIXME support cinterop with PM20
|
||||
sourceSets = project.provider { (settings.compilation as? KotlinCompilation<*>)?.kotlinSourceSets },
|
||||
libraryFile = outputFileProvider
|
||||
libraryFile = outputFileProvider,
|
||||
dependencies = libraries
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user