[gradle-plugin] Support Konan tooling model in the exp plugin (#2008)
This commit is contained in:
+5
-9
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
// TODO: implement ComponentWithObjectFiles when we build klibs as objects
|
||||
interface KotlinNativeBinary: ComponentWithDependencies, BuildableComponent {
|
||||
interface KotlinNativeBinary : ComponentWithDependencies, BuildableComponent, ComponentWithOutputs {
|
||||
|
||||
/** A component this binary belongs to. */
|
||||
val component: KotlinNativeComponent
|
||||
@@ -86,7 +86,6 @@ interface KotlinNativeBinary: ComponentWithDependencies, BuildableComponent {
|
||||
*/
|
||||
// TODO: Consider implementing ComponentWithExecutable and ComponentWithInstallation.
|
||||
interface KotlinNativeExecutable : KotlinNativeBinary,
|
||||
ComponentWithOutputs,
|
||||
PublishableComponent,
|
||||
ConfigurableComponentWithRuntimeUsage
|
||||
|
||||
@@ -95,29 +94,26 @@ interface KotlinNativeExecutable : KotlinNativeBinary,
|
||||
*/
|
||||
// TODO: Consider implementing ComponentWithLinkFile.
|
||||
interface KotlinNativeLibrary : KotlinNativeBinary,
|
||||
ComponentWithOutputs,
|
||||
PublishableComponent,
|
||||
ConfigurableComponentWithLinkUsage
|
||||
|
||||
/**
|
||||
* Represents an Objective C framework compiled from Kotlin/Native sources.
|
||||
*/
|
||||
interface KotlinNativeFramework : KotlinNativeBinary, ComponentWithOutputs
|
||||
interface KotlinNativeFramework : KotlinNativeBinary
|
||||
|
||||
/**
|
||||
* A shared library compiled from Kotlin/Native sources.
|
||||
*/
|
||||
interface KotlinNativeDynamic : KotlinNativeBinary, ComponentWithOutputs
|
||||
interface KotlinNativeDynamic : KotlinNativeBinary
|
||||
|
||||
/**
|
||||
* A static library compiled from Kotlin/Native sources.
|
||||
*/
|
||||
interface KotlinNativeStatic : KotlinNativeBinary, ComponentWithOutputs
|
||||
interface KotlinNativeStatic : KotlinNativeBinary
|
||||
|
||||
/**
|
||||
* Represents a test executable.
|
||||
*/
|
||||
// TODO: Consider implementing ComponentWithExecutable and ComponentWithInstallation.
|
||||
interface KotlinNativeTestExecutable : KotlinNativeBinary,
|
||||
ComponentWithOutputs,
|
||||
TestComponent
|
||||
interface KotlinNativeTestExecutable : KotlinNativeBinary, TestComponent
|
||||
+62
-7
@@ -18,29 +18,84 @@ package org.jetbrains.kotlin.gradle.plugin.model
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilder
|
||||
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeBinary
|
||||
import org.jetbrains.kotlin.gradle.plugin.konanArtifactsContainer
|
||||
import org.jetbrains.kotlin.gradle.plugin.konanExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.konanHome
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import java.io.File
|
||||
import java.lang.IllegalStateException
|
||||
|
||||
|
||||
object KonanToolingModelBuilder : ToolingModelBuilder {
|
||||
|
||||
override fun canBuild(modelName: String) = KonanModel::class.java.name == modelName
|
||||
|
||||
override fun buildAll(modelName: String, project: Project): KonanModel {
|
||||
private fun buildModelKonan(project: Project): KonanModel {
|
||||
val artifacts = project.konanArtifactsContainer.flatten().toList().map { it.toModelArtifact() }
|
||||
return KonanModelImpl(
|
||||
artifacts,
|
||||
project.file(project.konanHome),
|
||||
KonanVersion.CURRENT,
|
||||
// TODO: Provide defaults for these versions.
|
||||
project.konanExtension.languageVersion,
|
||||
project.konanExtension.apiVersion
|
||||
artifacts,
|
||||
project.file(project.konanHome),
|
||||
KonanVersion.CURRENT,
|
||||
// TODO: Provide defaults for these versions.
|
||||
project.konanExtension.languageVersion,
|
||||
project.konanExtension.apiVersion
|
||||
)
|
||||
}
|
||||
|
||||
private fun buildModelKotlinNative(project: Project): KonanModel {
|
||||
val artifacts = project.components.withType(AbstractKotlinNativeBinary::class.java).map {
|
||||
it.toModelArtifact()
|
||||
}
|
||||
return KonanModelImpl(
|
||||
artifacts,
|
||||
project.file(project.konanHome),
|
||||
KonanVersion.CURRENT,
|
||||
null,
|
||||
null
|
||||
)
|
||||
}
|
||||
|
||||
private fun AbstractKotlinNativeBinary.toModelArtifact(): KonanModelArtifact {
|
||||
val compileTask = compileTask.get()
|
||||
val sourceRoots = with(component.sources) {
|
||||
kotlin.srcDirs + getPlatformSources(konanTarget).srcDirs
|
||||
}
|
||||
return KonanModelArtifactImpl(
|
||||
name,
|
||||
compileTask.outputFile,
|
||||
kind,
|
||||
konanTarget.name,
|
||||
compileTask.name,
|
||||
sourceRoots.toList(),
|
||||
sources.files.toList(),
|
||||
klibraries.files.toList(),
|
||||
klibraries.files.map { it.parentFile }
|
||||
)
|
||||
}
|
||||
|
||||
private val Project.hasKonanPlugin: Boolean
|
||||
get() = with(pluginManager) {
|
||||
hasPlugin("konan") ||
|
||||
hasPlugin("org.jetbrains.kotlin.konan")
|
||||
}
|
||||
|
||||
private val Project.hasKotlinNativePlugin: Boolean
|
||||
get() = with(pluginManager) {
|
||||
hasPlugin("kotlin-native") ||
|
||||
hasPlugin("kotlin-platform-native") ||
|
||||
hasPlugin("org.jetbrains.kotlin.native") ||
|
||||
hasPlugin("org.jetbrains.kotlin.platform.native")
|
||||
}
|
||||
|
||||
|
||||
override fun buildAll(modelName: String, project: Project): KonanModel =
|
||||
when {
|
||||
project.hasKotlinNativePlugin -> buildModelKotlinNative(project)
|
||||
project.hasKonanPlugin -> buildModelKonan(project)
|
||||
else -> throw IllegalStateException("The project '${project.path}' has no Kotlin/Native plugin")
|
||||
}
|
||||
}
|
||||
|
||||
internal data class KonanModelImpl(
|
||||
|
||||
@@ -9,7 +9,9 @@ import org.gradle.testkit.runner.TaskOutcome
|
||||
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.KotlinNativeMainComponent
|
||||
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.OutputKind
|
||||
import org.jetbrains.kotlin.gradle.plugin.experimental.plugins.KotlinNativePlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.experimental.plugins.kotlinNativeSourceSets
|
||||
import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile
|
||||
import org.jetbrains.kotlin.gradle.plugin.model.KonanToolingModelBuilder
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
@@ -406,8 +408,8 @@ class ExperimentalPluginTests {
|
||||
@Test
|
||||
fun `Plugin should not create compilation tasks for targets unsupported by the current host`() =
|
||||
withProject {
|
||||
val hosts = arrayOf("macos_x64", "linux_x64", "mingw_x64")
|
||||
components.withType(KotlinNativeMainComponent::class.java).getByName("main").target(*hosts)
|
||||
val hosts = listOf("macos_x64", "linux_x64", "mingw_x64")
|
||||
components.withType(KotlinNativeMainComponent::class.java).getByName("main").targets = hosts
|
||||
evaluate()
|
||||
hosts.map { HostManager().targetByName(it) }.forEach {
|
||||
val task = tasks.findByName("compileDebug${it.name.capitalize()}KotlinNative")
|
||||
@@ -727,4 +729,89 @@ class ExperimentalPluginTests {
|
||||
output.contains("Transitive call!")
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Plugin should support the konan tooling model`() {
|
||||
withProject {
|
||||
val hostName = HostManager.hostName
|
||||
val mainSrcDirs = listOf("src/main/kotlin", "src/other/kotlin").map {
|
||||
file(it).apply { mkdirs() }
|
||||
}
|
||||
val testDir = file("src/test/kotlin").apply { mkdirs() }
|
||||
|
||||
val mainSrcFiles = listOf(
|
||||
"src/main/kotlin/main.kt" to "fun main(args: Array<String>) { foo() }",
|
||||
"src/other/kotlin/foo.kt" to "fun foo() { println(42) }"
|
||||
).map { (name, content) ->
|
||||
project.file(name).apply { createNewFile(); writeText(content) }
|
||||
}
|
||||
val testSrcFile = file("src/test/kotlin/test.kt").apply {
|
||||
createNewFile()
|
||||
writeText("""
|
||||
import kotlin.test.*
|
||||
@Test fun test() { foo() }
|
||||
""".trimIndent())
|
||||
}
|
||||
|
||||
components.withType(KotlinNativeMainComponent::class.java).getByName("main").apply {
|
||||
outputKinds.set(listOf(OutputKind.KLIBRARY, OutputKind.EXECUTABLE))
|
||||
targets = listOf(hostName, "wasm32")
|
||||
}
|
||||
kotlinNativeSourceSets.getByName("main").kotlin.srcDirs(*mainSrcDirs.toTypedArray())
|
||||
|
||||
evaluate()
|
||||
|
||||
val model = KonanToolingModelBuilder.buildAll("konan", this)
|
||||
val mainArtifacts = model.artifacts.filterNot { it.name.toLowerCase().contains("test") }
|
||||
val testArtifacts = model.artifacts.filter { it.name.toLowerCase().contains("test") }
|
||||
|
||||
mainArtifacts.forEach {
|
||||
assertEquals(mainSrcDirs.toSet(), it.srcDirs.toSet())
|
||||
assertEquals(mainSrcFiles.toSet(), it.srcFiles.toSet())
|
||||
}
|
||||
testArtifacts.forEach {
|
||||
assertEquals(setOf(testDir), it.srcDirs.toSet())
|
||||
assertEquals(setOf(testSrcFile) + mainSrcFiles.toSet(), it.srcFiles.toSet())
|
||||
}
|
||||
|
||||
val nameToArtifact = model.artifacts.map { it.name to it }.toMap()
|
||||
|
||||
val buildTypes = listOf("debug", "release")
|
||||
val kinds = listOf(OutputKind.EXECUTABLE, OutputKind.KLIBRARY)
|
||||
val targets = listOf(HostManager.host, KonanTarget.WASM32)
|
||||
|
||||
// Production binaries
|
||||
buildTypes.forEach { buildType ->
|
||||
kinds.forEach { kind ->
|
||||
targets.forEach { target ->
|
||||
val suffix = "${buildType.capitalize()}${kind.name.toLowerCase().capitalize()}${target.name.capitalize()}"
|
||||
val artifact = nameToArtifact.getValue("main$suffix")
|
||||
assertEquals(target.name, artifact.targetPlatform)
|
||||
assertEquals(kind.compilerOutputKind, artifact.type)
|
||||
assertEquals("compile${suffix}KotlinNative", artifact.buildTaskName)
|
||||
|
||||
val outputRoot = if (kind == OutputKind.EXECUTABLE) "exe" else "lib"
|
||||
val outputFile = file(
|
||||
"build/$outputRoot/main/$buildType/${kind.name.toLowerCase()}/${target.name}/" +
|
||||
"testProject${kind.compilerOutputKind.suffix(target)}"
|
||||
)
|
||||
assertEquals(outputFile, artifact.file)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Test binaries
|
||||
targets.forEach { target ->
|
||||
val suffix = "Debug${target.name.capitalize()}"
|
||||
val artifact = nameToArtifact.getValue("test$suffix")
|
||||
assertEquals(target.name, artifact.targetPlatform)
|
||||
assertEquals(CompilerOutputKind.PROGRAM, artifact.type)
|
||||
assertEquals("compileTest${suffix}KotlinNative", artifact.buildTaskName)
|
||||
assertEquals(
|
||||
file("build/test-exe/test/debug/${target.name}/test${CompilerOutputKind.PROGRAM.suffix(target)}"),
|
||||
artifact.file
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user