Basic native support in kotlin-multiplatform (#1811)
* Add dependency on KN shared in gradle-plugin
* Basic support for Kotlin/Native:
* Target presets
* Compilation into a klib
* Compilation into native binraies: framework and executable
* Basic dependencies between projects
* No jars in native publications
* Replace '-' with '_' in framework names
* Escape quotes in native command lines on Windows
* Move targets from Kotlin/Native repo
* Download KN compiler using Gradle's mechanisms
* Support source set dependencies in native
This commit is contained in:
@@ -0,0 +1,21 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
description = "Kotlin/Native utils"
|
||||
|
||||
jvmTarget = "1.6"
|
||||
|
||||
dependencies {
|
||||
compile(projectDist(":kotlin-stdlib"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" {}
|
||||
}
|
||||
|
||||
standardPublicJars()
|
||||
|
||||
publish()
|
||||
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan
|
||||
|
||||
import java.io.Serializable
|
||||
|
||||
interface KonanVersion : Serializable {
|
||||
val meta: MetaVersion
|
||||
val major: Int
|
||||
val minor: Int
|
||||
val maintenance: Int
|
||||
val build: Int
|
||||
|
||||
fun toString(showMeta: Boolean, showBuild: Boolean): String
|
||||
|
||||
companion object
|
||||
}
|
||||
|
||||
data class KonanVersionImpl(
|
||||
override val meta: MetaVersion = MetaVersion.DEV,
|
||||
override val major: Int,
|
||||
override val minor: Int,
|
||||
override val maintenance: Int,
|
||||
override val build: Int = -1
|
||||
) : KonanVersion {
|
||||
|
||||
override fun toString(showMeta: Boolean, showBuild: Boolean) = buildString {
|
||||
append(major)
|
||||
append('.')
|
||||
append(minor)
|
||||
if (maintenance != 0) {
|
||||
append('.')
|
||||
append(maintenance)
|
||||
}
|
||||
if (showMeta) {
|
||||
append('-')
|
||||
append(meta.metaString)
|
||||
}
|
||||
if (showBuild && build != -1) {
|
||||
append('-')
|
||||
append(build)
|
||||
}
|
||||
}
|
||||
|
||||
private val isRelease: Boolean
|
||||
get() = meta == MetaVersion.RELEASE
|
||||
|
||||
private val versionString by lazy { toString(!isRelease, !isRelease) }
|
||||
|
||||
override fun toString() = versionString
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan
|
||||
|
||||
/**
|
||||
* https://en.wikipedia.org/wiki/Software_versioning
|
||||
* scheme major.minor[.build[.revision]].
|
||||
*/
|
||||
|
||||
enum class MetaVersion(val metaString: String) {
|
||||
DEV("dev"),
|
||||
EAP("eap"),
|
||||
ALPHA("alpha"),
|
||||
BETA("beta"),
|
||||
RC1("rc1"),
|
||||
RC2("rc2"),
|
||||
RELEASE("release")
|
||||
}
|
||||
@@ -0,0 +1,279 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.target
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||
import org.jetbrains.kotlin.konan.util.Named
|
||||
|
||||
enum class Family(val exeSuffix:String, val dynamicPrefix: String, val dynamicSuffix: String,
|
||||
val staticPrefix: String, val staticSuffix: String) {
|
||||
OSX ("kexe", "lib", "dylib", "lib", "a"),
|
||||
IOS ("kexe", "lib", "dylib", "lib", "a"),
|
||||
LINUX ("kexe", "lib", "so" , "lib", "a"),
|
||||
MINGW ("exe" , "" , "dll" , "lib", "a"),
|
||||
ANDROID ("so" , "lib", "so" , "lib", "a"),
|
||||
WASM ("wasm", "" , "wasm" , "", "wasm"),
|
||||
ZEPHYR ("o" , "lib", "a" , "lib", "a")
|
||||
}
|
||||
|
||||
enum class Architecture(val bitness: Int) {
|
||||
X64(64),
|
||||
ARM64(64),
|
||||
ARM32(32),
|
||||
MIPS32(32),
|
||||
MIPSEL32(32),
|
||||
WASM32(32);
|
||||
}
|
||||
|
||||
sealed class KonanTarget(override val name: String, val family: Family, val architecture: Architecture) : Named {
|
||||
object ANDROID_ARM32 : KonanTarget( "android_arm32", Family.ANDROID, Architecture.ARM32)
|
||||
object ANDROID_ARM64 : KonanTarget( "android_arm64", Family.ANDROID, Architecture.ARM64)
|
||||
object IOS_ARM32 : KonanTarget( "ios_arm32", Family.IOS, Architecture.ARM32)
|
||||
object IOS_ARM64 : KonanTarget( "ios_arm64", Family.IOS, Architecture.ARM64)
|
||||
object IOS_X64 : KonanTarget( "ios_x64", Family.IOS, Architecture.X64)
|
||||
object LINUX_X64 : KonanTarget( "linux_x64", Family.LINUX, Architecture.X64)
|
||||
object MINGW_X64 : KonanTarget( "mingw_x64", Family.MINGW, Architecture.X64)
|
||||
object MACOS_X64 : KonanTarget( "macos_x64", Family.OSX, Architecture.X64)
|
||||
object LINUX_ARM32_HFP :KonanTarget( "linux_arm32_hfp", Family.LINUX, Architecture.ARM32)
|
||||
object LINUX_MIPS32 : KonanTarget( "linux_mips32", Family.LINUX, Architecture.MIPS32)
|
||||
object LINUX_MIPSEL32 : KonanTarget( "linux_mipsel32", Family.LINUX, Architecture.MIPSEL32)
|
||||
object WASM32 : KonanTarget( "wasm32", Family.WASM, Architecture.WASM32)
|
||||
|
||||
// Tunable targets
|
||||
class ZEPHYR(val subName: String, val genericName: String = "zephyr") :
|
||||
KonanTarget("${genericName}_$subName", Family.ZEPHYR, Architecture.ARM32)
|
||||
|
||||
override fun toString() = name
|
||||
}
|
||||
|
||||
fun hostTargetSuffix(host: KonanTarget, target: KonanTarget) =
|
||||
if (target == host) host.name else "${host.name}-${target.name}"
|
||||
|
||||
enum class CompilerOutputKind {
|
||||
PROGRAM {
|
||||
override fun suffix(target: KonanTarget?) = ".${target!!.family.exeSuffix}"
|
||||
},
|
||||
DYNAMIC {
|
||||
override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}"
|
||||
override fun prefix(target: KonanTarget?) = "${target!!.family.dynamicPrefix}"
|
||||
},
|
||||
STATIC {
|
||||
override fun suffix(target: KonanTarget?) = ".${target!!.family.staticSuffix}"
|
||||
override fun prefix(target: KonanTarget?) = "${target!!.family.staticPrefix}"
|
||||
},
|
||||
FRAMEWORK {
|
||||
override fun suffix(target: KonanTarget?): String = ".framework"
|
||||
},
|
||||
LIBRARY {
|
||||
override fun suffix(target: KonanTarget?) = ".klib"
|
||||
},
|
||||
BITCODE {
|
||||
override fun suffix(target: KonanTarget?) = ".bc"
|
||||
};
|
||||
|
||||
abstract fun suffix(target: KonanTarget? = null): String
|
||||
open fun prefix(target: KonanTarget? = null): String = ""
|
||||
}
|
||||
|
||||
interface TargetManager {
|
||||
val target: KonanTarget
|
||||
val targetName : String
|
||||
fun list() : Unit
|
||||
val hostTargetSuffix: String
|
||||
val targetSuffix: String
|
||||
}
|
||||
|
||||
/** */
|
||||
interface SubTargetProvider {
|
||||
fun availableSubTarget(genericName: String): List<String>
|
||||
}
|
||||
|
||||
private class NoSubTargets: SubTargetProvider {
|
||||
override fun availableSubTarget(genericName: String): List<String> = emptyList()
|
||||
}
|
||||
|
||||
private class TargetManagerImpl(val userRequest: String?, val hostManager: HostManager): TargetManager {
|
||||
override val target = determineCurrent()
|
||||
override val targetName
|
||||
get() = target.visibleName
|
||||
|
||||
override fun list() {
|
||||
hostManager.enabled.forEach {
|
||||
val isDefault = if (it == target) "(default)" else ""
|
||||
val aliasList = HostManager.listAliases(it.visibleName).joinToString(", ")
|
||||
println(String.format("%1$-30s%2$-10s%3\$s", "${it.visibleName}:", "$isDefault", aliasList))
|
||||
}
|
||||
}
|
||||
|
||||
fun determineCurrent(): KonanTarget {
|
||||
return if (userRequest == null || userRequest == "host") {
|
||||
HostManager.host
|
||||
} else {
|
||||
val resolvedAlias = HostManager.resolveAlias(userRequest)
|
||||
hostManager.targets[hostManager.known(resolvedAlias)]!!
|
||||
}
|
||||
}
|
||||
|
||||
override val hostTargetSuffix get() = hostTargetSuffix(HostManager.host, target)
|
||||
override val targetSuffix get() = target.name
|
||||
}
|
||||
|
||||
open class HostManager(subtargetProvider: SubTargetProvider = NoSubTargets()) {
|
||||
|
||||
fun targetManager(userRequest: String? = null): TargetManager = TargetManagerImpl(userRequest, this)
|
||||
|
||||
// TODO: need a better way to enumerated predefined targets.
|
||||
private val predefinedTargets = listOf(
|
||||
KonanTarget.ANDROID_ARM32, ANDROID_ARM64,
|
||||
IOS_ARM32, IOS_ARM64, IOS_X64,
|
||||
LINUX_X64, LINUX_ARM32_HFP, LINUX_MIPS32, LINUX_MIPSEL32,
|
||||
MINGW_X64,
|
||||
MACOS_X64,
|
||||
WASM32)
|
||||
|
||||
private val zephyrSubtargets = subtargetProvider.availableSubTarget("zephyr").map { ZEPHYR(it) }
|
||||
|
||||
private val configurableSubtargets = zephyrSubtargets
|
||||
|
||||
val targetValues: List<KonanTarget> by lazy {
|
||||
predefinedTargets + configurableSubtargets
|
||||
}
|
||||
|
||||
val targets = targetValues.associate{ it.visibleName to it }
|
||||
|
||||
fun toKonanTargets(names: Iterable<String>): List<KonanTarget> {
|
||||
return names.map {
|
||||
if (it == "host") HostManager.host
|
||||
else targets[known(resolveAlias(it))]!!
|
||||
}
|
||||
}
|
||||
|
||||
fun known(name: String): String {
|
||||
if (targets[name] == null) {
|
||||
throw TargetSupportException("Unknown target: $name. Use -list_targets to see the list of available targets")
|
||||
}
|
||||
return name
|
||||
}
|
||||
|
||||
fun targetByName(name: String): KonanTarget {
|
||||
if (name == "host") return host
|
||||
val target = targets[resolveAlias(name)]
|
||||
if (target == null) throw TargetSupportException("Unknown target name: $name")
|
||||
return target
|
||||
}
|
||||
|
||||
val enabled: List<KonanTarget> by lazy {
|
||||
when (host) {
|
||||
KonanTarget.LINUX_X64 -> listOf(
|
||||
KonanTarget.LINUX_X64,
|
||||
KonanTarget.LINUX_ARM32_HFP,
|
||||
KonanTarget.LINUX_MIPS32,
|
||||
KonanTarget.LINUX_MIPSEL32,
|
||||
KonanTarget.ANDROID_ARM32,
|
||||
KonanTarget.ANDROID_ARM64,
|
||||
KonanTarget.WASM32
|
||||
) + zephyrSubtargets
|
||||
KonanTarget.MINGW_X64 -> listOf(
|
||||
KonanTarget.MINGW_X64,
|
||||
KonanTarget.WASM32
|
||||
) + zephyrSubtargets
|
||||
KonanTarget.MACOS_X64 -> listOf(
|
||||
KonanTarget.MACOS_X64,
|
||||
KonanTarget.IOS_ARM32,
|
||||
KonanTarget.IOS_ARM64,
|
||||
KonanTarget.IOS_X64,
|
||||
KonanTarget.ANDROID_ARM32,
|
||||
KonanTarget.ANDROID_ARM64,
|
||||
KonanTarget.WASM32
|
||||
) + zephyrSubtargets
|
||||
else ->
|
||||
throw TargetSupportException("Unknown host platform: $host")
|
||||
}
|
||||
}
|
||||
|
||||
fun isEnabled(target: KonanTarget) = enabled.contains(target)
|
||||
|
||||
companion object {
|
||||
fun host_os(): String {
|
||||
val javaOsName = System.getProperty("os.name")
|
||||
return when {
|
||||
javaOsName == "Mac OS X" -> "osx"
|
||||
javaOsName == "Linux" -> "linux"
|
||||
javaOsName.startsWith("Windows") -> "windows"
|
||||
else -> throw TargetSupportException("Unknown operating system: ${javaOsName}")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun simpleOsName(): String {
|
||||
val hostOs = host_os()
|
||||
return if (hostOs == "osx") "macos" else hostOs
|
||||
}
|
||||
|
||||
val jniHostPlatformIncludeDir: String
|
||||
get() = when(host) {
|
||||
KonanTarget.MACOS_X64 -> "darwin"
|
||||
KonanTarget.LINUX_X64 -> "linux"
|
||||
KonanTarget.MINGW_X64 ->"win32"
|
||||
else -> throw TargetSupportException("Unknown host: $host.")
|
||||
}
|
||||
|
||||
fun host_arch(): String {
|
||||
val javaArch = System.getProperty("os.arch")
|
||||
return when (javaArch) {
|
||||
"x86_64" -> "x86_64"
|
||||
"amd64" -> "x86_64"
|
||||
"arm64" -> "arm64"
|
||||
else -> throw TargetSupportException("Unknown hardware platform: ${javaArch}")
|
||||
}
|
||||
}
|
||||
|
||||
val host: KonanTarget = when (host_os()) {
|
||||
"osx" -> KonanTarget.MACOS_X64
|
||||
"linux" -> KonanTarget.LINUX_X64
|
||||
"windows" -> KonanTarget.MINGW_X64
|
||||
else -> throw TargetSupportException("Unknown host target: ${host_os()} ${host_arch()}")
|
||||
}
|
||||
|
||||
val hostIsMac = (host == KonanTarget.MACOS_X64)
|
||||
val hostIsLinux = (host == KonanTarget.LINUX_X64)
|
||||
val hostIsMingw = (host == KonanTarget.MINGW_X64)
|
||||
|
||||
val hostSuffix get() = host.name
|
||||
@JvmStatic
|
||||
val hostName get() = host.name
|
||||
|
||||
val knownTargetTemplates = listOf("zephyr")
|
||||
|
||||
private val targetAliasResolutions = mapOf(
|
||||
"linux" to "linux_x64",
|
||||
"macbook" to "macos_x64",
|
||||
"macos" to "macos_x64",
|
||||
"imac" to "macos_x64",
|
||||
"raspberrypi" to "linux_arm32_hfp",
|
||||
"iphone32" to "ios_arm32",
|
||||
"iphone" to "ios_arm64",
|
||||
"ipad" to "ios_arm64",
|
||||
"ios" to "ios_arm64",
|
||||
"iphone_sim" to "ios_x64",
|
||||
"mingw" to "mingw_x64"
|
||||
)
|
||||
|
||||
private val targetAliases: Map<String, List<String>> by lazy {
|
||||
val result = mutableMapOf<String, MutableList<String>>()
|
||||
targetAliasResolutions.entries.forEach {
|
||||
result.getOrPut(it.value, { mutableListOf() } ).add(it.key)
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun resolveAlias(request: String): String = targetAliasResolutions[request] ?: request
|
||||
|
||||
fun listAliases(target: String): List<String> = targetAliases[target] ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
class TargetSupportException (message: String = "", cause: Throwable? = null) : Exception(message, cause)
|
||||
@@ -0,0 +1,21 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
import java.io.File
|
||||
|
||||
object DependencyDirectories {
|
||||
val localKonanDir: File by lazy {
|
||||
File(System.getenv("KONAN_DATA_DIR") ?: (System.getProperty("user.home") + File.separator + ".konan"))
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
val defaultDependenciesRoot: File
|
||||
get() = localKonanDir.resolve("dependencies")
|
||||
|
||||
val defaultDependencyCacheDir: File
|
||||
get() = localKonanDir.resolve("cache")
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
val <T : Enum<T>> T.visibleName get() = name.toLowerCase()
|
||||
interface Named {
|
||||
val name: String
|
||||
val visibleName get() = name
|
||||
}
|
||||
@@ -15,7 +15,8 @@ pill {
|
||||
|
||||
dependencies {
|
||||
compile project(':kotlin-stdlib')
|
||||
|
||||
compile project('::konan:konan-utils')
|
||||
|
||||
compileOnly gradleApi()
|
||||
compileOnly 'com.android.tools.build:gradle:0.4.2'
|
||||
}
|
||||
|
||||
+1
-2
@@ -12,8 +12,7 @@ import org.gradle.api.attributes.CompatibilityCheckDetails
|
||||
import java.io.Serializable
|
||||
|
||||
enum class KotlinPlatformType: Named, Serializable {
|
||||
common, jvm, js, androidJvm,
|
||||
native; // TODO: split native into separate entries here or transform the enum to interface and implement entries in K/N
|
||||
common, jvm, js, androidJvm, native;
|
||||
|
||||
override fun toString(): String = name
|
||||
override fun getName(): String = name
|
||||
|
||||
@@ -38,6 +38,7 @@ dependencies {
|
||||
compileOnly project(':compiler:daemon-common')
|
||||
|
||||
compile project(':kotlin-stdlib')
|
||||
compile project(':konan:konan-utils')
|
||||
compileOnly project(':kotlin-reflect-api')
|
||||
compileOnly project(':kotlin-android-extensions')
|
||||
compileOnly project(':kotlin-build-common')
|
||||
|
||||
+1
-1
@@ -102,7 +102,7 @@ class Android25ProjectHandler(kotlinConfigurationTools: KotlinConfigurationTools
|
||||
override fun setUpDependencyResolution(variant: BaseVariant, compilation: KotlinJvmAndroidCompilation) {
|
||||
val project = compilation.target.project
|
||||
|
||||
KotlinTargetConfigurator.defineConfigurationsForCompilation(compilation, compilation.target, project.configurations)
|
||||
AbstractKotlinTargetConfigurator.defineConfigurationsForCompilation(compilation, compilation.target, project.configurations)
|
||||
|
||||
compilation.compileDependencyFiles = variant.compileConfiguration.apply {
|
||||
usesPlatformOf(compilation.target)
|
||||
|
||||
+162
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright 2010-2018 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.compilerRunner
|
||||
|
||||
import org.gradle.api.Named
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.DependencyDirectories
|
||||
|
||||
/** Copied from Kotlin/Native repository. */
|
||||
|
||||
// TODO: Rename to FQ names
|
||||
internal enum class KotlinNativeProjectProperty(val propertyName: String) {
|
||||
KONAN_HOME ("konan.home"),
|
||||
KONAN_JVM_ARGS ("konan.jvmArgs"),
|
||||
KONAN_USE_ENVIRONMENT_VARIABLES("konan.useEnvironmentVariables"),
|
||||
DOWNLOAD_COMPILER ("download.compiler"),
|
||||
|
||||
// Properties used instead of env vars until https://github.com/gradle/gradle/issues/3468 is fixed.
|
||||
// TODO: Remove them when an API for env vars is provided.
|
||||
KONAN_CONFIGURATION_BUILD_DIR ("konan.configuration.build.dir"),
|
||||
KONAN_DEBUGGING_SYMBOLS ("konan.debugging.symbols"),
|
||||
KONAN_OPTIMIZATIONS_ENABLE ("konan.optimizations.enable"),
|
||||
KONAN_PUBLICATION_ENABLED ("konan.publication.enabled")
|
||||
}
|
||||
|
||||
internal fun Project.hasProperty(property: KotlinNativeProjectProperty) = hasProperty(property.propertyName)
|
||||
internal fun Project.findProperty(property: KotlinNativeProjectProperty): Any? = findProperty(property.propertyName)
|
||||
|
||||
internal fun Project.setProperty(property: KotlinNativeProjectProperty, value: Any?) =
|
||||
extensions.extraProperties.set(property.propertyName, value)
|
||||
|
||||
internal fun Project.getProperty(property: KotlinNativeProjectProperty) = findProperty(property)
|
||||
?: throw IllegalArgumentException("No such property in the project: ${property.propertyName}")
|
||||
|
||||
internal val Project.jvmArgs
|
||||
get() = (findProperty(KotlinNativeProjectProperty.KONAN_JVM_ARGS) as String?)?.split("\\s+".toRegex()).orEmpty()
|
||||
|
||||
// konanHome extension is set by downloadKonanCompiler task.
|
||||
internal val Project.konanHome: String
|
||||
get() {
|
||||
assert(hasProperty(KotlinNativeProjectProperty.KONAN_HOME))
|
||||
return project.file(getProperty(KotlinNativeProjectProperty.KONAN_HOME)).canonicalPath
|
||||
}
|
||||
|
||||
internal interface KonanToolRunner: Named {
|
||||
val mainClass: String
|
||||
val classpath: FileCollection
|
||||
val jvmArgs: List<String>
|
||||
val environment: Map<String, Any>
|
||||
val additionalSystemProperties: Map<String, String>
|
||||
|
||||
fun run(args: List<String>)
|
||||
fun run(vararg args: String) = run(args.toList())
|
||||
}
|
||||
|
||||
internal abstract class KonanCliRunner(
|
||||
val toolName: String,
|
||||
val fullName: String,
|
||||
val project: Project,
|
||||
private val additionalJvmArgs: List<String>
|
||||
): KonanToolRunner {
|
||||
override val mainClass = "org.jetbrains.kotlin.cli.utilities.MainKt"
|
||||
|
||||
override fun getName() = toolName
|
||||
|
||||
// We need to unset some environment variables which are set by XCode and may potentially affect the tool executed.
|
||||
protected val blacklistEnvironment: List<String> by lazy {
|
||||
KonanToolRunner::class.java.getResourceAsStream("/env_blacklist")?.let { stream ->
|
||||
stream.reader().use { it.readLines() }
|
||||
} ?: emptyList<String>()
|
||||
}
|
||||
|
||||
override val classpath: FileCollection =
|
||||
project.fileTree("${project.konanHome}/konan/lib/")
|
||||
.apply { include("*.jar") }
|
||||
|
||||
override val jvmArgs = mutableListOf("-ea").apply {
|
||||
if (additionalJvmArgs.none { it.startsWith("-Xmx") } &&
|
||||
project.jvmArgs.none { it.startsWith("-Xmx") }) {
|
||||
add("-Xmx3G")
|
||||
}
|
||||
addAll(additionalJvmArgs)
|
||||
addAll(project.jvmArgs)
|
||||
}
|
||||
|
||||
override val additionalSystemProperties = mutableMapOf(
|
||||
"konan.home" to project.konanHome,
|
||||
"java.library.path" to "${project.konanHome}/konan/nativelib"
|
||||
)
|
||||
|
||||
override val environment = mutableMapOf("LIBCLANG_DISABLE_CRASH_RECOVERY" to "1")
|
||||
|
||||
private fun String.escapeQuotes() = replace("\"", "\\\"")
|
||||
|
||||
private fun List<Pair<String, String>>.escapeQuotesForWindows() =
|
||||
if (HostManager.hostIsMingw) {
|
||||
map { (key, value) -> key.escapeQuotes() to value.escapeQuotes() }
|
||||
} else {
|
||||
this
|
||||
}
|
||||
|
||||
override fun run(args: List<String>) {
|
||||
project.logger.info("Run tool: $toolName with args: ${args.joinToString(separator = " ")}")
|
||||
if (classpath.isEmpty) {
|
||||
throw IllegalStateException("Classpath of the tool is empty: $toolName\n" +
|
||||
"Probably the 'konan.home' project property contains an incorrect path.\n" +
|
||||
"Please change it to the compiler root directory and rerun the build.")
|
||||
}
|
||||
|
||||
project.javaexec { spec ->
|
||||
spec.main = mainClass
|
||||
spec.classpath = classpath
|
||||
spec.jvmArgs(jvmArgs)
|
||||
spec.systemProperties(
|
||||
System.getProperties()
|
||||
.map { (k, v) -> k.toString() to v.toString() }
|
||||
.escapeQuotesForWindows()
|
||||
.toMap()
|
||||
)
|
||||
spec.systemProperties(additionalSystemProperties)
|
||||
spec.args(listOf(toolName) + args)
|
||||
blacklistEnvironment.forEach { spec.environment.remove(it) }
|
||||
spec.environment(environment)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class KonanInteropRunner(project: Project, additionalJvmArgs: List<String> = emptyList())
|
||||
: KonanCliRunner("cinterop", "Kotlin/Native cinterop tool", project, additionalJvmArgs)
|
||||
{
|
||||
init {
|
||||
if (HostManager.host == KonanTarget.MINGW_X64) {
|
||||
//TODO: Oh-ho-ho fix it in more convinient way.
|
||||
environment.put("PATH", DependencyDirectories.defaultDependenciesRoot.absolutePath +
|
||||
"\\msys2-mingw-w64-x86_64-gcc-7.2.0-clang-llvm-5.0.0-windows-x86-64" +
|
||||
"\\bin;${environment.get("PATH")}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal class KonanCompilerRunner(project: Project, additionalJvmArgs: List<String> = emptyList())
|
||||
: KonanCliRunner("konanc", "Kotlin/Native compiler", project, additionalJvmArgs)
|
||||
|
||||
internal class KonanKlibRunner(project: Project, additionalJvmArgs: List<String> = emptyList())
|
||||
: KonanCliRunner("klib", "Klib management tool", project, additionalJvmArgs)
|
||||
+1
-1
@@ -432,7 +432,7 @@ internal abstract class AbstractKotlinPlugin(
|
||||
// Setup the consuming configurations:
|
||||
project.dependencies.attributesSchema.attribute(KotlinPlatformType.attribute)
|
||||
kotlinTarget.compilations.all { compilation ->
|
||||
KotlinTargetConfigurator.defineConfigurationsForCompilation(compilation, kotlinTarget, project.configurations)
|
||||
AbstractKotlinTargetConfigurator.defineConfigurationsForCompilation(compilation, kotlinTarget, project.configurations)
|
||||
}
|
||||
|
||||
// Setup the published configurations:
|
||||
|
||||
+274
-67
@@ -18,6 +18,8 @@ import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.artifacts.ArtifactAttributes
|
||||
import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact
|
||||
import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
|
||||
import org.gradle.api.internal.plugins.DslObject
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.plugins.JavaBasePlugin
|
||||
@@ -26,22 +28,26 @@ import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.internal.cleanup.BuildOutputCleanupRegistry
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.gradle.nativeplatform.test.tasks.RunTestExecutable
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.defaultSourceSetName
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
|
||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.KonanCompilerDownloadTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
|
||||
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import java.util.concurrent.Callable
|
||||
|
||||
open class KotlinTargetConfigurator(
|
||||
abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>(
|
||||
private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry
|
||||
) {
|
||||
fun <KotlinCompilationType: KotlinCompilation> configureTarget(
|
||||
target: KotlinOnlyTarget<KotlinCompilationType>
|
||||
open fun configureTarget(
|
||||
target: KotlinTargetType
|
||||
) {
|
||||
configureCompilationDefaults(target)
|
||||
configureCompilations(target)
|
||||
@@ -49,11 +55,12 @@ open class KotlinTargetConfigurator(
|
||||
configureArchivesAndComponent(target)
|
||||
configureTest(target)
|
||||
configureBuild(target)
|
||||
|
||||
setCompatibilityOfAbstractCompileTasks(target.project)
|
||||
}
|
||||
|
||||
private fun <KotlinCompilationType: KotlinCompilation> configureCompilations(platformTarget: KotlinOnlyTarget<KotlinCompilationType>) {
|
||||
|
||||
abstract fun configureArchivesAndComponent(target: KotlinTargetType)
|
||||
|
||||
protected fun configureCompilations(platformTarget: KotlinTargetType) {
|
||||
val project = platformTarget.project
|
||||
val main = platformTarget.compilations.create(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
|
||||
@@ -75,7 +82,7 @@ open class KotlinTargetConfigurator(
|
||||
|
||||
}
|
||||
|
||||
private fun <KotlinCompilationType: KotlinCompilation> configureCompilationDefaults(target: KotlinOnlyTarget<KotlinCompilationType>) {
|
||||
protected fun configureCompilationDefaults(target: KotlinTargetType) {
|
||||
val project = target.project
|
||||
|
||||
target.compilations.all { compilation ->
|
||||
@@ -94,49 +101,7 @@ open class KotlinTargetConfigurator(
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureArchivesAndComponent(target: KotlinOnlyTarget<*>) {
|
||||
val project = target.project
|
||||
|
||||
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
|
||||
val jar = project.tasks.create(target.artifactsTaskName, Jar::class.java)
|
||||
jar.description = "Assembles a jar archive containing the main classes."
|
||||
jar.group = BasePlugin.BUILD_GROUP
|
||||
jar.from(mainCompilation.output)
|
||||
|
||||
val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
|
||||
|
||||
target.disambiguationClassifier?.let { jar.classifier = it }
|
||||
|
||||
// Workaround: adding the artifact during configuration seems to interfere with the Java plugin, which results into missing
|
||||
// task dependency 'assemble -> jar' if the Java plugin is applied after this steps
|
||||
project.afterEvaluate {
|
||||
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, jar) { jarArtifact ->
|
||||
jarArtifact.builtBy(jar)
|
||||
jarArtifact.type = ArtifactTypeDefinition.JAR_TYPE
|
||||
|
||||
addJar(apiElementsConfiguration, jarArtifact)
|
||||
|
||||
if (mainCompilation is KotlinCompilationToRunnableFiles) {
|
||||
val runtimeConfiguration = project.configurations.getByName(mainCompilation.deprecatedRuntimeConfigurationName)
|
||||
val runtimeElementsConfiguration = project.configurations.getByName(target.runtimeElementsConfigurationName)
|
||||
addJar(runtimeConfiguration, jarArtifact)
|
||||
addJar(runtimeElementsConfiguration, jarArtifact)
|
||||
// TODO Check Gradle's special split into variants for classes & resources -- do we need that too?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addJar(configuration: Configuration, jarArtifact: PublishArtifact) {
|
||||
val publications = configuration.outgoing
|
||||
|
||||
// Configure an implicit variant
|
||||
publications.artifacts.add(jarArtifact)
|
||||
publications.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, ArtifactTypeDefinition.JAR_TYPE)
|
||||
}
|
||||
|
||||
private fun configureTest(target: KotlinTarget) {
|
||||
protected fun configureTest(target: KotlinTarget) {
|
||||
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME) as? KotlinCompilationToRunnableFiles
|
||||
?: return // Otherwise, there is no runtime classpath
|
||||
|
||||
@@ -151,7 +116,7 @@ open class KotlinTargetConfigurator(
|
||||
}
|
||||
}
|
||||
|
||||
private fun configureResourceProcessing(
|
||||
protected fun configureResourceProcessing(
|
||||
compilation: KotlinCompilationWithResources,
|
||||
resourceSet: FileCollection
|
||||
) {
|
||||
@@ -168,7 +133,7 @@ open class KotlinTargetConfigurator(
|
||||
resourcesTask.from(resourceSet)
|
||||
}
|
||||
|
||||
private fun createLifecycleTask(compilation: KotlinCompilation) {
|
||||
protected fun createLifecycleTask(compilation: KotlinCompilation) {
|
||||
val project = compilation.target.project
|
||||
|
||||
(compilation.output.classesDirs as ConfigurableFileCollection).from(project.files().builtBy(compilation.compileAllTaskName))
|
||||
@@ -186,7 +151,7 @@ open class KotlinTargetConfigurator(
|
||||
}
|
||||
}
|
||||
|
||||
private fun defineConfigurationsForTarget(target: KotlinOnlyTarget<*>) {
|
||||
protected fun defineConfigurationsForTarget(target: KotlinTargetType) {
|
||||
val project = target.project
|
||||
|
||||
val configurations = project.configurations
|
||||
@@ -243,7 +208,7 @@ open class KotlinTargetConfigurator(
|
||||
defaultConfiguration.extendsFrom(runtimeElementsConfiguration).usesPlatformOf(target)
|
||||
}
|
||||
|
||||
private fun configureBuild(target: KotlinOnlyTarget<*>) {
|
||||
protected fun configureBuild(target: KotlinTargetType) {
|
||||
val project = target.project
|
||||
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
|
||||
project.tasks.maybeCreate(buildNeededTaskName, DefaultTask::class.java).apply {
|
||||
@@ -279,14 +244,6 @@ open class KotlinTargetConfigurator(
|
||||
task.dependsOn(configuration.getTaskDependencyFromProjectDependency(useDependedOn, otherProjectTaskName))
|
||||
}
|
||||
|
||||
private fun setCompatibilityOfAbstractCompileTasks(project: Project) = with (project) {
|
||||
tasks.withType(AbstractKotlinCompile::class.java).all {
|
||||
// Workaround: these are input properties and should not hold null values:
|
||||
it.targetCompatibility = ""
|
||||
it.sourceCompatibility = ""
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
const val buildNeededTaskName = "buildAllNeeded"
|
||||
const val buildDependentTaskName = "buildAllDependents"
|
||||
@@ -363,14 +320,260 @@ open class KotlinTargetConfigurator(
|
||||
}
|
||||
}
|
||||
|
||||
private val KotlinCompilation.deprecatedCompileConfigurationName: String
|
||||
|
||||
internal val KotlinCompilation.deprecatedCompileConfigurationName: String
|
||||
get() = disambiguateName("compile")
|
||||
|
||||
private val KotlinCompilationToRunnableFiles.deprecatedRuntimeConfigurationName: String
|
||||
internal val KotlinCompilationToRunnableFiles.deprecatedRuntimeConfigurationName: String
|
||||
get() = disambiguateName("runtime")
|
||||
}
|
||||
}
|
||||
|
||||
open class KotlinTargetConfigurator<KotlinCompilationType: KotlinCompilation>(
|
||||
buildOutputCleanupRegistry: BuildOutputCleanupRegistry
|
||||
) : AbstractKotlinTargetConfigurator<KotlinOnlyTarget<KotlinCompilationType>>(buildOutputCleanupRegistry) {
|
||||
|
||||
override fun configureTarget(
|
||||
target: KotlinOnlyTarget<KotlinCompilationType>
|
||||
) {
|
||||
super.configureTarget(target)
|
||||
setCompatibilityOfAbstractCompileTasks(target.project)
|
||||
}
|
||||
|
||||
override fun configureArchivesAndComponent(target: KotlinOnlyTarget<KotlinCompilationType>) {
|
||||
val project = target.project
|
||||
|
||||
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
|
||||
val jar = project.tasks.create(target.artifactsTaskName, Jar::class.java)
|
||||
jar.description = "Assembles a jar archive containing the main classes."
|
||||
jar.group = BasePlugin.BUILD_GROUP
|
||||
jar.from(mainCompilation.output)
|
||||
|
||||
val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
|
||||
|
||||
target.disambiguationClassifier?.let { jar.classifier = it }
|
||||
|
||||
// Workaround: adding the artifact during configuration seems to interfere with the Java plugin, which results into missing
|
||||
// task dependency 'assemble -> jar' if the Java plugin is applied after this steps
|
||||
project.afterEvaluate {
|
||||
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, jar) { jarArtifact ->
|
||||
jarArtifact.builtBy(jar)
|
||||
jarArtifact.type = ArtifactTypeDefinition.JAR_TYPE
|
||||
|
||||
addJar(apiElementsConfiguration, jarArtifact)
|
||||
|
||||
if (mainCompilation is KotlinCompilationToRunnableFiles) {
|
||||
val runtimeConfiguration = project.configurations.getByName(mainCompilation.deprecatedRuntimeConfigurationName)
|
||||
val runtimeElementsConfiguration = project.configurations.getByName(target.runtimeElementsConfigurationName)
|
||||
addJar(runtimeConfiguration, jarArtifact)
|
||||
addJar(runtimeElementsConfiguration, jarArtifact)
|
||||
// TODO Check Gradle's special split into variants for classes & resources -- do we need that too?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun addJar(configuration: Configuration, jarArtifact: PublishArtifact) {
|
||||
val publications = configuration.outgoing
|
||||
|
||||
// Configure an implicit variant
|
||||
publications.artifacts.add(jarArtifact)
|
||||
publications.attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, ArtifactTypeDefinition.JAR_TYPE)
|
||||
}
|
||||
|
||||
private fun setCompatibilityOfAbstractCompileTasks(project: Project) = with (project) {
|
||||
tasks.withType(AbstractKotlinCompile::class.java).all {
|
||||
// Workaround: these are input properties and should not hold null values:
|
||||
it.targetCompatibility = ""
|
||||
it.sourceCompatibility = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
open class KotlinNativeTargetConfigurator(
|
||||
buildOutputCleanupRegistry: BuildOutputCleanupRegistry
|
||||
) : AbstractKotlinTargetConfigurator<KotlinNativeTarget>(buildOutputCleanupRegistry) {
|
||||
|
||||
private val Collection<*>.isDimensionVisible: Boolean
|
||||
get() = size > 1
|
||||
|
||||
private fun createDimensionSuffix(dimensionName: String, multivalueProperty: Collection<*>): String =
|
||||
if (multivalueProperty.isDimensionVisible) {
|
||||
dimensionName.toLowerCase().capitalize()
|
||||
} else {
|
||||
""
|
||||
}
|
||||
|
||||
private fun Project.createTestTask(compilation: KotlinNativeCompilation, testExecutableLinkTask: KotlinNativeCompile) {
|
||||
val taskName = lowerCamelCaseName("run", compilation.name, compilation.target.name)
|
||||
val testTask = tasks.create(taskName, RunTestExecutable::class.java).apply {
|
||||
group = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||
description = "Executes Kotlin/Native unit tests from the '${compilation.name}' compilation " +
|
||||
"for target '${compilation.platformType.name}'"
|
||||
|
||||
val testExecutableProperty = testExecutableLinkTask.outputFile
|
||||
executable = testExecutableProperty.get().absolutePath
|
||||
// TODO: Provide a normal test path!
|
||||
outputDir = project.layout.buildDirectory.dir("test-results").get().asFile
|
||||
|
||||
onlyIf { testExecutableProperty.get().exists() }
|
||||
inputs.file(testExecutableProperty)
|
||||
dependsOn(testExecutableLinkTask)
|
||||
dependsOnCompilerDownloading()
|
||||
}
|
||||
tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME).apply {
|
||||
dependsOn(testTask)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.createBinaryLinkTasks(compilation: KotlinNativeCompilation) = whenEvaluated {
|
||||
val konanTarget = compilation.target.konanTarget
|
||||
val buildTypes = compilation.buildTypes
|
||||
val availableOutputKinds = compilation.outputKinds.filter { it.availableFor(konanTarget) }
|
||||
val linkAll = project.tasks.maybeCreate(compilation.linkAllTaskName)
|
||||
|
||||
for (buildType in compilation.buildTypes) {
|
||||
for (kind in availableOutputKinds) {
|
||||
val compilerOutputKind = kind.compilerOutputKind
|
||||
|
||||
val compilationSuffix = compilation.name
|
||||
val buildTypeSuffix = createDimensionSuffix(buildType.name, buildTypes)
|
||||
val targetSuffix = compilation.target.name
|
||||
val kindSuffix = kind.taskNameClassifier
|
||||
val taskName = lowerCamelCaseName("link", compilationSuffix, buildTypeSuffix, kindSuffix, targetSuffix)
|
||||
|
||||
val linkTask = project.tasks.create(
|
||||
taskName,
|
||||
KotlinNativeCompile::class.java
|
||||
).apply {
|
||||
this.compilation = compilation
|
||||
outputKind = compilerOutputKind
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
description = "Links ${kind.description} from the '${compilation.name}' " +
|
||||
"compilation for target '${compilation.platformType.name}'"
|
||||
|
||||
optimized = buildType.optimized
|
||||
debuggable = buildType.debuggable
|
||||
|
||||
if (outputKind == CompilerOutputKind.FRAMEWORK) {
|
||||
outputs.dir(outputFile)
|
||||
} else {
|
||||
outputs.file(outputFile)
|
||||
}
|
||||
|
||||
outputFile.set(provider {
|
||||
val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty()
|
||||
val buildTypeSubDirectory = buildType.name.toLowerCase()
|
||||
val compilationName = compilation.compilationName
|
||||
val prefix = compilerOutputKind.prefix(konanTarget)
|
||||
val suffix = compilerOutputKind.suffix(konanTarget)
|
||||
var filename = "$prefix$compilationName$suffix"
|
||||
if (outputKind == CompilerOutputKind.FRAMEWORK) {
|
||||
filename = filename.replace('-', '_')
|
||||
}
|
||||
File(project.buildDir, "bin/$targetSubDirectory$compilationName/$buildTypeSubDirectory/$filename")
|
||||
})
|
||||
|
||||
dependsOnCompilerDownloading()
|
||||
linkAll.dependsOn(this)
|
||||
}
|
||||
|
||||
if (compilation.isTestCompilation &&
|
||||
buildType == NativeBuildType.DEBUG &&
|
||||
konanTarget == HostManager.host
|
||||
) {
|
||||
createTestTask(compilation, linkTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.createKlibPublishableArtifact(compilation: KotlinNativeCompilation, compileTask: KotlinNativeCompile) {
|
||||
val apiElements = configurations.getByName(compilation.target.apiElementsConfigurationName)
|
||||
val klibArtifact = DefaultPublishArtifact(
|
||||
compilation.name,
|
||||
"klib",
|
||||
"klib",
|
||||
null,
|
||||
Date(),
|
||||
compileTask.outputFile.get(),
|
||||
compileTask
|
||||
)
|
||||
compilation.target.disambiguationClassifier?.let { klibArtifact.classifier = it }
|
||||
project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
|
||||
|
||||
with(apiElements.outgoing) {
|
||||
artifacts.add(klibArtifact)
|
||||
attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Project.createKlibCompilationTask(compilation: KotlinNativeCompilation) {
|
||||
val compileTask = tasks.create(
|
||||
compilation.compileKotlinTaskName,
|
||||
KotlinNativeCompile::class.java
|
||||
).apply {
|
||||
this.compilation = compilation
|
||||
outputKind = CompilerOutputKind.LIBRARY
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
description = "Compiles a klibrary from the '${compilation.name}' " +
|
||||
"compilation for target '${compilation.platformType.name}'"
|
||||
|
||||
outputs.file(outputFile)
|
||||
outputFile.set(provider {
|
||||
val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty()
|
||||
val classifier = compilation.target.disambiguationClassifier?.let { "-$it" }.orEmpty()
|
||||
val compilationName = compilation.compilationName
|
||||
val klibName = if (compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||
project.name
|
||||
else
|
||||
compilationName
|
||||
File(project.buildDir, "classes/kotlin/$targetSubDirectory$compilationName/$klibName$classifier.klib")
|
||||
})
|
||||
|
||||
dependsOnCompilerDownloading()
|
||||
compilation.output.tryAddClassesDir {
|
||||
project.files(this.outputFile).builtBy(this)
|
||||
}
|
||||
}
|
||||
|
||||
project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTask)
|
||||
|
||||
if (compilation.compilationName == KotlinCompilation.MAIN_COMPILATION_NAME) {
|
||||
project.tasks.getByName(compilation.target.artifactsTaskName).apply {
|
||||
dependsOn(compileTask)
|
||||
dependsOn(compilation.linkAllTaskName)
|
||||
}
|
||||
project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply {
|
||||
dependsOn(compileTask)
|
||||
dependsOn(compilation.linkAllTaskName)
|
||||
}
|
||||
createKlibPublishableArtifact(compilation, compileTask)
|
||||
}
|
||||
}
|
||||
|
||||
override fun configureArchivesAndComponent(target: KotlinNativeTarget) = with(target.project) {
|
||||
if (!HostManager().isEnabled(target.konanTarget)) {
|
||||
return
|
||||
}
|
||||
|
||||
tasks.create(target.artifactsTaskName)
|
||||
target.compilations.all {
|
||||
createKlibCompilationTask(it)
|
||||
createBinaryLinkTasks(it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun Task.dependsOnCompilerDownloading() =
|
||||
dependsOn(KonanCompilerDownloadTask.KONAN_DOWNLOAD_TASK_NAME)
|
||||
|
||||
object NativeArtifactFormat {
|
||||
const val KLIB = "org.jerbrains.kotlin.klib"
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Project.usageByName(usageName: String): Usage =
|
||||
if (isGradleVersionAtLeast(4, 0)) {
|
||||
// `project.objects` is an API introduced in Gradle 4.0
|
||||
@@ -383,5 +586,9 @@ internal fun Project.usageByName(usageName: String): Usage =
|
||||
|
||||
fun Configuration.usesPlatformOf(target: KotlinTarget): Configuration {
|
||||
attributes.attribute(KotlinPlatformType.attribute, target.platformType)
|
||||
// TODO: Provide an universal way to copy attributes from the target.
|
||||
if (target is KotlinNativeTarget) {
|
||||
attributes.attribute(KotlinNativeTarget.konanTargetAttribute, target.konanTarget.name)
|
||||
}
|
||||
return this
|
||||
}
|
||||
+21
-9
@@ -3,15 +3,6 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
|
||||
@@ -82,4 +73,25 @@ class KotlinJsCompilationFactory(
|
||||
|
||||
override fun create(name: String): KotlinJsCompilation =
|
||||
KotlinJsCompilation(target, name, target.createCompilationOutput(name))
|
||||
}
|
||||
|
||||
class KotlinNativeCompilationFactory(
|
||||
val project: Project,
|
||||
val target: KotlinNativeTarget
|
||||
) : KotlinCompilationFactory<KotlinNativeCompilation> {
|
||||
|
||||
override val itemClass: Class<KotlinNativeCompilation>
|
||||
get() = KotlinNativeCompilation::class.java
|
||||
|
||||
override fun create(name: String): KotlinNativeCompilation =
|
||||
KotlinNativeCompilation(target, name, target.createCompilationOutput(name)).apply {
|
||||
if (name == KotlinCompilation.TEST_COMPILATION_NAME) {
|
||||
outputKinds = mutableListOf(NativeOutputKind.EXECUTABLE)
|
||||
buildTypes = mutableListOf(NativeBuildType.DEBUG)
|
||||
isTestCompilation = true
|
||||
} else {
|
||||
buildTypes = mutableListOf(NativeBuildType.DEBUG, NativeBuildType.RELEASE)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
-10
@@ -3,16 +3,6 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
|
||||
import org.gradle.api.Project
|
||||
|
||||
+4
@@ -25,6 +25,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.source.KotlinSourceSet
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
|
||||
internal val Project.multiplatformExtension get(): KotlinMultiplatformExtension? =
|
||||
project.extensions.getByName("kotlin") as KotlinMultiplatformExtension
|
||||
@@ -86,6 +87,9 @@ class KotlinMultiplatformPlugin(
|
||||
add(KotlinJsTargetPreset(project, instantiator, fileResolver, buildOutputCleanupRegistry, kotlinPluginVersion))
|
||||
add(KotlinAndroidTargetPreset(project, kotlinPluginVersion))
|
||||
add(KotlinJvmWithJavaTargetPreset(project, kotlinPluginVersion))
|
||||
HostManager().targets.forEach { _, target ->
|
||||
add(KotlinNativeTargetPreset(target.presetName, project, target, buildOutputCleanupRegistry))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -33,6 +33,12 @@ class KotlinSoftwareComponent(
|
||||
}
|
||||
}
|
||||
|
||||
// At the moment all KN artifacts have JAVA_API usage.
|
||||
// TODO: Replace it with a specific usage
|
||||
object NativeUsage {
|
||||
const val KOTLIN_KLIB = "kotlin-klib"
|
||||
}
|
||||
|
||||
internal class KotlinPlatformUsageContext(
|
||||
val project: Project,
|
||||
val kotlinTarget: KotlinTarget,
|
||||
|
||||
+48
@@ -0,0 +1,48 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
|
||||
import org.gradle.api.Named
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
object KotlinNativeUsage {
|
||||
const val KLIB = "kotlin-native-klib"
|
||||
const val FRAMEWORK = "kotlin-native-framework"
|
||||
}
|
||||
|
||||
enum class NativeBuildType(val optimized: Boolean, val debuggable: Boolean): Named {
|
||||
RELEASE(true, false),
|
||||
DEBUG(false, true);
|
||||
|
||||
override fun getName(): String = name.toLowerCase()
|
||||
}
|
||||
|
||||
enum class NativeOutputKind(
|
||||
val compilerOutputKind: CompilerOutputKind,
|
||||
val taskNameClassifier: String,
|
||||
val description: String = taskNameClassifier,
|
||||
val additionalCompilerFlags: List<String> = emptyList(),
|
||||
val runtimeUsageName: String? = null,
|
||||
val linkUsageName: String? = null,
|
||||
val publishable: Boolean = true
|
||||
) {
|
||||
EXECUTABLE(
|
||||
CompilerOutputKind.PROGRAM,
|
||||
"executable",
|
||||
description = "an executable",
|
||||
runtimeUsageName = Usage.NATIVE_RUNTIME
|
||||
),
|
||||
FRAMEWORK(
|
||||
CompilerOutputKind.FRAMEWORK,
|
||||
"framework",
|
||||
description = "an Objective-C framework",
|
||||
linkUsageName = KotlinNativeUsage.FRAMEWORK,
|
||||
publishable = false
|
||||
) {
|
||||
override fun availableFor(target: KonanTarget) =
|
||||
target.family == Family.OSX || target.family == Family.IOS
|
||||
};
|
||||
|
||||
open fun availableFor(target: KonanTarget) = true
|
||||
}
|
||||
+75
-13
@@ -3,16 +3,6 @@
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
/*
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
|
||||
import groovy.lang.Closure
|
||||
@@ -59,21 +49,30 @@ internal class DefaultKotlinDependencyHandler(
|
||||
}
|
||||
|
||||
abstract class AbstractKotlinCompilation(
|
||||
final override val target: KotlinTarget,
|
||||
target: KotlinTarget,
|
||||
override val compilationName: String
|
||||
) : KotlinCompilation, HasKotlinDependencies {
|
||||
|
||||
// Don't declare this property in the constructor to avoid NPE
|
||||
// when an overriding property of a subclass is accessed instead.
|
||||
override val target: KotlinTarget = target
|
||||
|
||||
private val attributeContainer = HierarchyAttributeContainer(target.attributes)
|
||||
|
||||
override fun getAttributes(): AttributeContainer = attributeContainer
|
||||
|
||||
override val kotlinSourceSets: MutableSet<KotlinSourceSet> = mutableSetOf()
|
||||
|
||||
open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet) {
|
||||
(target.project.tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(sourceSet.kotlin)
|
||||
}
|
||||
|
||||
override fun source(sourceSet: KotlinSourceSet) {
|
||||
if (kotlinSourceSets.add(sourceSet)) {
|
||||
with(target.project) {
|
||||
whenEvaluated {
|
||||
sourceSet.getSourceSetHierarchy().forEach { sourceSet ->
|
||||
(target.project.tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(sourceSet.kotlin)
|
||||
addSourcesToCompileTask(sourceSet)
|
||||
|
||||
// Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like
|
||||
// old Java & Android projects:
|
||||
@@ -242,4 +241,67 @@ class KotlinCommonCompilation(
|
||||
target: KotlinTarget,
|
||||
name: String,
|
||||
override val output: SourceSetOutput
|
||||
) : AbstractKotlinCompilation(target, name)
|
||||
) : AbstractKotlinCompilation(target, name)
|
||||
|
||||
class KotlinNativeCompilation(
|
||||
override val target: KotlinNativeTarget,
|
||||
name: String,
|
||||
override val output: SourceSetOutput
|
||||
) : AbstractKotlinCompilation(target, name) {
|
||||
|
||||
// A FileCollection containing source files from all source sets used by this compilation
|
||||
// (taking into account dependencies between source sets). Used by both compilation
|
||||
// and linking tasks.
|
||||
// TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
|
||||
internal var allSources: FileCollection = target.project.files()
|
||||
|
||||
val linkAllTaskName: String
|
||||
get() = lowerCamelCaseName(
|
||||
"link",
|
||||
compilationName.takeIf { it != "main" }.orEmpty(),
|
||||
target.disambiguationClassifier
|
||||
)
|
||||
|
||||
var isTestCompilation = false
|
||||
|
||||
// Native-specific DSL.
|
||||
val extraOpts = mutableListOf<String>()
|
||||
|
||||
fun extraOpts(vararg values: Any) = extraOpts(values.toList())
|
||||
fun extraOpts(values: List<Any>) {
|
||||
extraOpts.addAll(values.map { it.toString() })
|
||||
}
|
||||
|
||||
var buildTypes = mutableListOf<NativeBuildType>()
|
||||
var outputKinds = mutableListOf<NativeOutputKind>()
|
||||
|
||||
// Naming
|
||||
|
||||
override val compileDependencyConfigurationName: String
|
||||
get() = lowerCamelCaseName(
|
||||
target.disambiguationClassifier,
|
||||
compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
|
||||
"compileKlibraries"
|
||||
)
|
||||
|
||||
override val compileAllTaskName: String
|
||||
get() = lowerCamelCaseName(
|
||||
target.disambiguationClassifier,
|
||||
compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME }.orEmpty(),
|
||||
"klibrary"
|
||||
)
|
||||
|
||||
override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet) {
|
||||
allSources += sourceSet.kotlin
|
||||
}
|
||||
|
||||
// TODO: Can we do it better?
|
||||
companion object {
|
||||
val DEBUG = NativeBuildType.DEBUG
|
||||
val RELEASE = NativeBuildType.RELEASE
|
||||
|
||||
val EXECUTABLE = NativeOutputKind.EXECUTABLE
|
||||
val FRAMEWORK = NativeOutputKind.FRAMEWORK
|
||||
}
|
||||
|
||||
}
|
||||
+47
-3
@@ -10,9 +10,14 @@ import org.gradle.api.internal.file.FileResolver
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
import org.gradle.internal.cleanup.BuildOutputCleanupRegistry
|
||||
import org.gradle.internal.reflect.Instantiator
|
||||
import org.jetbrains.kotlin.compilerRunner.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.AndroidTasksProvider
|
||||
import org.jetbrains.kotlin.gradle.tasks.KonanCompilerDownloadTask
|
||||
import org.jetbrains.kotlin.gradle.tasks.KonanCompilerDownloadTask.Companion.KONAN_DOWNLOAD_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
abstract class KotlinOnlyTargetPreset<T : KotlinCompilation>(
|
||||
protected val project: Project,
|
||||
@@ -31,7 +36,7 @@ abstract class KotlinOnlyTargetPreset<T : KotlinCompilation>(
|
||||
compilations = project.container(compilationFactory.itemClass, compilationFactory)
|
||||
}
|
||||
|
||||
KotlinTargetConfigurator(buildOutputCleanupRegistry).configureTarget(result)
|
||||
KotlinTargetConfigurator<T>(buildOutputCleanupRegistry).configureTarget(result)
|
||||
|
||||
result.compilations.all { compilation ->
|
||||
buildCompilationProcessor(compilation).run()
|
||||
@@ -184,7 +189,7 @@ class KotlinJvmWithJavaTargetPreset(
|
||||
|
||||
target.compilations.all { compilation ->
|
||||
// Set up dependency resolution using platforms:
|
||||
KotlinTargetConfigurator.defineConfigurationsForCompilation(compilation, target, project.configurations)
|
||||
AbstractKotlinTargetConfigurator.defineConfigurationsForCompilation(compilation, target, project.configurations)
|
||||
}
|
||||
|
||||
target.compilations.getByName("test").run {
|
||||
@@ -200,4 +205,43 @@ class KotlinJvmWithJavaTargetPreset(
|
||||
companion object {
|
||||
const val PRESET_NAME = "jvmWithJava"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class KotlinNativeTargetPreset(
|
||||
private val name: String,
|
||||
val project: Project,
|
||||
val konanTarget: KonanTarget,
|
||||
private val buildOutputCleanupRegistry: BuildOutputCleanupRegistry
|
||||
) : KotlinTargetPreset<KotlinNativeTarget> {
|
||||
|
||||
override fun getName(): String = name
|
||||
|
||||
private fun createCompilerDownloadingTask() = with(project) {
|
||||
if (!hasProperty(KotlinNativeProjectProperty.KONAN_HOME)) {
|
||||
setProperty(KotlinNativeProjectProperty.KONAN_HOME, KonanCompilerDownloadTask.compilerDirectory)
|
||||
setProperty(KotlinNativeProjectProperty.DOWNLOAD_COMPILER, true)
|
||||
}
|
||||
tasks.maybeCreate(KONAN_DOWNLOAD_TASK_NAME, KonanCompilerDownloadTask::class.java)
|
||||
}
|
||||
|
||||
override fun createTarget(name: String): KotlinNativeTarget {
|
||||
val result = KotlinNativeTarget(project, konanTarget).apply {
|
||||
targetName = name
|
||||
disambiguationClassifier = name
|
||||
|
||||
val compilationFactory = KotlinNativeCompilationFactory(project, this)
|
||||
compilations = project.container(compilationFactory.itemClass, compilationFactory)
|
||||
}
|
||||
|
||||
createCompilerDownloadingTask()
|
||||
KotlinNativeTargetConfigurator(buildOutputCleanupRegistry).configureTarget(result)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal val KonanTarget.presetName: String
|
||||
get() = when(this) {
|
||||
KonanTarget.ANDROID_ARM32 -> "androidNativeArm32"
|
||||
KonanTarget.ANDROID_ARM64 -> "androidNativeArm64"
|
||||
else -> lowerCamelCaseName(*this.name.split('_').toTypedArray())
|
||||
}
|
||||
|
||||
+24
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.attributes.Attribute
|
||||
import org.gradle.api.attributes.AttributeContainer
|
||||
import org.gradle.api.internal.component.UsageContext
|
||||
import org.gradle.api.plugins.JavaPlugin
|
||||
@@ -15,6 +16,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationToRunnableFiles
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
abstract class AbstractKotlinTarget (
|
||||
override val project: Project
|
||||
@@ -118,3 +120,25 @@ open class KotlinOnlyTarget<T : KotlinCompilation>(
|
||||
override var disambiguationClassifier: String? = null
|
||||
internal set
|
||||
}
|
||||
|
||||
class KotlinNativeTarget(
|
||||
project: Project,
|
||||
val konanTarget: KonanTarget
|
||||
) : KotlinOnlyTarget<KotlinNativeCompilation>(project, KotlinPlatformType.native) {
|
||||
|
||||
init {
|
||||
attributes.attribute(konanTargetAttribute, konanTarget.name)
|
||||
}
|
||||
|
||||
// TODO: Should binary files be output of a target or a compilation?
|
||||
override val artifactsTaskName: String
|
||||
get() = disambiguateName("link")
|
||||
|
||||
companion object {
|
||||
val konanTargetAttribute = Attribute.of(
|
||||
"org.jetbrains.kotlin.native.target",
|
||||
String::class.java
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+238
@@ -0,0 +1,238 @@
|
||||
package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.artifacts.repositories.ArtifactRepository
|
||||
import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.compilerRunner.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.KonanVersionImpl
|
||||
import org.jetbrains.kotlin.konan.MetaVersion
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.util.DependencyDirectories
|
||||
import java.io.File
|
||||
|
||||
// TODO: It's just temporary tasks used while KN isn't integrated with Big Kotlin compilation infrastructure.
|
||||
|
||||
open class KotlinNativeCompile : DefaultTask() {
|
||||
|
||||
init {
|
||||
super.dependsOn(KonanCompilerDownloadTask.KONAN_DOWNLOAD_TASK_NAME)
|
||||
}
|
||||
|
||||
@Internal
|
||||
lateinit var compilation: KotlinNativeCompilation
|
||||
|
||||
// region inputs/outputs
|
||||
@Input
|
||||
lateinit var outputKind: CompilerOutputKind
|
||||
|
||||
// Inputs and outputs
|
||||
|
||||
val sources: FileCollection
|
||||
@InputFiles
|
||||
@SkipWhenEmpty
|
||||
get() = compilation.allSources
|
||||
|
||||
val libraries: FileCollection
|
||||
@InputFiles get() = compilation.compileDependencyFiles.filter {
|
||||
it.extension == "klib"
|
||||
}
|
||||
|
||||
@Input
|
||||
var optimized = false
|
||||
@Input
|
||||
var debuggable = true
|
||||
|
||||
val processTests
|
||||
@Input get() = compilation.isTestCompilation
|
||||
|
||||
val target: String
|
||||
@Input get() = compilation.target.konanTarget.name
|
||||
|
||||
val additionalCompilerOptions: Collection<String>
|
||||
@Input get() = compilation.extraOpts
|
||||
|
||||
|
||||
val outputFile: Property<File> = project.objects.property(File::class.java)
|
||||
|
||||
// endregion
|
||||
|
||||
// region Useful extensions
|
||||
internal fun MutableList<String>.addArg(parameter: String, value: String) {
|
||||
add(parameter)
|
||||
add(value)
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addArgs(parameter: String, values: Iterable<String>) {
|
||||
values.forEach {
|
||||
addArg(parameter, it)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addArgIfNotNull(parameter: String, value: String?) {
|
||||
if (value != null) {
|
||||
addArg(parameter, value)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addKey(key: String, enabled: Boolean) {
|
||||
if (enabled) {
|
||||
add(key)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addFileArgs(parameter: String, values: FileCollection) {
|
||||
values.files.forEach {
|
||||
addArg(parameter, it.canonicalPath)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addFileArgs(parameter: String, values: Collection<FileCollection>) {
|
||||
values.forEach {
|
||||
addFileArgs(parameter, it)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addListArg(parameter: String, values: List<String>) {
|
||||
if (values.isNotEmpty()) {
|
||||
addArg(parameter, values.joinToString(separator = " "))
|
||||
}
|
||||
}
|
||||
// endregion
|
||||
|
||||
@TaskAction
|
||||
fun compile() {
|
||||
val output = outputFile.get()
|
||||
output.parentFile.mkdirs()
|
||||
|
||||
val args = mutableListOf<String>().apply {
|
||||
addArg("-o", outputFile.get().absolutePath)
|
||||
addKey("-opt", optimized)
|
||||
addKey("-g", debuggable)
|
||||
addKey("-ea", debuggable)
|
||||
addKey("-tr", processTests)
|
||||
|
||||
addArg("-target", target)
|
||||
addArg("-p", outputKind.name.toLowerCase())
|
||||
|
||||
add("-Xmulti-platform")
|
||||
|
||||
addAll(additionalCompilerOptions)
|
||||
|
||||
libraries.files.forEach { library ->
|
||||
library.parent?.let { addArg("-r", it) }
|
||||
addArg("-l", library.nameWithoutExtension)
|
||||
}
|
||||
|
||||
// TODO: Filter only kt files?
|
||||
addAll(sources.files.map { it.absolutePath })
|
||||
}
|
||||
|
||||
KonanCompilerRunner(project).run(args)
|
||||
}
|
||||
}
|
||||
|
||||
open class KonanCompilerDownloadTask : DefaultTask() {
|
||||
|
||||
internal companion object {
|
||||
|
||||
val simpleOsName: String = HostManager.simpleOsName()
|
||||
|
||||
val compilerDirectory: File
|
||||
get() = DependencyDirectories.localKonanDir.resolve("kotlin-native-$simpleOsName-$compilerVersion")
|
||||
|
||||
// TODO: Support project property for Kotlin/Native compiler version
|
||||
val compilerVersion: KonanVersion = KonanVersionImpl(MetaVersion.RELEASE, 0, 8, 2)
|
||||
|
||||
internal const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
|
||||
const val KONAN_DOWNLOAD_TASK_NAME = "checkNativeCompiler"
|
||||
}
|
||||
|
||||
private val useZip = HostManager.hostIsMingw
|
||||
|
||||
private val archiveExtension
|
||||
get() = if (useZip) {
|
||||
"zip"
|
||||
} else {
|
||||
"tar.gz"
|
||||
}
|
||||
|
||||
private fun archiveFileTree(archive: File): FileTree =
|
||||
if (useZip) {
|
||||
project.zipTree(archive)
|
||||
} else {
|
||||
project.tarTree(archive)
|
||||
}
|
||||
|
||||
private fun setupRepo(url: String): ArtifactRepository {
|
||||
return project.repositories.ivy { repo ->
|
||||
repo.setUrl(url)
|
||||
repo.layout("pattern") {
|
||||
val layout = it as IvyPatternRepositoryLayout
|
||||
layout.artifact("[artifact]-[revision].[ext]")
|
||||
}
|
||||
repo.metadataSources {
|
||||
it.artifact()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun removeRepo(repo: ArtifactRepository) {
|
||||
project.repositories.remove(repo)
|
||||
}
|
||||
|
||||
private fun downloadAndExtract() {
|
||||
val versionString = compilerVersion.toString()
|
||||
|
||||
val url = buildString {
|
||||
append("$BASE_DOWNLOAD_URL/")
|
||||
append(if (compilerVersion.meta == MetaVersion.DEV) "dev/" else "releases/")
|
||||
append("$versionString/")
|
||||
append(simpleOsName)
|
||||
}
|
||||
|
||||
val repo = setupRepo(url)
|
||||
|
||||
val compilerDependency = project.dependencies.create(
|
||||
mapOf(
|
||||
"name" to "kotlin-native-$simpleOsName",
|
||||
"version" to versionString,
|
||||
"ext" to archiveExtension
|
||||
)
|
||||
)
|
||||
|
||||
val configuration = project.configurations.detachedConfiguration(compilerDependency)
|
||||
val archive = configuration.files.single()
|
||||
|
||||
logger.info("Use Kotlin/Native compiler archive: ${archive.absolutePath}")
|
||||
logger.lifecycle("Unpack Kotlin/Native compiler (version $versionString)...")
|
||||
project.copy {
|
||||
it.from(archiveFileTree(archive))
|
||||
it.into(DependencyDirectories.localKonanDir)
|
||||
}
|
||||
|
||||
removeRepo(repo)
|
||||
|
||||
}
|
||||
|
||||
|
||||
@TaskAction
|
||||
fun checkCompiler() {
|
||||
if (!project.hasProperty(KotlinNativeProjectProperty.DOWNLOAD_COMPILER)) {
|
||||
val konanHome = project.getProperty(KotlinNativeProjectProperty.KONAN_HOME)
|
||||
logger.info("Use a user-defined compiler path: $konanHome")
|
||||
} else {
|
||||
if (!compilerDirectory.exists()) {
|
||||
downloadAndExtract()
|
||||
}
|
||||
logger.info("Use Kotlin/Native distribution: $compilerDirectory")
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -49,6 +49,7 @@ include ":kotlin-build-common",
|
||||
":js:js.translator",
|
||||
":js:js.dce",
|
||||
":js:js.tests",
|
||||
":konan:konan-utils",
|
||||
":jps-plugin",
|
||||
":kotlin-jps-plugin",
|
||||
":core:descriptors",
|
||||
@@ -231,6 +232,7 @@ project(':compiler:ir.psi2ir').projectDir = "$rootDir/compiler/ir/ir.psi2ir" as
|
||||
project(':compiler:ir.ir2cfg').projectDir = "$rootDir/compiler/ir/ir.ir2cfg" as File
|
||||
project(':compiler:ir.backend.common').projectDir = "$rootDir/compiler/ir/backend.common" as File
|
||||
project(':compiler:backend.js').projectDir = "$rootDir/compiler/ir/backend.js" as File
|
||||
project(':konan:konan-utils').projectDir = "$rootDir/konan/utils" as File
|
||||
project(':kotlin-jps-plugin').projectDir = "$rootDir/prepare/jps-plugin" as File
|
||||
project(':idea:idea-android-output-parser').projectDir = "$rootDir/idea/idea-android/idea-android-output-parser" as File
|
||||
project(':plugins:android-extensions-compiler').projectDir = "$rootDir/plugins/android-extensions/android-extensions-compiler" as File
|
||||
|
||||
Reference in New Issue
Block a user