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