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:
committed by
SvyatoslavScherbina
parent
114010bbcd
commit
f1fa5327f3
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+130
-5
@@ -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
|
||||
}
|
||||
}
|
||||
+7
-7
@@ -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)
|
||||
}
|
||||
+222
@@ -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
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+111
-18
@@ -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(' '))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user