Improved Gradle plugin.

- Added conventional project structure for sources and def files.
- Fixed bug with konan.home setting, now it has defualt value, which is
download directory.
- Fixed structure of Gradle plugin sources.
- Added debug printing for command line options.
- Added run task.
This commit is contained in:
Alexander Podkhalyuzin
2017-06-08 13:28:06 +03:00
committed by SvyatoslavScherbina
parent 114010bbcd
commit f1fa5327f3
9 changed files with 470 additions and 387 deletions
@@ -1,128 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.*
import java.io.File
// TODO: form groups for tasks
// TODO: Make the task class nested for config with properties accessible for outer users.
open class KonanCompileTask: DefaultTask() {
companion object {
const val COMPILER_MAIN = "org.jetbrains.kotlin.cli.bc.K2NativeKt"
}
val COMPILER_JVM_ARGS: List<String>
get() = listOf("-Dkonan.home=${project.konanHome}", "-Djava.library.path=${project.konanHome}/konan/nativelib")
val COMPILER_CLASSPATH: String
get() = "${project.konanHome}/konan/lib/"
// Output artifact --------------------------------------------------------
lateinit var artifactName: String
@OutputDirectory
lateinit var outputDir: File
internal set
internal fun initialize(artifactName: String) {
dependsOn(project.konanCompilerDownloadTask)
this.artifactName = artifactName
outputDir = project.file("${project.konanCompilerOutputDir}/$artifactName")
}
private val artifactSuffix = mapOf("program" to "kexe", "library" to "klib", "bitcode" to "bc")
val artifactPath: String
get() = "${outputDir.absolutePath}/$artifactName.${artifactSuffix[produce]}"
// Other compilation parameters -------------------------------------------
@InputFiles val inputFiles = mutableSetOf<FileCollection>()
@InputFiles val libraries = mutableSetOf<FileCollection>()
@InputFiles val nativeLibraries = mutableSetOf<FileCollection>()
@Input var produce = "program"
internal set
@Input var linkerOpts = mutableListOf<String>()
internal set
@Input var noStdLib = false
internal set
@Input var noMain = false
internal set
@Input var enableOptimization = false
internal set
@Input var enableAssertions = false
internal set
@Optional @Input var target : String? = null
internal set
@Optional @Input var languageVersion : String? = null
internal set
@Optional @Input var apiVersion : String? = null
internal set
// TODO: Is there a better way to rerun tasks when the compiler version changes?
@Input val konanVersion = project.konanVersion
// Task action ------------------------------------------------------------
protected fun buildArgs() = mutableListOf<String>().apply {
addArg("-output", artifactPath)
addFileArgs("-library", libraries)
addFileArgs("-nativelibrary", nativeLibraries)
addArg("-produce", produce)
addListArg("-linkerOpts", linkerOpts)
addArgIfNotNull("-target", target)
addArgIfNotNull("-language-version", languageVersion)
addArgIfNotNull("-api-version", apiVersion)
addKey("-nostdlib", noStdLib)
addKey("-nomain", noMain)
addKey("-opt", enableOptimization)
addKey("-ea", enableAssertions)
inputFiles.forEach {
it.files.filter { it.name.endsWith(".kt") }.mapTo(this) { it.canonicalPath }
}
}
@TaskAction
fun compile() {
project.file(outputDir).mkdirs()
// TODO: Use compiler service.
project.javaexec {
with(it) {
main = COMPILER_MAIN
classpath = project.fileTree(COMPILER_CLASSPATH).apply { include("*.jar") }
jvmArgs(COMPILER_JVM_ARGS)
args(buildArgs().apply { logger.info("Compiler args: ${this.joinToString(separator = " ")}") })
}
}
}
}
@@ -1,116 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Named
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.project.ProjectInternal
/**
* What we can:
*
* konanInterop {
* foo {
* defFile <def-file>
* pkg <package with stubs>
* target <target: linux/macbook/iphone/iphone_sim>
* compilerOpts <Options for native stubs compilation>
* linkerOpts <Options for native stubs >
* headers <headers to process>
* includeDirs <directories where headers are located>
* linkFiles <files which will be linked with native stubs>
* }
*
* // TODO: add configuration for konan compiler
* }
*/
open class KonanInteropConfig(
val configName: String,
val project: ProjectInternal
): Named {
override fun getName() = configName
// Child tasks ------------------------------------------------------------
// Task to process the library and generate stubs
val generateStubsTask: KonanInteropTask = project.tasks.create(
"gen${name.capitalize()}InteropStubs",
KonanInteropTask::class.java
)
// Config and task to compile *.kt stubs in a *.bc library
internal val compileStubsConfig = KonanCompilerConfig("${name}InteropStubs", project, "compile").apply {
compilationTask.dependsOn(generateStubsTask)
outputDir("${project.konanInteropCompiledStubsDir}/$name")
produce("library")
inputFiles(project.fileTree(generateStubsTask.stubsDir).apply { builtBy(generateStubsTask) })
}
val compileStubsTask = compileStubsConfig.compilationTask
// DSL methods ------------------------------------------------------------
fun defFile(file: Any) = with(generateStubsTask) {
defFile = project.file(file)
}
fun pkg(value: String) = with(generateStubsTask) {
pkg = value
}
fun target(value: String) = with(generateStubsTask) {
generateStubsTask.target = value
compileStubsTask.target = value
}
fun compilerOpts(vararg values: String) = with(generateStubsTask) {
compilerOpts.addAll(values)
}
fun header(file: Any) = headers(file)
fun headers(vararg files: Any) = with(generateStubsTask) {
headers.add(project.files(files))
}
fun headers(files: FileCollection) = with(generateStubsTask) {
headers.add(files)
}
fun includeDirs(vararg values: String) = with(generateStubsTask) {
compilerOpts.addAll(values.map { "-I$it" })
}
fun linker(value: String) = with(generateStubsTask) {
linker = value
}
fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
fun linkerOpts(values: List<String>) = with(generateStubsTask) {
linkerOpts.addAll(values)
}
fun link(vararg files: Any) = with(generateStubsTask) {
linkFiles.add(project.files(files))
}
fun link(files: FileCollection) = with(generateStubsTask) {
linkFiles.add(files)
}
}
@@ -1,113 +0,0 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.Task
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.*
import java.io.File
open class KonanInteropTask: DefaultTask() {
internal companion object {
const val INTEROP_MAIN = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
}
init {
dependsOn(project.konanCompilerDownloadTask)
}
internal val INTEROP_JVM_ARGS: List<String>
get() = listOf("-Dkonan.home=${project.konanHome}", "-Djava.library.path=${project.konanHome}/konan/nativelib")
internal val INTEROP_CLASSPATH: String
get() = "${project.konanHome}/konan/lib/"
// Output directories -----------------------------------------------------
/** Directory with autogenerated interop stubs (*.kt) */
@OutputDirectory
val stubsDir = project.file("${project.konanInteropStubsOutputDir}/$name")
/** Directory with library bitcodes (*.bc) */
@OutputDirectory
val libsDir = project.file("${project.konanInteropLibsOutputDir}/$name")
// Interop stub generator parameters -------------------------------------
@Optional @InputFile var defFile: File? = null
internal set
@Optional @Input var target: String? = null
internal set
@Optional @Input var pkg: String? = null
internal set
@Optional @Input var linker: String? = null
internal set
@Input val compilerOpts = mutableListOf<String>()
@Input val linkerOpts = mutableListOf<String>()
// TODO: Check if we can use only one FileCollection instead of set.
@InputFiles val headers = mutableSetOf<FileCollection>()
@InputFiles val linkFiles = mutableSetOf<FileCollection>()
@Input val konanVersion = project.konanVersion
@TaskAction
fun exec() {
project.javaexec {
with(it) {
main = INTEROP_MAIN
classpath = project.fileTree(INTEROP_CLASSPATH).apply { include("*.jar") }
jvmArgs(INTEROP_JVM_ARGS)
environment("LIBCLANG_DISABLE_CRASH_RECOVERY", "1")
args(buildArgs().apply { logger.info("Interop args: ${this.joinToString(separator = " ")}") })
}
}
}
protected fun buildArgs() = mutableListOf<String>().apply {
addArg("-properties", "${project.konanHome}/konan/konan.properties")
addArg("-flavor", "native")
addArg("-generated", stubsDir.canonicalPath)
addArg("-natives", libsDir.canonicalPath)
addArgIfNotNull("-target", target)
addArgIfNotNull("-def", defFile?.canonicalPath)
addArgIfNotNull("-pkg", pkg)
addArgIfNotNull("-linker", linker)
addFileArgs("-h", headers)
compilerOpts.forEach {
addArg("-copt", it)
}
val linkerOpts = mutableListOf<String>().apply { addAll(linkerOpts) }
linkFiles.forEach {
linkerOpts.addAll(it.files.map { it.canonicalPath })
}
linkerOpts.forEach {
addArg("-lopt", it)
}
}
}
@@ -16,9 +16,11 @@
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.Named
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.tasks.*
import java.io.File
/**
@@ -62,9 +64,121 @@ import java.io.File
*/
// TODO: form groups for tasks
// TODO: Make the task class nested for config with properties accessible for outer users.
open class KonanCompileTask: DefaultTask() {
companion object {
const val COMPILER_MAIN = "org.jetbrains.kotlin.cli.bc.K2NativeKt"
}
val COMPILER_JVM_ARGS: List<String>
get() = listOf("-Dkonan.home=${project.konanHome}", "-Djava.library.path=${project.konanHome}/konan/nativelib")
val COMPILER_CLASSPATH: String
get() = "${project.konanHome}/konan/lib/"
// Output artifact --------------------------------------------------------
internal lateinit var artifactName: String
@OutputDirectory
lateinit var outputDir: File
internal set
internal fun init(artifactName: String) {
dependsOn(project.konanCompilerDownloadTask)
this.artifactName = artifactName
outputDir = project.file("${project.konanCompilerOutputDir}/$artifactName")
}
private val artifactSuffix = mapOf("program" to "kexe", "library" to "klib", "bitcode" to "bc")
val artifactPath: String
get() = "${outputDir.absolutePath}/$artifactName.${artifactSuffix[produce]}"
// Other compilation parameters -------------------------------------------
@InputFiles val inputFiles = mutableSetOf<FileCollection>()
@InputFiles val libraries = mutableSetOf<FileCollection>()
@InputFiles val nativeLibraries = mutableSetOf<FileCollection>()
@Input var produce = "program"
internal set
@Input var linkerOpts = mutableListOf<String>()
internal set
@Input var noStdLib = false
internal set
@Input var noMain = false
internal set
@Input var enableOptimization = false
internal set
@Input var enableAssertions = false
internal set
@Optional @Input var target : String? = null
internal set
@Optional @Input var languageVersion : String? = null
internal set
@Optional @Input var apiVersion : String? = null
internal set
@Input var dumpParameters: Boolean = false
// TODO: Is there a better way to rerun tasks when the compiler version changes?
@Input val konanVersion = project.konanVersion
// Task action ------------------------------------------------------------
protected fun buildArgs() = mutableListOf<String>().apply {
addArg("-output", artifactPath)
addFileArgs("-library", libraries)
addFileArgs("-nativelibrary", nativeLibraries)
addArg("-produce", produce)
addListArg("-linkerOpts", linkerOpts)
addArgIfNotNull("-target", target)
addArgIfNotNull("-language-version", languageVersion)
addArgIfNotNull("-api-version", apiVersion)
addKey("-nostdlib", noStdLib)
addKey("-nomain", noMain)
addKey("-opt", enableOptimization)
addKey("-ea", enableAssertions)
(if (inputFiles.isEmpty()) {
project.fileTree("${project.projectDir.canonicalPath}/src/main/kotlin")
} else {
inputFiles.flatMap { it.files }
}).filter { it.name.endsWith(".kt") }.mapTo(this) { it.canonicalPath }
}
@TaskAction
fun compile() {
project.file(outputDir).mkdirs()
if (dumpParameters) dumpProperties(this@KonanCompileTask)
// TODO: Use compiler service.
project.javaexec {
with(it) {
main = COMPILER_MAIN
classpath = project.fileTree(COMPILER_CLASSPATH).apply { include("*.jar") }
jvmArgs(COMPILER_JVM_ARGS)
args(buildArgs().apply { logger.info("Compiler args: ${this.joinToString(separator = " ")}") })
}
}
}
}
// TODO: check debug outputs
// TODO: Use +=/-= syntax for libraries and inputFiles
open class KonanCompilerConfig(
open class KonanCompileConfig(
val configName: String,
val project: ProjectInternal,
taskNamePrefix: String = "compileKonan"): Named {
@@ -74,12 +188,12 @@ open class KonanCompilerConfig(
val compilationTask: KonanCompileTask = project.tasks.create(
"$taskNamePrefix${configName.capitalize()}",
KonanCompileTask::class.java
) { it.initialize(this@KonanCompilerConfig.name) }
) { it.init(this@KonanCompileConfig.name) }
// DSL methods --------------------------------------------------
// TODO: Check if we copied all data or not
fun extendsFrom(anotherConfig: KonanCompilerConfig) = with(compilationTask) {
fun extendsFrom(anotherConfig: KonanCompileConfig) = with(compilationTask) {
val anotherTask = anotherConfig.compilationTask
outputDir(anotherTask.outputDir.absolutePath)
@@ -97,7 +211,7 @@ open class KonanCompilerConfig(
if (anotherTask.enableAssertions) enableAssertions()
}
fun useInterop(interopConfig: KonanInteropConfig) {
private fun useInteropFromConfig(interopConfig: KonanInteropConfig) {
val generateStubsTask = interopConfig.generateStubsTask
val compileStubsTask = interopConfig.compileStubsTask
@@ -111,7 +225,14 @@ open class KonanCompilerConfig(
include("**/*.bc")
})
}
fun useInterop(interop: String) = useInterop(project.konanInteropContainer.getByName(interop))
fun useInterops(interops: ArrayList<String>) {
interops.forEach { useInteropFromConfig(project.konanInteropContainer.getByName(it)) }
}
fun useInterop(interop: String) {
useInteropFromConfig(project.konanInteropContainer.getByName(interop))
}
// DSL. Input/output files
@@ -185,4 +306,8 @@ open class KonanCompilerConfig(
fun enableAssertions() = with(compilationTask) {
enableAssertions = true
}
fun dumpParameters(value: Boolean) = with(compilationTask) {
dumpParameters = value
}
}
@@ -22,18 +22,19 @@ import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.konan.DependencyDownloader
import java.io.File
open class CompilerDownloadTask: DefaultTask() {
open class KonanCompilerDownloadTask : DefaultTask() {
internal companion object {
internal const val DOWNLOAD_URL = "http://download.jetbrains.com/kotlin/native"
private val KONAN_PARENT_DIR = "${System.getProperty("user.home")}/.konan"
internal val KONAN_PARENT_DIR = "${System.getProperty("user.home")}/.konan"
internal fun simpleOsName(): String {
val osName = System.getProperty("os.name")
return when (osName) {
"Mac OS X" -> "macos"
"Linux" -> "linux"
return when {
osName == "Mac OS X" -> "macos"
osName == "Linux" -> "linux"
osName.startsWith("Windows") -> "windows"
else -> throw IllegalStateException("Unsupported platform: $osName")
}
}
@@ -47,10 +48,9 @@ open class CompilerDownloadTask: DefaultTask() {
return
}
try {
val konanCompiler = "kotlin-native-${simpleOsName()}-${project.konanVersion}"
val konanCompiler = project.konanCompilerName()
logger.info("Downloading Kotlin Native compiler from $DOWNLOAD_URL/$konanCompiler into $KONAN_PARENT_DIR")
DependencyDownloader(File(KONAN_PARENT_DIR), DOWNLOAD_URL, listOf(konanCompiler)).run()
project.extensions.extraProperties.set(KonanPlugin.KONAN_HOME_PROPERTY_NAME, "$KONAN_PARENT_DIR/$konanCompiler")
} catch (e: RuntimeException) {
throw GradleScriptException("Cannot download Kotlin Native compiler", e)
}
@@ -0,0 +1,222 @@
/*
* Copyright 2010-2017 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.Named
import org.gradle.api.file.FileCollection
import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.tasks.*
import java.io.File
/**
* What we can:
*
* konanInterop {
* pkgName {
* defFile <def-file>
* pkg <package with stubs>
* target <target: linux/macbook/iphone/iphone_sim>
* compilerOpts <Options for native stubs compilation>
* linkerOpts <Options for native stubs >
* headers <headers to process>
* includeDirs <directories where headers are located>
* linkFiles <files which will be linked with native stubs>
* dumpParameters <Option to print parameters of task before execution>
* }
*
* // TODO: add configuration for konan compiler
* }
*/
open class KonanInteropTask: DefaultTask() {
internal companion object {
const val INTEROP_MAIN = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
}
internal fun init(libName: String) {
dependsOn(project.konanCompilerDownloadTask)
this.libName = libName
}
internal val INTEROP_JVM_ARGS: List<String>
get() = listOf("-Dkonan.home=${project.konanHome}", "-Djava.library.path=${project.konanHome}/konan/nativelib")
internal val INTEROP_CLASSPATH: String
get() = "${project.konanHome}/konan/lib/"
internal val C_INTEROP_DIR_PATH: String
get() = "${project.projectDir}/src/main/c_interop"
// Output directories -----------------------------------------------------
/** Directory with autogenerated interop stubs (*.kt) */
@OutputDirectory
val stubsDir = project.file("${project.konanInteropStubsOutputDir}/$name")
/** Directory with library bitcodes (*.bc) */
@OutputDirectory
val libsDir = project.file("${project.konanInteropLibsOutputDir}/$name")
// Interop stub generator parameters -------------------------------------
@Optional @InputFile var defFile: File? = null
internal set
@Optional @Input var target: String? = null
internal set
@Optional @Input var pkg: String? = null
internal set
@Input lateinit var libName: String
@Optional @Input var linker: String? = null
internal set
@Input var dumpParameters: Boolean = false
@Input val compilerOpts = mutableListOf<String>()
@Input val linkerOpts = mutableListOf<String>()
// TODO: Check if we can use only one FileCollection instead of set.
@InputFiles val headers = mutableSetOf<FileCollection>()
@InputFiles val linkFiles = mutableSetOf<FileCollection>()
@Input val konanVersion = project.konanVersion
@TaskAction
fun exec() {
if (dumpParameters) dumpProperties(this@KonanInteropTask)
project.javaexec {
with(it) {
main = INTEROP_MAIN
classpath = project.fileTree(INTEROP_CLASSPATH).apply { include("*.jar") }
jvmArgs(INTEROP_JVM_ARGS)
environment("LIBCLANG_DISABLE_CRASH_RECOVERY", "1")
args(buildArgs().apply { logger.info("Interop args: ${this.joinToString(separator = " ")}") })
}
}
}
protected fun buildArgs() = mutableListOf<String>().apply {
addArg("-properties", "${project.konanHome}/konan/konan.properties")
addArg("-flavor", "native")
addArg("-generated", stubsDir.canonicalPath)
addArg("-natives", libsDir.canonicalPath)
addArgIfNotNull("-target", target)
val defFilePath = defFile?.canonicalPath ?:
project.file("$C_INTEROP_DIR_PATH/$libName.def").takeIf { it.exists() }?.canonicalPath
addArgIfNotNull("-def", defFilePath)
addArg("-pkg", pkg ?: libName)
addArgIfNotNull("-linker", linker)
addFileArgs("-h", headers)
compilerOpts.forEach {
addArg("-copt", it)
}
val linkerOpts = mutableListOf<String>().apply { addAll(linkerOpts) }
linkFiles.forEach {
linkerOpts.addAll(it.files.map { it.canonicalPath })
}
linkerOpts.forEach {
addArg("-lopt", it)
}
}
}
open class KonanInteropConfig(
val configName: String,
val project: ProjectInternal
): Named {
override fun getName() = configName
// Child tasks ------------------------------------------------------------
// Task to process the library and generate stubs
val generateStubsTask: KonanInteropTask = project.tasks.create(
"gen${name.capitalize()}InteropStubs",
KonanInteropTask::class.java
) { it.init(name) }
// Config and task to compile *.kt stubs in a *.bc library
internal val compileStubsConfig = KonanCompileConfig("${name}InteropStubs", project, "compile").apply {
compilationTask.dependsOn(generateStubsTask)
outputDir("${project.konanInteropCompiledStubsDir}/$name")
produce("library")
inputFiles(project.fileTree(generateStubsTask.stubsDir).apply { builtBy(generateStubsTask) })
}
val compileStubsTask = compileStubsConfig.compilationTask
// DSL methods ------------------------------------------------------------
fun defFile(file: Any) = with(generateStubsTask) {
defFile = project.file(file)
}
fun pkg(value: String) = with(generateStubsTask) {
pkg = value
}
fun target(value: String) = with(generateStubsTask) {
generateStubsTask.target = value
compileStubsTask.target = value
}
fun compilerOpts(vararg values: String) = with(generateStubsTask) {
compilerOpts.addAll(values)
}
fun header(file: Any) = headers(file)
fun headers(vararg files: Any) = with(generateStubsTask) {
headers.add(project.files(files))
}
fun headers(files: FileCollection) = with(generateStubsTask) {
headers.add(files)
}
fun includeDirs(vararg values: String) = with(generateStubsTask) {
compilerOpts.addAll(values.map { "-I$it" })
}
fun linker(value: String) = with(generateStubsTask) {
linker = value
}
fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
fun linkerOpts(values: List<String>) = with(generateStubsTask) {
linkerOpts.addAll(values)
}
fun link(vararg files: Any) = with(generateStubsTask) {
linkFiles.add(project.files(files))
}
fun link(files: FileCollection) = with(generateStubsTask) {
linkFiles.add(files)
}
fun dumpParameters(value: Boolean) = with(generateStubsTask) {
dumpParameters = value
compileStubsTask.dumpParameters = value
}
}
@@ -57,27 +57,38 @@ internal val Project.konanCompilerDownloadTask get() = tasks.getByName(KonanPlu
internal val Project.konanVersion
get() = findProperty(KonanPlugin.KONAN_VERSION_PROPERTY_NAME) as String? ?: KonanPlugin.DEFAULT_KONAN_VERSION
internal val Project.supportedCompileTasks: TaskCollection<KonanCompileTask>
get() = project.tasks.withType(KonanCompileTask::class.java).matching { it.target?.isSupported() ?: true }
internal val Project.supportedInteropTasks: TaskCollection<KonanInteropTask>
get() = project.tasks.withType(KonanInteropTask::class.java).matching { it.target?.isSupported() ?: true }
private fun String.isSupported(): Boolean {
val os = CompilerDownloadTask.simpleOsName()
return when (os) {
"macos" -> this == "macbook" || this == "iphone"
"linux" -> this == "linux" || this == "raspberrypi"
else -> false
internal fun Project.isTargetSupported(target: String?): Boolean {
val targets = extensions.extraProperties.get(KonanPlugin.KONAN_BUILD_TARGETS).toString().trim().split(' ')
if (targets.contains("all")) {
return target?.isSupported() ?: true
} else {
return target == null || targets.contains(target)
}
}
class KonanArtifactsContainer(val project: ProjectInternal): AbstractNamedDomainObjectContainer<KonanCompilerConfig>(
KonanCompilerConfig::class.java,
internal val Project.supportedCompileTasks: TaskCollection<KonanCompileTask>
get() {
return project.tasks.withType(KonanCompileTask::class.java).matching { isTargetSupported(it.target) }
}
internal val Project.supportedInteropTasks: TaskCollection<KonanInteropTask>
get() {
return project.tasks.withType(KonanInteropTask::class.java).matching { isTargetSupported(it.target) }
}
internal fun Project.konanCompilerName(): String =
"kotlin-native-${KonanCompilerDownloadTask.simpleOsName()}-${this.konanVersion}"
internal fun Project.konanCompilerDownloadDir(): String =
KonanCompilerDownloadTask.KONAN_PARENT_DIR + "/" + project.konanCompilerName()
class KonanArtifactsContainer(val project: ProjectInternal): AbstractNamedDomainObjectContainer<KonanCompileConfig>(
KonanCompileConfig::class.java,
project.gradle.services.get(Instantiator::class.java)) {
override fun doCreate(name: String): KonanCompilerConfig =
KonanCompilerConfig(name, project)
override fun doCreate(name: String): KonanCompileConfig =
KonanCompileConfig(name, project)
}
class KonanInteropContainer(val project: ProjectInternal): AbstractNamedDomainObjectContainer<KonanInteropConfig>(
@@ -125,6 +136,58 @@ internal fun MutableList<String>.addListArg(parameter: String, values: List<Stri
}
}
internal fun dumpProperties(task: Task) {
when (task) {
is KonanCompileTask -> {
println()
println("Compilation task: ${task.name}")
println("outputDir : ${task.outputDir}")
println("artifactPath : ${task.artifactPath}")
println("inputFiles : ${task.inputFiles.joinToString(prefix = "[", separator = ", ", postfix = "]")}")
println("libraries : ${task.libraries}")
println("nativeLibraries : ${task.nativeLibraries}")
println("linkerOpts : ${task.linkerOpts}")
println("noStdLib : ${task.noStdLib}")
println("noMain : ${task.noMain}")
println("enableOptimization : ${task.enableOptimization}")
println("enableAssertions : ${task.enableAssertions}")
println("target : ${task.target}")
println("languageVersion : ${task.languageVersion}")
println("apiVersion : ${task.apiVersion}")
println()
}
is KonanInteropTask -> {
println()
println("Stub generation task: ${task.name}")
println("stubsDir : ${task.stubsDir}")
println("libsDir : ${task.libsDir}")
println("defFile : ${task.defFile}")
println("target : ${task.target}")
println("pkg : ${task.pkg}")
println("linker : ${task.linker}")
println("compilerOpts : ${task.compilerOpts}")
println("linkerOpts : ${task.linkerOpts}")
println("headers : ${task.headers.joinToString(prefix = "[", separator = ", ", postfix = "]")}")
println("linkFiles : ${task.linkFiles}")
println()
}
else -> {
println("Unsupported task.")
}
}
}
private fun String.isSupported(): Boolean {
val os = KonanCompilerDownloadTask.simpleOsName()
return when (os) {
"macos" -> this == "macbook" || this == "iphone"
"linux" -> this == "linux" || this == "raspberrypi"
"windows" -> this == "mingw"
else -> false
}
}
class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderRegistry)
: Plugin<ProjectInternal> {
@@ -135,6 +198,7 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
internal const val KONAN_HOME_PROPERTY_NAME = "konan.home"
internal const val KONAN_VERSION_PROPERTY_NAME = "konan.version"
internal const val KONAN_BUILD_TARGETS = "konan.build.targets"
internal const val DEFAULT_KONAN_VERSION = "0.2"
}
@@ -157,15 +221,44 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
override fun apply(project: ProjectInternal?) {
if (project == null) { return }
registry.register(KonanToolingModelBuilder)
project.tasks.create(KONAN_DOWNLOAD_TASK_NAME, CompilerDownloadTask::class.java)
project.tasks.create(KONAN_DOWNLOAD_TASK_NAME, KonanCompilerDownloadTask::class.java)
project.extensions.add(COMPILER_EXTENSION_NAME, KonanArtifactsContainer(project))
project.extensions.add(INTEROP_EXTENSION_NAME, KonanInteropContainer(project))
if (!project.extensions.extraProperties.has(KonanPlugin.KONAN_HOME_PROPERTY_NAME)) {
project.extensions.extraProperties.set(KonanPlugin.KONAN_HOME_PROPERTY_NAME, project.konanCompilerDownloadDir())
}
val hostTarget = when (KonanCompilerDownloadTask.simpleOsName()) {
"macos" -> "macbook"
"linux" -> "linux"
"windows" -> "mingw"
else -> throw IllegalStateException("Unsupported platform")
}
if (!project.extensions.extraProperties.has(KonanPlugin.KONAN_BUILD_TARGETS)) {
project.extensions.extraProperties.set(KonanPlugin.KONAN_BUILD_TARGETS, hostTarget)
}
getTask(project, "clean").doLast {
project.delete(project.konanBuildRoot)
}
getTask(project, "build").apply {
dependsOn(project.supportedCompileTasks)
dependsOn(project.supportedInteropTasks)
}
getTask(project, "run").apply {
dependsOn(getTask(project, "build"))
doLast {
for (task in project.tasks.withType(KonanCompileTask::class.java).matching { it.target?.equals(hostTarget) ?: true}) {
if (task.artifactPath.endsWith("kexe")) {
project.exec {
with(it) {
commandLine(task.artifactPath)
if (project.extensions.extraProperties.has("runArgs")) {
args(project.extensions.extraProperties.get("runArgs").toString().split(' '))
}
}
}
}
}
}
}
}