Split shared: Remove code copied to kotlin-native-utils
This commit is contained in:
committed by
Ilya Matveev
parent
873b40be80
commit
a89bfba751
@@ -1,233 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.konan.file
|
|
||||||
|
|
||||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole 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.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))
|
|
||||||
|
|
||||||
val path: String
|
|
||||||
get() = javaPath.toString()
|
|
||||||
val absolutePath: String
|
|
||||||
get() = javaPath.toAbsolutePath().toString()
|
|
||||||
val absoluteFile: File
|
|
||||||
get() = File(absolutePath)
|
|
||||||
val name: String
|
|
||||||
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
|
|
||||||
get() = javaPath.parent.toString()
|
|
||||||
val parentFile: File
|
|
||||||
get() = File(javaPath.parent)
|
|
||||||
|
|
||||||
val exists
|
|
||||||
get() = Files.exists(javaPath)
|
|
||||||
val isDirectory
|
|
||||||
get() = Files.isDirectory(javaPath)
|
|
||||||
val isFile
|
|
||||||
get() = Files.isRegularFile(javaPath)
|
|
||||||
val isAbsolute
|
|
||||||
get() = javaPath.isAbsolute()
|
|
||||||
val listFiles: List<File>
|
|
||||||
get() = Files.newDirectoryStream(javaPath).use { stream -> stream.map { File(it) } }
|
|
||||||
val listFilesOrEmpty: List<File>
|
|
||||||
get() = if (exists) listFiles else emptyList()
|
|
||||||
|
|
||||||
fun child(name: String) = File(this, name)
|
|
||||||
|
|
||||||
fun copyTo(destination: File) {
|
|
||||||
Files.copy(javaPath, destination.javaPath, StandardCopyOption.REPLACE_EXISTING)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun recursiveCopyTo(destination: File) {
|
|
||||||
val sourcePath = javaPath
|
|
||||||
val destPath = destination.javaPath
|
|
||||||
sourcePath.recursiveCopyTo(destPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun mkdirs() = Files.createDirectories(javaPath)
|
|
||||||
fun delete() = Files.deleteIfExists(javaPath)
|
|
||||||
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<Path>() {
|
|
||||||
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
|
|
||||||
task(file!!)
|
|
||||||
return FileVisitResult.CONTINUE
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun preVisitDirectory(dir: Path?, attrs: BasicFileAttributes?): FileVisitResult {
|
|
||||||
task(dir!!)
|
|
||||||
return FileVisitResult.CONTINUE
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun postorder(task: (Path) -> Unit) {
|
|
||||||
if (!this.exists) return
|
|
||||||
|
|
||||||
Files.walkFileTree(javaPath, object: SimpleFileVisitor<Path>() {
|
|
||||||
override fun visitFile(file: Path?, attrs: BasicFileAttributes?): FileVisitResult {
|
|
||||||
task(file!!)
|
|
||||||
return FileVisitResult.CONTINUE
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun postVisitDirectory(dir: Path?, exc: java.io.IOException?): FileVisitResult {
|
|
||||||
task(dir!!)
|
|
||||||
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,
|
|
||||||
// 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 writeLines(lines: Iterable<String>) {
|
|
||||||
Files.write(javaPath, lines)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun writeText(text: String): Unit = writeLines(listOf(text))
|
|
||||||
|
|
||||||
fun forEachLine(action: (String) -> Unit) {
|
|
||||||
Files.lines(javaPath).use { lines ->
|
|
||||||
lines.forEach { action(it) }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun createAsSymlink(target: String) {
|
|
||||||
val targetPath = Paths.get(target)
|
|
||||||
if (Files.isSymbolicLink(this.javaPath) && Files.readSymbolicLink(javaPath) == targetPath) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
Files.createSymbolicLink(this.javaPath, targetPath)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun toString() = 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()
|
|
||||||
|
|
||||||
companion object {
|
|
||||||
val userDir
|
|
||||||
get() = File(System.getProperty("user.dir"))
|
|
||||||
|
|
||||||
val userHome
|
|
||||||
get() = File(System.getProperty("user.home"))
|
|
||||||
|
|
||||||
val javaHome
|
|
||||||
get() = File(System.getProperty("java.home"))
|
|
||||||
val pathSeparator = java.io.File.pathSeparator
|
|
||||||
val separator = java.io.File.separator
|
|
||||||
}
|
|
||||||
|
|
||||||
fun readStrings() = mutableListOf<String>().also { list -> forEachLine{list.add(it)}}
|
|
||||||
|
|
||||||
override fun equals(other: Any?): Boolean {
|
|
||||||
val otherFile = other as? File ?: return false
|
|
||||||
return otherFile.javaPath.toAbsolutePath() == javaPath.toAbsolutePath()
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun hashCode() = javaPath.toAbsolutePath().hashCode()
|
|
||||||
}
|
|
||||||
|
|
||||||
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 Path.recursiveCopyTo(destPath: Path) {
|
|
||||||
val sourcePath = this
|
|
||||||
Files.walk(sourcePath).forEach next@ { oldPath ->
|
|
||||||
|
|
||||||
val relative = sourcePath.relativize(oldPath)
|
|
||||||
val destFs = destPath.getFileSystem()
|
|
||||||
// We are copying files between file systems,
|
|
||||||
// so pass the relative path through the String.
|
|
||||||
val newPath = destFs.getPath(destPath.toString(), relative.toString())
|
|
||||||
|
|
||||||
// File systems don't allow replacing an existing root.
|
|
||||||
if (newPath == newPath.getRoot()) return@next
|
|
||||||
if (Files.isDirectory(newPath)) {
|
|
||||||
Files.createDirectories(newPath)
|
|
||||||
} else {
|
|
||||||
Files.copy(oldPath, newPath, StandardCopyOption.REPLACE_EXISTING)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun bufferedReader(errorStream: InputStream?) = BufferedReader(InputStreamReader(errorStream))
|
|
||||||
|
|
||||||
// stdlib `use` function adapted for AutoCloseable.
|
|
||||||
inline fun <T : AutoCloseable?, R> T.use(block: (T) -> R): R {
|
|
||||||
var closed = false
|
|
||||||
try {
|
|
||||||
return block(this)
|
|
||||||
} catch (e: Exception) {
|
|
||||||
closed = true
|
|
||||||
try {
|
|
||||||
this?.close()
|
|
||||||
} catch (closeException: Exception) {
|
|
||||||
}
|
|
||||||
throw e
|
|
||||||
} finally {
|
|
||||||
if (!closed) {
|
|
||||||
this?.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,52 +0,0 @@
|
|||||||
package org.jetbrains.kotlin.konan.file
|
|
||||||
|
|
||||||
import java.net.URI
|
|
||||||
import java.nio.file.*
|
|
||||||
|
|
||||||
private val File.zipUri: URI
|
|
||||||
get() = URI.create("jar:${this.toPath().toUri()}")
|
|
||||||
|
|
||||||
fun File.zipFileSystem(mutable: Boolean = false): FileSystem {
|
|
||||||
val zipUri = this.zipUri
|
|
||||||
val attributes = hashMapOf("create" to mutable.toString())
|
|
||||||
return try {
|
|
||||||
FileSystems.newFileSystem(zipUri, attributes, null)
|
|
||||||
} catch (e: FileSystemAlreadyExistsException) {
|
|
||||||
FileSystems.getFileSystem(zipUri)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun FileSystem.file(file: File) = File(this.getPath(file.path))
|
|
||||||
|
|
||||||
fun FileSystem.file(path: String) = File(this.getPath(path))
|
|
||||||
|
|
||||||
private fun File.toPath() = Paths.get(this.path)
|
|
||||||
|
|
||||||
fun File.zipDirAs(unixFile: File) {
|
|
||||||
unixFile.withMutableZipFileSystem() {
|
|
||||||
this.recursiveCopyTo(it.file("/"))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Path.unzipTo(directory: Path) {
|
|
||||||
val zipUri = URI.create("jar:" + this.toUri())
|
|
||||||
FileSystems.newFileSystem(zipUri, emptyMap<String, Any?>(), null).use { zipfs ->
|
|
||||||
val zipPath = zipfs.getPath("/")
|
|
||||||
zipPath.recursiveCopyTo(directory)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> File.withZipFileSystem(mutable: Boolean = false, action: (FileSystem) -> T): T {
|
|
||||||
val zipFileSystem = this.zipFileSystem(mutable)
|
|
||||||
return try {
|
|
||||||
action(zipFileSystem)
|
|
||||||
} finally {
|
|
||||||
zipFileSystem.close()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun <T> File.withZipFileSystem(action: (FileSystem) -> T): T
|
|
||||||
= this.withZipFileSystem(false, action)
|
|
||||||
|
|
||||||
fun <T> File.withMutableZipFileSystem(action: (FileSystem) -> T): T
|
|
||||||
= this.withZipFileSystem(true, action)
|
|
||||||
@@ -1,94 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.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.DependencyProcessor
|
|
||||||
|
|
||||||
class Distribution(
|
|
||||||
private val onlyDefaultProfiles: Boolean = false,
|
|
||||||
private val konanHomeOverride: String? = null,
|
|
||||||
private val runtimeFileOverride: String? = null) {
|
|
||||||
|
|
||||||
val localKonanDir = DependencyProcessor.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<File> {
|
|
||||||
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 = DependencyProcessor.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)
|
|
||||||
@@ -1,342 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.konan.target
|
|
||||||
|
|
||||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
|
||||||
import org.jetbrains.kotlin.konan.util.Named
|
|
||||||
import java.io.Serializable
|
|
||||||
|
|
||||||
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),
|
|
||||||
X86(32),
|
|
||||||
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_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)
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
|
||||||
|
|
||||||
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(protected val distribution: Distribution = Distribution(), experimental: Boolean = false) {
|
|
||||||
|
|
||||||
fun targetManager(userRequest: String? = null): TargetManager = TargetManagerImpl(userRequest, this)
|
|
||||||
|
|
||||||
// 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<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 enabledRegularByHost: Map<KonanTarget, Set<KonanTarget>> = 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<KonanTarget, Set<KonanTarget>> = mapOf(
|
|
||||||
LINUX_X64 to setOf(MINGW_X86, MINGW_X64) + zephyrSubtargets,
|
|
||||||
MACOS_X64 to setOf(MINGW_X86, MINGW_X64) + zephyrSubtargets,
|
|
||||||
MINGW_X64 to setOf<KonanTarget>() + zephyrSubtargets
|
|
||||||
)
|
|
||||||
|
|
||||||
val enabledByHost: Map<KonanTarget, Set<KonanTarget>> 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<KonanTarget> by lazy {
|
|
||||||
enabledRegularByHost[host]?.toList() ?: throw TargetSupportException("Unknown host platform: $host")
|
|
||||||
}
|
|
||||||
|
|
||||||
val enabledExperimental: List<KonanTarget> by lazy {
|
|
||||||
enabledExperimentalByHost[host]?.toList() ?: throw TargetSupportException("Unknown host platform: $host")
|
|
||||||
}
|
|
||||||
|
|
||||||
val enabled : List<KonanTarget>
|
|
||||||
get() = if (experimentalEnabled) enabledRegular + enabledExperimental else enabledRegular
|
|
||||||
|
|
||||||
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()}")
|
|
||||||
}
|
|
||||||
|
|
||||||
// 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 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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Name of a preset used in the 'kotlin-multiplatform' Gradle plugin to represent this target.
|
|
||||||
*/
|
|
||||||
val KonanTarget.presetName: String
|
|
||||||
get() = when (this) {
|
|
||||||
ANDROID_ARM32 -> "androidNativeArm32"
|
|
||||||
ANDROID_ARM64 -> "androidNativeArm64"
|
|
||||||
else -> evaluatePresetName(this.name)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun evaluatePresetName(targetName: String): String {
|
|
||||||
val nameParts = targetName.split('_').mapNotNull { it.takeIf(String::isNotEmpty) }
|
|
||||||
return nameParts.asSequence().drop(1).joinToString("", nameParts.firstOrNull().orEmpty(), transform = String::capitalize)
|
|
||||||
}
|
|
||||||
|
|
||||||
class TargetSupportException (message: String = "", cause: Throwable? = null) : Exception(message, cause)
|
|
||||||
|
|
||||||
@@ -1,65 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.konan.properties
|
|
||||||
|
|
||||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.file.*
|
|
||||||
import org.jetbrains.kotlin.konan.util.parseSpaceSeparatedArgs
|
|
||||||
|
|
||||||
typealias Properties = java.util.Properties
|
|
||||||
|
|
||||||
fun File.loadProperties(): Properties {
|
|
||||||
val properties = java.util.Properties()
|
|
||||||
this.bufferedReader().use { reader ->
|
|
||||||
properties.load(reader)
|
|
||||||
}
|
|
||||||
return properties
|
|
||||||
}
|
|
||||||
|
|
||||||
fun loadProperties(path: String): Properties = File(path).loadProperties()
|
|
||||||
|
|
||||||
fun File.saveProperties(properties: Properties) {
|
|
||||||
this.outputStream().use {
|
|
||||||
properties.store(it, null)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun Properties.saveToFile(file: File) = file.saveProperties(this)
|
|
||||||
|
|
||||||
fun Properties.propertyString(key: String, suffix: String? = null): String? = getProperty(key.suffix(suffix)) ?: this.getProperty(key)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO: this method working with suffixes should be replaced with
|
|
||||||
* functionality borrowed from def file parser and unified for interop tool
|
|
||||||
* and kotlin compiler.
|
|
||||||
*/
|
|
||||||
fun Properties.propertyList(key: String, suffix: String? = null, escapeInQuotes: Boolean = false): List<String> {
|
|
||||||
val value = this.getProperty(key.suffix(suffix)) ?: this.getProperty(key)
|
|
||||||
if (value?.isBlank() == true) return 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 String.suffix(suf: String?): String =
|
|
||||||
if (suf == null) this
|
|
||||||
else "${this}.$suf"
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,93 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2017 JetBrains s.r.o.
|
|
||||||
*
|
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
|
||||||
* you may not use this file except in compliance with the License.
|
|
||||||
* You may obtain a copy of the License at
|
|
||||||
*
|
|
||||||
* http://www.apache.org/licenses/LICENSE-2.0
|
|
||||||
*
|
|
||||||
* Unless required by applicable law or agreed to in writing, software
|
|
||||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
|
||||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
||||||
* See the License for the specific language governing permissions and
|
|
||||||
* limitations under the License.
|
|
||||||
*/
|
|
||||||
|
|
||||||
package org.jetbrains.kotlin.konan.util
|
|
||||||
|
|
||||||
import kotlin.system.measureTimeMillis
|
|
||||||
import org.jetbrains.kotlin.konan.file.*
|
|
||||||
import java.lang.StringBuilder
|
|
||||||
|
|
||||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function:
|
|
||||||
fun <T> printMillisec(message: String, body: () -> T): T {
|
|
||||||
var result: T? = null
|
|
||||||
val msec = measureTimeMillis{
|
|
||||||
result = body()
|
|
||||||
}
|
|
||||||
println("$message: $msec msec")
|
|
||||||
return result!!
|
|
||||||
}
|
|
||||||
|
|
||||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function:
|
|
||||||
fun profile(message: String, body: () -> Unit) = profileIf(
|
|
||||||
System.getProperty("konan.profile")?.equals("true") ?: false,
|
|
||||||
message, body)
|
|
||||||
|
|
||||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this function:
|
|
||||||
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 <T> Lazy<T>.getValueOrNull(): T? = if (isInitialized()) value else null
|
|
||||||
|
|
||||||
fun parseSpaceSeparatedArgs(argsString: String): List<String> {
|
|
||||||
val parsedArgs = mutableListOf<String>()
|
|
||||||
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
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user