[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
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
|
||||||
// TODO: implement ComponentWithObjectFiles when we build klibs as objects
|
// TODO: implement ComponentWithObjectFiles when we build klibs as objects
|
||||||
interface KotlinNativeBinary: ComponentWithDependencies, BuildableComponent {
|
interface KotlinNativeBinary : ComponentWithDependencies, BuildableComponent, ComponentWithOutputs {
|
||||||
|
|
||||||
/** A component this binary belongs to. */
|
/** A component this binary belongs to. */
|
||||||
val component: KotlinNativeComponent
|
val component: KotlinNativeComponent
|
||||||
@@ -86,7 +86,6 @@ interface KotlinNativeBinary: ComponentWithDependencies, BuildableComponent {
|
|||||||
*/
|
*/
|
||||||
// TODO: Consider implementing ComponentWithExecutable and ComponentWithInstallation.
|
// TODO: Consider implementing ComponentWithExecutable and ComponentWithInstallation.
|
||||||
interface KotlinNativeExecutable : KotlinNativeBinary,
|
interface KotlinNativeExecutable : KotlinNativeBinary,
|
||||||
ComponentWithOutputs,
|
|
||||||
PublishableComponent,
|
PublishableComponent,
|
||||||
ConfigurableComponentWithRuntimeUsage
|
ConfigurableComponentWithRuntimeUsage
|
||||||
|
|
||||||
@@ -95,29 +94,26 @@ interface KotlinNativeExecutable : KotlinNativeBinary,
|
|||||||
*/
|
*/
|
||||||
// TODO: Consider implementing ComponentWithLinkFile.
|
// TODO: Consider implementing ComponentWithLinkFile.
|
||||||
interface KotlinNativeLibrary : KotlinNativeBinary,
|
interface KotlinNativeLibrary : KotlinNativeBinary,
|
||||||
ComponentWithOutputs,
|
|
||||||
PublishableComponent,
|
PublishableComponent,
|
||||||
ConfigurableComponentWithLinkUsage
|
ConfigurableComponentWithLinkUsage
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an Objective C framework compiled from Kotlin/Native sources.
|
* 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.
|
* A shared library compiled from Kotlin/Native sources.
|
||||||
*/
|
*/
|
||||||
interface KotlinNativeDynamic : KotlinNativeBinary, ComponentWithOutputs
|
interface KotlinNativeDynamic : KotlinNativeBinary
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A static library compiled from Kotlin/Native sources.
|
* A static library compiled from Kotlin/Native sources.
|
||||||
*/
|
*/
|
||||||
interface KotlinNativeStatic : KotlinNativeBinary, ComponentWithOutputs
|
interface KotlinNativeStatic : KotlinNativeBinary
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a test executable.
|
* Represents a test executable.
|
||||||
*/
|
*/
|
||||||
// TODO: Consider implementing ComponentWithExecutable and ComponentWithInstallation.
|
// TODO: Consider implementing ComponentWithExecutable and ComponentWithInstallation.
|
||||||
interface KotlinNativeTestExecutable : KotlinNativeBinary,
|
interface KotlinNativeTestExecutable : KotlinNativeBinary, TestComponent
|
||||||
ComponentWithOutputs,
|
|
||||||
TestComponent
|
|
||||||
+62
-7
@@ -18,29 +18,84 @@ package org.jetbrains.kotlin.gradle.plugin.model
|
|||||||
|
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.tooling.provider.model.ToolingModelBuilder
|
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.konanArtifactsContainer
|
||||||
import org.jetbrains.kotlin.gradle.plugin.konanExtension
|
import org.jetbrains.kotlin.gradle.plugin.konanExtension
|
||||||
import org.jetbrains.kotlin.gradle.plugin.konanHome
|
import org.jetbrains.kotlin.gradle.plugin.konanHome
|
||||||
import org.jetbrains.kotlin.konan.KonanVersion
|
import org.jetbrains.kotlin.konan.KonanVersion
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
import java.lang.IllegalStateException
|
||||||
|
|
||||||
|
|
||||||
object KonanToolingModelBuilder : ToolingModelBuilder {
|
object KonanToolingModelBuilder : ToolingModelBuilder {
|
||||||
|
|
||||||
override fun canBuild(modelName: String) = KonanModel::class.java.name == modelName
|
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() }
|
val artifacts = project.konanArtifactsContainer.flatten().toList().map { it.toModelArtifact() }
|
||||||
return KonanModelImpl(
|
return KonanModelImpl(
|
||||||
artifacts,
|
artifacts,
|
||||||
project.file(project.konanHome),
|
project.file(project.konanHome),
|
||||||
KonanVersion.CURRENT,
|
KonanVersion.CURRENT,
|
||||||
// TODO: Provide defaults for these versions.
|
// TODO: Provide defaults for these versions.
|
||||||
project.konanExtension.languageVersion,
|
project.konanExtension.languageVersion,
|
||||||
project.konanExtension.apiVersion
|
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(
|
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.KotlinNativeMainComponent
|
||||||
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.OutputKind
|
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.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.experimental.tasks.KotlinNativeCompile
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.model.KonanToolingModelBuilder
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
@@ -406,8 +408,8 @@ class ExperimentalPluginTests {
|
|||||||
@Test
|
@Test
|
||||||
fun `Plugin should not create compilation tasks for targets unsupported by the current host`() =
|
fun `Plugin should not create compilation tasks for targets unsupported by the current host`() =
|
||||||
withProject {
|
withProject {
|
||||||
val hosts = arrayOf("macos_x64", "linux_x64", "mingw_x64")
|
val hosts = listOf("macos_x64", "linux_x64", "mingw_x64")
|
||||||
components.withType(KotlinNativeMainComponent::class.java).getByName("main").target(*hosts)
|
components.withType(KotlinNativeMainComponent::class.java).getByName("main").targets = hosts
|
||||||
evaluate()
|
evaluate()
|
||||||
hosts.map { HostManager().targetByName(it) }.forEach {
|
hosts.map { HostManager().targetByName(it) }.forEach {
|
||||||
val task = tasks.findByName("compileDebug${it.name.capitalize()}KotlinNative")
|
val task = tasks.findByName("compileDebug${it.name.capitalize()}KotlinNative")
|
||||||
@@ -727,4 +729,89 @@ class ExperimentalPluginTests {
|
|||||||
output.contains("Transitive call!")
|
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