diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/file/File.kt b/konan/utils/src/org/jetbrains/kotlin/konan/file/File.kt similarity index 73% rename from konan/library-reader/src/org/jetbrains/kotlin/konan/file/File.kt rename to konan/utils/src/org/jetbrains/kotlin/konan/file/File.kt index 7cf765450ad..b72d17c5523 100644 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/file/File.kt +++ b/konan/utils/src/org/jetbrains/kotlin/konan/file/File.kt @@ -1,21 +1,27 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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.file +import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent import java.io.BufferedReader import java.io.InputStream import java.io.InputStreamReader +import java.io.RandomAccessFile +import java.lang.Exception +import java.net.URI +import java.nio.MappedByteBuffer +import java.nio.channels.FileChannel import java.nio.file.* import java.nio.file.attribute.BasicFileAttributes data class File constructor(internal val javaPath: Path) { - constructor(parent: Path, child: String) : this(parent.resolve(child)) - constructor(parent: File, child: String) : this(parent.javaPath.resolve(child)) - constructor(path: String) : this(Paths.get(path)) - constructor(parent: String, child: String) : this(Paths.get(parent, child)) + constructor(parent: Path, child: String): this(parent.resolve(child)) + constructor(parent: File, child: String): this(parent.javaPath.resolve(child)) + constructor(path: String): this(Paths.get(path)) + constructor(parent: String, child: String): this(Paths.get(parent, child)) val path: String get() = javaPath.toString() @@ -24,7 +30,7 @@ data class File constructor(internal val javaPath: Path) { val absoluteFile: File get() = File(absolutePath) val name: String - get() = javaPath.fileName.toString() + get() = javaPath.fileName.toString().removeSuffixIfPresent("/") // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8153248 val extension: String get() = name.substringAfterLast('.', "") val parent: String @@ -59,13 +65,13 @@ data class File constructor(internal val javaPath: Path) { fun mkdirs() = Files.createDirectories(javaPath) fun delete() = Files.deleteIfExists(javaPath) - fun deleteRecursively() = postorder { Files.delete(it) } - fun deleteOnExitRecursively() = preorder { File(it).deleteOnExit() } + fun deleteRecursively() = postorder{Files.delete(it)} + fun deleteOnExitRecursively() = preorder{File(it).deleteOnExit()} fun preorder(task: (Path) -> Unit) { if (!this.exists) return - Files.walkFileTree(javaPath, object : SimpleFileVisitor() { + Files.walkFileTree(javaPath, object: SimpleFileVisitor() { override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult { task(file!!) return FileVisitResult.CONTINUE @@ -82,7 +88,7 @@ data class File constructor(internal val javaPath: Path) { fun postorder(task: (Path) -> Unit) { if (!this.exists) return - Files.walkFileTree(javaPath, object : SimpleFileVisitor() { + Files.walkFileTree(javaPath, object: SimpleFileVisitor() { override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult { task(file!!) return FileVisitResult.CONTINUE @@ -93,19 +99,27 @@ data class File constructor(internal val javaPath: Path) { return FileVisitResult.CONTINUE } }) + } + fun map(mode: FileChannel.MapMode = FileChannel.MapMode.READ_ONLY, + start: Long = 0, size: Long = -1): MappedByteBuffer { + val file = RandomAccessFile(path, + if (mode == FileChannel.MapMode.READ_ONLY) "r" else "rw") + val fileSize = if (mode == FileChannel.MapMode.READ_ONLY) + file.length() else size.also { assert(size != -1L) } + return file.channel.map(mode, start, fileSize) // Shall we .also { file.close() }? } fun deleteOnExit(): File { - // Works only on the default file system, + // Works only on the default file system, // but that's okay for now. javaPath.toFile().deleteOnExit() return this // Allow streaming. } - fun readBytes() = Files.readAllBytes(javaPath) fun writeBytes(bytes: ByteArray) = Files.write(javaPath, bytes) - fun appendBytes(bytes: ByteArray) = Files.write(javaPath, bytes, StandardOpenOption.APPEND) + fun appendBytes(bytes: ByteArray) + = Files.write(javaPath, bytes, StandardOpenOption.APPEND) fun writeLines(lines: Iterable) { Files.write(javaPath, lines) @@ -131,7 +145,6 @@ data class File constructor(internal val javaPath: Path) { // TODO: Consider removeing these after konanazing java.util.Properties. fun bufferedReader() = Files.newBufferedReader(javaPath) - fun outputStream() = Files.newOutputStream(javaPath) fun printWriter() = javaPath.toFile().printWriter() @@ -145,9 +158,10 @@ data class File constructor(internal val javaPath: Path) { val javaHome get() = File(System.getProperty("java.home")) val pathSeparator = java.io.File.pathSeparator + val separator = java.io.File.separator } - fun readStrings() = mutableListOf().also { list -> forEachLine { list.add(it) } } + fun readStrings() = mutableListOf().also { list -> forEachLine{list.add(it)}} override fun equals(other: Any?): Boolean { val otherFile = other as? File ?: return false @@ -160,16 +174,18 @@ data class File constructor(internal val javaPath: Path) { fun String.File(): File = File(this) fun Path.File(): File = File(this) -fun createTempFile(name: String, suffix: String? = null) = Files.createTempFile(name, suffix).File() -fun createTempDir(name: String): File = Files.createTempDirectory(name).File() +fun createTempFile(name: String, suffix: String? = null) + = Files.createTempFile(name, suffix).File() +fun createTempDir(name: String): File + = Files.createTempDirectory(name).File() fun Path.recursiveCopyTo(destPath: Path) { val sourcePath = this - Files.walk(sourcePath).forEach next@{ oldPath -> + Files.walk(sourcePath).forEach next@ { oldPath -> val relative = sourcePath.relativize(oldPath) val destFs = destPath.getFileSystem() - // We are copying files between file systems, + // We are copying files between file systems, // so pass the relative path through the String. val newPath = destFs.getPath(destPath.toString(), relative.toString()) diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/file/ZipUtil.kt b/konan/utils/src/org/jetbrains/kotlin/konan/file/ZipUtil.kt similarity index 100% rename from konan/library-reader/src/org/jetbrains/kotlin/konan/file/ZipUtil.kt rename to konan/utils/src/org/jetbrains/kotlin/konan/file/ZipUtil.kt diff --git a/konan/library-reader/src/org/jetbrains/kotlin/konan/properties/Properties.kt b/konan/utils/src/org/jetbrains/kotlin/konan/properties/Properties.kt similarity index 52% rename from konan/library-reader/src/org/jetbrains/kotlin/konan/properties/Properties.kt rename to konan/utils/src/org/jetbrains/kotlin/konan/properties/Properties.kt index 5e1fdfb2f39..d3629ad6041 100644 --- a/konan/library-reader/src/org/jetbrains/kotlin/konan/properties/Properties.kt +++ b/konan/utils/src/org/jetbrains/kotlin/konan/properties/Properties.kt @@ -1,11 +1,12 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * 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.properties import org.jetbrains.kotlin.konan.file.* +import org.jetbrains.kotlin.konan.util.parseSpaceSeparatedArgs typealias Properties = java.util.Properties @@ -34,14 +35,28 @@ fun Properties.propertyString(key: String, suffix: String? = null): String? = ge * functionality borrowed from def file parser and unified for interop tool * and kotlin compiler. */ -fun Properties.propertyList(key: String, suffix: String? = null): List { +fun Properties.propertyList(key: String, suffix: String? = null, escapeInQuotes: Boolean = false): List { val value = this.getProperty(key.suffix(suffix)) ?: this.getProperty(key) if (value?.isBlank() == true) return emptyList() - - return value?.split(Regex("\\s+")) ?: emptyList() + return if (escapeInQuotes) value?.let { parseSpaceSeparatedArgs(it) } ?: emptyList() + else value?.split(Regex("\\s+")) ?: emptyList() } -fun Properties.hasProperty(key: String, suffix: String? = null): Boolean = this.getProperty(key.suffix(suffix)) != null +fun Properties.hasProperty(key: String, suffix: String? = null): Boolean + = this.getProperty(key.suffix(suffix)) != null -fun String.suffix(suf: String?): String = if (suf == null) this else "${this}.$suf" +fun String.suffix(suf: String?): String = + if (suf == null) this + else "${this}.$suf" +fun Properties.keepOnlyDefaultProfiles() { + val DEPENDENCY_PROFILES_KEY = "dependencyProfiles" + val dependencyProfiles = this.getProperty(DEPENDENCY_PROFILES_KEY) + if (dependencyProfiles != "default alt") + error("unexpected $DEPENDENCY_PROFILES_KEY value: expected 'default alt', got '$dependencyProfiles'") + + // Force build to use only 'default' profile: + this.setProperty(DEPENDENCY_PROFILES_KEY, "default") + // TODO: it actually affects only resolution made in :dependencies, + // that's why we assume that 'default' profile comes first (and check this above). +} diff --git a/konan/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt b/konan/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt new file mode 100644 index 00000000000..ce57133dd28 --- /dev/null +++ b/konan/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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.file.File +import org.jetbrains.kotlin.konan.properties.keepOnlyDefaultProfiles +import org.jetbrains.kotlin.konan.properties.loadProperties +import org.jetbrains.kotlin.konan.util.DependencyDirectories + +class Distribution( + private val onlyDefaultProfiles: Boolean = false, + private val konanHomeOverride: String? = null, + private val runtimeFileOverride: String? = null) { + + val localKonanDir = DependencyDirectories.localKonanDir + + private fun findKonanHome(): String { + if (konanHomeOverride != null) return konanHomeOverride + + val value = System.getProperty("konan.home", "dist") + val path = File(value).absolutePath + return path + } + + val konanHome = findKonanHome() + val konanSubdir = "$konanHome/konan" + val mainPropertyFileName = "$konanSubdir/konan.properties" + val experimentalEnabled by lazy { + File("$konanSubdir/experimentalTargetsEnabled").exists + } + + private fun propertyFilesFromConfigDir(configDir: String, genericName: String): List { + val directory = File(configDir, "platforms/$genericName") + return if (directory.exists && directory.isDirectory) + directory.listFiles + else + emptyList() + } + + private fun preconfiguredPropertyFiles(genericName: String) = + propertyFilesFromConfigDir(konanSubdir, genericName) + + private fun userPropertyFiles(genericName: String) = + propertyFilesFromConfigDir(localKonanDir.absolutePath, genericName) + + fun additionalPropertyFiles(genericName: String) = + preconfiguredPropertyFiles(genericName) + userPropertyFiles(genericName) + + val properties by lazy { + val loaded = File(mainPropertyFileName).loadProperties() + HostManager.knownTargetTemplates.forEach { + additionalPropertyFiles(it).forEach { + val additional = it.loadProperties() + loaded.putAll(additional) + } + } + if (onlyDefaultProfiles) { + loaded.keepOnlyDefaultProfiles() + } + loaded + } + + val klib = "$konanHome/klib" + val stdlib = "$klib/common/stdlib" + + fun defaultNatives(target: KonanTarget) = "$konanHome/konan/targets/${target.visibleName}/native" + + fun runtime(target: KonanTarget) = runtimeFileOverride ?: "$stdlib/targets/${target.visibleName}/native/runtime.bc" + + val launcherFiles = listOf("launcher.bc") + + val dependenciesDir = DependencyDirectories.defaultDependenciesRoot.absolutePath + + fun availableSubTarget(genericName: String) = + additionalPropertyFiles(genericName).map { it.name } +} + +fun buildDistribution(konanHomeOverride: String? = null) = Distribution(true, konanHomeOverride, null) + +fun customerDistribution(konanHomeOverride: String? = null) = Distribution(false, konanHomeOverride, null) \ No newline at end of file diff --git a/konan/utils/src/org/jetbrains/kotlin/konan/target/KonanTarget.kt b/konan/utils/src/org/jetbrains/kotlin/konan/target/KonanTarget.kt index 683f2023acc..cd048739c56 100644 --- a/konan/utils/src/org/jetbrains/kotlin/konan/target/KonanTarget.kt +++ b/konan/utils/src/org/jetbrains/kotlin/konan/target/KonanTarget.kt @@ -1,5 +1,5 @@ /* - * Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. */ @@ -7,18 +7,18 @@ package org.jetbrains.kotlin.konan.target import org.jetbrains.kotlin.konan.target.KonanTarget.* import org.jetbrains.kotlin.konan.util.Named +import java.io.Serializable +import java.lang.Exception -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 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) { @@ -32,44 +32,27 @@ enum class Architecture(val bitness: Int) { } 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 MINGW_X86 : KonanTarget("mingw_x86", Family.MINGW, Architecture.X86) - 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) + 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_X86 : KonanTarget( "mingw_x86", Family.MINGW, Architecture.X86) + object MINGW_X64 : KonanTarget( "mingw_x64", Family.MINGW, Architecture.X64) + object MACOS_X64 : KonanTarget( "macos_x64", Family.OSX, Architecture.X64) + object LINUX_ARM64 : KonanTarget( "linux_arm64", Family.LINUX, Architecture.ARM64) + 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) + class ZEPHYR(val subName: String, val genericName: String = "zephyr") : KonanTarget("${genericName}_$subName", Family.ZEPHYR, Architecture.ARM32) override fun toString() = name } -// TODO: need a better way to enumerated predefined targets. -object PredefinedKonanTargets { - - val ALL = listOf( - ANDROID_ARM32, ANDROID_ARM64, - IOS_ARM32, IOS_ARM64, IOS_X64, - LINUX_X64, LINUX_ARM32_HFP, LINUX_MIPS32, LINUX_MIPSEL32, - MINGW_X64, MINGW_X86, - MACOS_X64, - KonanTarget.WASM32 - ) - - private val ALL_BY_NAME = ALL.associate { it.name to it } - - fun getByName(name: String) = ALL_BY_NAME[name] -} - fun hostTargetSuffix(host: KonanTarget, target: KonanTarget) = if (target == host) host.name else "${host.name}-${target.name}" @@ -79,11 +62,11 @@ enum class CompilerOutputKind { }, DYNAMIC { override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}" - override fun prefix(target: KonanTarget?) = target!!.family.dynamicPrefix + 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 + override fun prefix(target: KonanTarget?) = "${target!!.family.staticPrefix}" }, FRAMEWORK { override fun suffix(target: KonanTarget?): String = ".framework" @@ -101,21 +84,13 @@ enum class CompilerOutputKind { interface TargetManager { val target: KonanTarget - val targetName: String - fun list() + val targetName : String + fun list() : Unit val hostTargetSuffix: String val targetSuffix: String } -interface SubTargetProvider { - fun availableSubTarget(genericName: String): List -} - -private class NoSubTargets : SubTargetProvider { - override fun availableSubTarget(genericName: String): List = emptyList() -} - -private class TargetManagerImpl(val userRequest: String?, val hostManager: HostManager) : TargetManager { +private class TargetManagerImpl(val userRequest: String?, val hostManager: HostManager): TargetManager { override val target = determineCurrent() override val targetName get() = target.visibleName @@ -141,19 +116,30 @@ private class TargetManagerImpl(val userRequest: String?, val hostManager: HostM override val targetSuffix get() = target.name } -open class HostManager(subtargetProvider: SubTargetProvider = NoSubTargets()) { +open class HostManager(protected val distribution: Distribution = Distribution(), experimental: Boolean = false) { fun targetManager(userRequest: String? = null): TargetManager = TargetManagerImpl(userRequest, this) - private val zephyrSubtargets = subtargetProvider.availableSubTarget("zephyr").map { ZEPHYR(it) } + // TODO: need a better way to enumerated predefined targets. + private val predefinedTargets = listOf( + ANDROID_ARM32, ANDROID_ARM64, + IOS_ARM32, IOS_ARM64, IOS_X64, + LINUX_X64, LINUX_ARM32_HFP, LINUX_ARM64, LINUX_MIPS32, LINUX_MIPSEL32, + MINGW_X64, MINGW_X86, + MACOS_X64, + WASM32) + + private val zephyrSubtargets = distribution.availableSubTarget("zephyr").map { ZEPHYR(it) } + + private val experimentalEnabled = experimental || distribution.experimentalEnabled private val configurableSubtargets = zephyrSubtargets val targetValues: List by lazy { - PredefinedKonanTargets.ALL + configurableSubtargets + predefinedTargets + configurableSubtargets } - val targets = targetValues.associate { it.visibleName to it } + val targets = targetValues.associate{ it.visibleName to it } fun toKonanTargets(names: Iterable): List { return names.map { @@ -171,44 +157,74 @@ open class HostManager(subtargetProvider: SubTargetProvider = NoSubTargets()) { fun targetByName(name: String): KonanTarget { if (name == "host") return host - return targets[resolveAlias(name)] ?: throw TargetSupportException("Unknown target name: $name") + val target = targets[resolveAlias(name)] + if (target == null) throw TargetSupportException("Unknown target name: $name") + return target } - val enabled: List by lazy { - enabledTargetsByHost[host]?.toList() ?: throw TargetSupportException("Unknown host platform: $host") - } - - val enabledTargetsByHost = mapOf( - KonanTarget.LINUX_X64 to setOf( - 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 to setOf( - KonanTarget.MINGW_X64, - KonanTarget.MINGW_X86, - KonanTarget.WASM32, - KonanTarget.LINUX_X64, - KonanTarget.LINUX_ARM32_HFP, - KonanTarget.ANDROID_ARM32 - ) + zephyrSubtargets, - KonanTarget.MACOS_X64 to setOf( - KonanTarget.MACOS_X64, - KonanTarget.IOS_ARM32, - KonanTarget.IOS_ARM64, - KonanTarget.IOS_X64, - KonanTarget.LINUX_X64, - KonanTarget.LINUX_ARM32_HFP, - KonanTarget.ANDROID_ARM32, - KonanTarget.ANDROID_ARM64, - KonanTarget.WASM32 - ) + zephyrSubtargets + val enabledRegularByHost: Map> = mapOf( + LINUX_X64 to setOf( + LINUX_X64, + LINUX_ARM32_HFP, + LINUX_ARM64, + LINUX_MIPS32, + LINUX_MIPSEL32, + ANDROID_ARM32, + ANDROID_ARM64, + WASM32 + ), + MINGW_X64 to setOf( + MINGW_X64, + MINGW_X86, + LINUX_X64, + LINUX_ARM32_HFP, + LINUX_ARM64, + ANDROID_ARM32, + // TODO: toolchain to be fixed for that to work. + // ANDROID_ARM64, + WASM32 + ), + MACOS_X64 to setOf( + MACOS_X64, + IOS_ARM32, + IOS_ARM64, + IOS_X64, + LINUX_X64, + LINUX_ARM32_HFP, + LINUX_ARM64, + ANDROID_ARM32, + ANDROID_ARM64, + WASM32 + ) ) + val enabledExperimentalByHost: Map> = mapOf( + LINUX_X64 to setOf(MINGW_X86, MINGW_X64) + zephyrSubtargets, + MACOS_X64 to setOf(MINGW_X86, MINGW_X64) + zephyrSubtargets, + MINGW_X64 to setOf() + zephyrSubtargets + ) + + val enabledByHost: Map> by lazy { + val result = enabledRegularByHost.toMutableMap() + if (experimentalEnabled) { + enabledExperimentalByHost.forEach { (k, v) -> + result.merge(k, v) { old, new -> old + new } + } + } + result.toMap() + } + + val enabledRegular: List by lazy { + enabledRegularByHost[host]?.toList() ?: throw TargetSupportException("Unknown host platform: $host") + } + + val enabledExperimental: List by lazy { + enabledExperimentalByHost[host]?.toList() ?: throw TargetSupportException("Unknown host platform: $host") + } + + val enabled : List + get() = if (experimentalEnabled) enabledRegular + enabledExperimental else enabledRegular + fun isEnabled(target: KonanTarget) = enabled.contains(target) companion object { @@ -218,7 +234,7 @@ open class HostManager(subtargetProvider: SubTargetProvider = NoSubTargets()) { javaOsName == "Mac OS X" -> "osx" javaOsName == "Linux" -> "linux" javaOsName.startsWith("Windows") -> "windows" - else -> throw TargetSupportException("Unknown operating system: $javaOsName") + else -> throw TargetSupportException("Unknown operating system: ${javaOsName}") } } @@ -229,10 +245,10 @@ open class HostManager(subtargetProvider: SubTargetProvider = NoSubTargets()) { } val jniHostPlatformIncludeDir: String - get() = when (host) { + get() = when(host) { KonanTarget.MACOS_X64 -> "darwin" KonanTarget.LINUX_X64 -> "linux" - KonanTarget.MINGW_X64 -> "win32" + KonanTarget.MINGW_X64 ->"win32" else -> throw TargetSupportException("Unknown host: $host.") } @@ -240,48 +256,51 @@ open class HostManager(subtargetProvider: SubTargetProvider = NoSubTargets()) { 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") + "amd64" -> "x86_64" + "arm64" -> "arm64" + else -> throw TargetSupportException("Unknown hardware platform: ${javaArch}") } } val host: KonanTarget = when (host_os()) { - "osx" -> KonanTarget.MACOS_X64 + "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) + // Note Hotspot-specific VM option enforcing C1-only, critical for decent compilation speed. + val defaultJvmArgs = listOf("-XX:TieredStopAtLevel=1", "-ea", "-Dfile.encoding=UTF-8") + val regularJvmArgs = defaultJvmArgs + "-Xmx3G" + + val hostIsMac = (host.family == Family.OSX) + val hostIsLinux = (host.family == Family.LINUX) + val hostIsMingw = (host.family == Family.MINGW) val hostSuffix get() = host.name @JvmStatic - val hostName - get() = host.name + 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", + "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" + "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> by lazy { val result = mutableMapOf>() targetAliasResolutions.entries.forEach { - result.getOrPut(it.value, { mutableListOf() }).add(it.key) + result.getOrPut(it.value, { mutableListOf() } ).add(it.key) } result } @@ -292,10 +311,13 @@ open class HostManager(subtargetProvider: SubTargetProvider = NoSubTargets()) { } } +/** + * Name of a preset used in the 'kotlin-multiplatform' Gradle plugin to represent this target. + */ val KonanTarget.presetName: String get() = when (this) { - KonanTarget.ANDROID_ARM32 -> "androidNativeArm32" - KonanTarget.ANDROID_ARM64 -> "androidNativeArm64" + ANDROID_ARM32 -> "androidNativeArm32" + ANDROID_ARM64 -> "androidNativeArm64" else -> evaluatePresetName(this.name) } @@ -304,4 +326,4 @@ private fun evaluatePresetName(targetName: String): String { return nameParts.asSequence().drop(1).joinToString("", nameParts.firstOrNull().orEmpty(), transform = String::capitalize) } -class TargetSupportException(message: String = "", cause: Throwable? = null) : Exception(message, cause) \ No newline at end of file +class TargetSupportException (message: String = "", cause: Throwable? = null) : Exception(message, cause) \ No newline at end of file diff --git a/konan/utils/src/org/jetbrains/kotlin/konan/util/Util.kt b/konan/utils/src/org/jetbrains/kotlin/konan/util/Util.kt new file mode 100644 index 00000000000..2484b2c3488 --- /dev/null +++ b/konan/utils/src/org/jetbrains/kotlin/konan/util/Util.kt @@ -0,0 +1,79 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors. + * 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 kotlin.system.measureTimeMillis +import org.jetbrains.kotlin.konan.file.* +import java.lang.StringBuilder + +fun printMillisec(message: String, body: () -> T): T { + var result: T? = null + val msec = measureTimeMillis{ + result = body() + } + println("$message: $msec msec") + return result!! +} + +fun profile(message: String, body: () -> Unit) = profileIf( + System.getProperty("konan.profile")?.equals("true") ?: false, + message, body) + +fun profileIf(condition: Boolean, message: String, body: () -> Unit) = + if (condition) printMillisec(message, body) else body() + +fun nTabs(amount: Int): String { + return String.format("%1$-${(amount+1)*4}s", "") +} + +fun String.prefixIfNot(prefix: String) = + if (this.startsWith(prefix)) this else "$prefix$this" + +fun String.prefixBaseNameIfNot(prefix: String): String { + val file = File(this).absoluteFile + val name = file.name + val directory = file.parent + return "$directory/${name.prefixIfNot(prefix)}" +} + +fun String.suffixIfNot(suffix: String) = + if (this.endsWith(suffix)) this else "$this$suffix" + +fun String.removeSuffixIfPresent(suffix: String) = + if (this.endsWith(suffix)) this.dropLast(suffix.length) else this + +fun Lazy.getValueOrNull(): T? = if (isInitialized()) value else null + +fun parseSpaceSeparatedArgs(argsString: String): List { + val parsedArgs = mutableListOf() + var inQuotes = false + var currentCharSequence = StringBuilder() + fun saveArg() { + if (!currentCharSequence.isEmpty()) { + parsedArgs.add(currentCharSequence.toString()) + currentCharSequence = StringBuilder() + } + } + argsString.forEach { char -> + if (char == '"') { + inQuotes = !inQuotes + // Save value which was in quotes. + if (!inQuotes) { + saveArg() + } + } else if (char == ' ' && !inQuotes) { + // Space is separator. + saveArg() + } else { + currentCharSequence.append(char) + } + } + if (inQuotes) { + error("No close-quote was found in $currentCharSequence.") + } + saveArg() + return parsedArgs +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin/build.gradle.kts index 52b07c58b1a..025ac7f86ca 100644 --- a/libraries/tools/kotlin-gradle-plugin/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin/build.gradle.kts @@ -23,7 +23,6 @@ javadocJar() repositories { google() maven("https://plugins.gradle.org/m2/") - maven(kotlinNativeRepo) } pill { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt index f1dd4715899..ec00d388e8b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt @@ -95,7 +95,7 @@ class KotlinNativeTargetPreset( if (!konanTarget.enabledOnCurrentHost) { with(HostManager()) { - val supportedHosts = enabledTargetsByHost.filterValues { konanTarget in it }.keys + val supportedHosts = enabledByHost.filterValues { konanTarget in it }.keys val supportedHostsString = if (supportedHosts.size == 1) "a ${supportedHosts.single()} host" else