KT-66156 add KotlinRuntime to Swift Export Synthetic

This commit is contained in:
Andrey Yastrebov
2024-02-27 10:47:26 +01:00
committed by Space Team
parent a17ad6bc55
commit 42f6eb4eb4
8 changed files with 81 additions and 30 deletions
@@ -1,5 +1,5 @@
import SwiftUI
@testable import shared
@testable import Shared
struct ContentView: View {
var body: some View {
@@ -7,7 +7,7 @@
//
import XCTest
@testable import shared
@testable import Shared
final class iosAppTests: XCTestCase {
@@ -9,7 +9,7 @@ kotlin {
iosSimulatorArm64()
).forEach {
it.binaries.framework {
baseName = "sdk"
baseName = "Shared"
}
}
@@ -24,11 +24,19 @@ internal abstract class CopySwiftExportIntermediatesForConsumer @Inject construc
providerFactory: ProviderFactory,
private val fileSystem: FileSystemOperations
) : DefaultTask() {
companion object {
private const val KOTLIN_RUNTIME = "KotlinRuntime"
private const val KOTLIN_BRIDGE = "KotlinBridge"
}
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val includeBridgeDirectory: RegularFileProperty
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val includeKotlinRuntimeDirectory: RegularFileProperty
@get:InputFile
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val kotlinLibraryPath: RegularFileProperty
@@ -53,7 +61,16 @@ internal abstract class CopySwiftExportIntermediatesForConsumer @Inject construc
val syntheticInterfacesDestinationPath: DirectoryProperty = objectFactory.directoryProperty().convention(
builtProductsDirectory.flatMap {
projectLayout.dir(providerFactory.provider {
it.asFile.resolve("KotlinBridge")
it.asFile.resolve(KOTLIN_BRIDGE)
})
}
)
@get:OutputDirectory
val kotlinRuntimeDestinationPath: DirectoryProperty = objectFactory.directoryProperty().convention(
builtProductsDirectory.flatMap {
projectLayout.dir(providerFactory.provider {
it.asFile.resolve(KOTLIN_RUNTIME)
})
}
)
@@ -70,5 +87,9 @@ internal abstract class CopySwiftExportIntermediatesForConsumer @Inject construc
it.from(includeBridgeDirectory)
it.into(syntheticInterfacesDestinationPath)
}
fileSystem.copy {
it.from(includeKotlinRuntimeDirectory)
it.into(kotlinRuntimeDestinationPath)
}
}
}
@@ -18,6 +18,9 @@ import org.jetbrains.kotlin.incremental.deleteRecursivelyOrThrow
@DisableCachingByDefault(because = "Swift Export is experimental, so no caching for now")
internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
companion object {
private const val KOTLIN_RUNTIME = "KotlinRuntime"
}
@get:Input
abstract val swiftApiModuleName: Property<String>
@@ -31,6 +34,10 @@ internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
@get:Input
abstract val kotlinLibraryName: Property<String>
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val kotlinRuntime: DirectoryProperty
@get:InputFile
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val swiftApiPath: RegularFileProperty
@@ -49,6 +56,9 @@ internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
@get:Internal
val headerBridgeIncludePath get() = headerBridgeModulePath.resolve("include")
@get:Internal
val kotlinRuntimeIncludePath get() = kotlinRuntimeModulePath.resolve("include")
private val swiftApiModule get() = swiftApiModuleName.get()
private val headerBridgeModule get() = headerBridgeModuleName.get()
private val spmPackageRootPath get() = packagePath.getFile()
@@ -56,6 +66,7 @@ internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
private val sourcesPath get() = spmPackageRootPath.resolve("Sources")
private val swiftApiModulePath get() = sourcesPath.resolve(swiftApiModule)
private val headerBridgeModulePath get() = sourcesPath.resolve(headerBridgeModule)
private val kotlinRuntimeModulePath get() = sourcesPath.resolve(KOTLIN_RUNTIME)
@TaskAction
fun generate() {
@@ -63,6 +74,7 @@ internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
createHeaderTarget()
createSwiftTarget()
createPackageManifest()
createKotlinRuntimeTarget()
}
private fun preparePackageDirectory() {
@@ -71,10 +83,11 @@ internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
}
swiftApiModulePath.createDirectory()
headerBridgeIncludePath.createDirectory()
kotlinRuntimeIncludePath.createDirectory()
}
private fun createHeaderTarget() {
headerBridgePath.get().asFile.copyTo(
headerBridgePath.getFile().copyTo(
headerBridgeIncludePath.resolve("Kotlin.h")
)
headerBridgeIncludePath.resolve("module.modulemap").writeText(
@@ -91,6 +104,15 @@ internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
headerBridgeModulePath.resolve("linkingStub.c").writeText("\n")
}
private fun createKotlinRuntimeTarget() {
kotlinRuntime.asFileTree.forEach {
it.copyTo(
kotlinRuntimeIncludePath.resolve(it.name)
)
}
kotlinRuntimeModulePath.resolve("linkingStub.c").writeText("\n")
}
private fun createSwiftTarget() {
swiftApiModulePath.resolve("Kotlin.swift").writer().use { kotlinApi ->
swiftApiPath.get().asFile.reader().forEachLine {
@@ -117,10 +139,13 @@ internal abstract class GenerateSPMPackageFromSwiftExport : DefaultTask() {
targets: [
.target(
name: "$swiftApiModule",
dependencies: ["$headerBridgeModule"]
dependencies: ["$headerBridgeModule", "$KOTLIN_RUNTIME"]
),
.target(
name: "$headerBridgeModule"
),
.target(
name: "$KOTLIN_RUNTIME"
)
]
)
@@ -15,8 +15,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventionsIm
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeBinaryContainer
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.kotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
@@ -26,12 +24,13 @@ import org.jetbrains.kotlin.gradle.utils.getOrCreate
import org.jetbrains.kotlin.gradle.utils.konanDistribution
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.gradle.utils.mapToFile
import org.jetbrains.kotlin.konan.target.Distribution
fun Project.registerSwiftExportTask(
framework: Framework,
): TaskProvider<*> {
return registerSwiftExportTask(
swiftApiModuleName = framework.baseNameProvider,
swiftApiModuleName = provider { framework.baseName },
target = framework.target,
buildType = framework.buildType,
)
@@ -112,16 +111,16 @@ private fun Project.registerSwiftExportRun(
val kotlinIntermediates = outputs.map { it.dir("kotlinIntermediates") }
// Input
task.swiftExportClasspath.from(project.maybeCreateSwiftExportClasspathResolvableConfiguration())
task.parameters.sourceRoot.set(commonMainProvider.getOrThrow())
task.parameters.bridgeModuleName.set(swiftApiModuleName.map { "${it}Bridge" })
task.parameters.debugMode.set(true)
task.parameters.konanDistribution.set(konanDistribution.root)
task.swiftExportClasspath.from(maybeCreateSwiftExportClasspathResolvableConfiguration())
task.parameters.sourceRoot.convention(commonMainProvider.map { objects.directoryProperty(it) }.getOrThrow())
task.parameters.bridgeModuleName.convention(swiftApiModuleName.map { "${it}Bridge" })
task.parameters.debugMode.convention(true)
task.parameters.konanDistribution.convention(Distribution(konanDistribution.root.absolutePath))
// Output
task.parameters.swiftApiPath.set(swiftIntermediates.map { it.file("KotlinAPI.swift") })
task.parameters.headerBridgePath.set(swiftIntermediates.map { it.file("KotlinBridge.h") })
task.parameters.kotlinBridgePath.set(kotlinIntermediates.map { it.file("KotlinBridge.kt") })
task.parameters.swiftApiPath.convention(swiftIntermediates.map { it.file("KotlinAPI.swift") })
task.parameters.headerBridgePath.convention(swiftIntermediates.map { it.file("KotlinBridge.h") })
task.parameters.kotlinBridgePath.convention(kotlinIntermediates.map { it.file("KotlinBridge.kt") })
}
}
@@ -174,13 +173,19 @@ private fun Project.registerPackageGeneration(
task.description = "Generates $taskNamePrefix SPM Package"
// Input
task.swiftApiPath.set(swiftExportTask.map { it.parameters.swiftApiPath.get() })
task.headerBridgePath.set(swiftExportTask.map { it.parameters.headerBridgePath.get() })
task.headerBridgeModuleName.set(swiftExportTask.map { it.parameters.bridgeModuleName.get() })
task.libraryPath.set { staticLibrary.linkTaskProvider.map { it.outputFile.get() }.get() }
task.swiftLibraryName.set(swiftApiLibraryName)
task.kotlinLibraryName.set(kotlinStaticLibraryName)
task.swiftApiModuleName.set(swiftApiModuleName)
task.kotlinRuntime.convention(
objects.directoryProperty(
file(Distribution(konanDistribution.root.absolutePath).kotlinRuntimeForSwiftHome)
)
)
task.swiftApiPath.convention(swiftExportTask.flatMap { it.parameters.swiftApiPath })
task.headerBridgePath.convention(swiftExportTask.flatMap { it.parameters.headerBridgePath })
task.headerBridgeModuleName.convention(swiftExportTask.flatMap { it.parameters.bridgeModuleName })
task.libraryPath.convention(staticLibrary.linkTaskProvider.flatMap { layout.file(it.outputFile) })
task.swiftLibraryName.convention(swiftApiLibraryName)
task.kotlinLibraryName.convention(kotlinStaticLibraryName)
task.swiftApiModuleName.convention(swiftApiModuleName)
// Output
task.packagePath.set(syntheticBuildRoot.flatMap { root ->
@@ -205,7 +210,7 @@ private fun Project.registerSyntheticProjectBuild(
task.description = "Builds $taskNamePrefix synthetic project"
task.swiftApiModuleName.set(swiftApiModuleName)
task.swiftLibraryName.set(swiftApiLibraryName)
task.syntheticProjectDirectory.set(syntheticBuildRoot)
task.syntheticProjectDirectory.convention(syntheticBuildRoot)
}
syntheticProjectBuild.dependsOn(packageGenerationTask)
return syntheticProjectBuild
@@ -222,6 +227,7 @@ private fun Project.registerCopyTask(
task.group = BasePlugin.BUILD_GROUP
task.description = "Copy $taskNamePrefix synthetic project intermediates"
task.includeBridgeDirectory.convention(layout.file(packageGenerationTask.map { it.headerBridgeIncludePath }))
task.includeKotlinRuntimeDirectory.convention(layout.file(packageGenerationTask.map { it.kotlinRuntimeIncludePath }))
task.kotlinLibraryPath.convention(layout.file(staticLibrary.linkTaskProvider.flatMap { it.outputFile }))
task.syntheticLibraryPath.convention(layout.file(syntheticProjectBuild.flatMap { it.syntheticLibraryPath.mapToFile() }))
task.syntheticInterfacesPath.convention(layout.file(syntheticProjectBuild.flatMap { it.syntheticInterfacesPath.mapToFile() }))
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.apple.swiftexport
import org.gradle.workers.WorkAction
import org.jetbrains.kotlin.gradle.utils.getFile
import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.swiftexport.standalone.*
import java.util.logging.Level
import java.util.logging.Logger
@@ -40,7 +39,7 @@ internal abstract class SwiftExportAction : WorkAction<SwiftExportParameters> {
SwiftExportConfig.BRIDGE_MODULE_NAME to parameters.bridgeModuleName.getOrElse(SwiftExportConfig.DEFAULT_BRIDGE_MODULE_NAME),
),
Companion,
distribution = Distribution(parameters.konanDistribution.getFile().absolutePath),
distribution = parameters.konanDistribution.get(),
),
output = SwiftExportOutput(
swiftApi = parameters.swiftApiPath.getFile().toPath(),
@@ -10,6 +10,7 @@ import org.gradle.api.file.RegularFileProperty
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.gradle.workers.WorkParameters
import org.jetbrains.kotlin.konan.target.Distribution
internal interface SwiftExportParameters : WorkParameters {
@@ -19,9 +20,8 @@ internal interface SwiftExportParameters : WorkParameters {
@get:Input
val debugMode: Property<Boolean>
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)
val konanDistribution: DirectoryProperty
@get:Input
val konanDistribution: Property<Distribution>
@get:InputDirectory
@get:PathSensitive(PathSensitivity.RELATIVE)