[K/N lib] add Kotlin/Native deserializer and library reader
This commit is contained in:
committed by
Mikhail Glukhikh
parent
fade311b92
commit
51bb408c56
@@ -8,8 +8,7 @@ description = "Kotlin/Native metadata"
|
||||
jvmTarget = "1.6"
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:serialization"))
|
||||
compile(project(":konan:konan-utils"))
|
||||
compile(project(":core:metadata"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
plugins {
|
||||
kotlin("jvm")
|
||||
id("jps-compatible")
|
||||
}
|
||||
|
||||
description = "Kotlin/Native deserializer and library reader"
|
||||
|
||||
jvmTarget = "1.6"
|
||||
|
||||
dependencies {
|
||||
compile(project(":compiler:frontend"))
|
||||
compile(project(":compiler:frontend.java"))
|
||||
compile(project(":konan:konan-metadata"))
|
||||
compile(project(":konan:konan-utils"))
|
||||
}
|
||||
|
||||
sourceSets {
|
||||
"main" { projectDefault() }
|
||||
"test" {}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
/*
|
||||
* 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.builtins.konan
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
class KonanBuiltIns(storageManager: StorageManager) : KotlinBuiltIns(storageManager) {
|
||||
|
||||
override fun getSuspendFunction(parameterCount: Int) =
|
||||
getBuiltInClassByName(Name.identifier("SuspendFunction$parameterCount"))
|
||||
}
|
||||
+37
@@ -0,0 +1,37 @@
|
||||
/*
|
||||
* 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.descriptors.konan
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
interface KonanModuleDescriptorFactory {
|
||||
|
||||
/**
|
||||
* Base method for creation of any Kotlin/Native [ModuleDescriptor].
|
||||
*/
|
||||
fun createDescriptor(
|
||||
name: Name,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns,
|
||||
origin: KonanModuleOrigin,
|
||||
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
|
||||
): ModuleDescriptorImpl
|
||||
|
||||
/**
|
||||
* Please use this method with care: As far as it creates an instance of [KotlinBuiltIns] it should be
|
||||
* normally used for creation of the very first (e.g. "stdlib") module in the set of created modules.
|
||||
*/
|
||||
fun createDescriptorAndNewBuiltIns(
|
||||
name: Name,
|
||||
storageManager: StorageManager,
|
||||
origin: KonanModuleOrigin,
|
||||
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?> = emptyMap()
|
||||
): ModuleDescriptorImpl
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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.descriptors.konan
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private val STDLIB_MODULE_NAME = Name.special("<$KONAN_STDLIB_NAME>")
|
||||
|
||||
fun ModuleDescriptor.isKonanStdlib() = name == STDLIB_MODULE_NAME
|
||||
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.descriptors.konan
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
|
||||
sealed class KonanModuleOrigin {
|
||||
|
||||
companion object {
|
||||
val CAPABILITY = ModuleDescriptor.Capability<KonanModuleOrigin>("KonanModuleOrigin")
|
||||
}
|
||||
}
|
||||
|
||||
sealed class CompiledKonanModuleOrigin: KonanModuleOrigin()
|
||||
|
||||
class DeserializedKonanModuleOrigin(val library: KonanLibrary) : CompiledKonanModuleOrigin()
|
||||
|
||||
object CurrentKonanModuleOrigin: CompiledKonanModuleOrigin()
|
||||
|
||||
object SyntheticModulesOrigin : KonanModuleOrigin()
|
||||
|
||||
val ModuleDescriptor.konanModuleOrigin get() = this.getCapability(KonanModuleOrigin.CAPABILITY)!!
|
||||
+46
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
* 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.descriptors.konan.impl
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
|
||||
import org.jetbrains.kotlin.descriptors.konan.KonanModuleOrigin
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal object KonanModuleDescriptorFactoryImpl : KonanModuleDescriptorFactory {
|
||||
|
||||
override fun createDescriptor(
|
||||
name: Name,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns,
|
||||
origin: KonanModuleOrigin,
|
||||
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
|
||||
) = ModuleDescriptorImpl(
|
||||
name,
|
||||
storageManager,
|
||||
builtIns,
|
||||
capabilities = customCapabilities + mapOf(KonanModuleOrigin.CAPABILITY to origin)
|
||||
)
|
||||
|
||||
override fun createDescriptorAndNewBuiltIns(
|
||||
name: Name,
|
||||
storageManager: StorageManager,
|
||||
origin: KonanModuleOrigin,
|
||||
customCapabilities: Map<ModuleDescriptor.Capability<*>, Any?>
|
||||
): ModuleDescriptorImpl {
|
||||
|
||||
val builtIns = KonanBuiltIns(storageManager)
|
||||
|
||||
val moduleDescriptor = createDescriptor(name, storageManager, builtIns, origin, customCapabilities)
|
||||
builtIns.builtInsModule = moduleDescriptor
|
||||
|
||||
return moduleDescriptor
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,70 @@
|
||||
/*
|
||||
* 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.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jetbrains.kotlin.konan.properties.propertyList
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
const val KLIB_PROPERTY_ABI_VERSION = "abi_version"
|
||||
const val KLIB_PROPERTY_UNIQUE_NAME = "unique_name"
|
||||
const val KLIB_PROPERTY_LINKED_OPTS = "linkerOpts"
|
||||
const val KLIB_PROPERTY_DEPENDS = "depends"
|
||||
const val KLIB_PROPERTY_INTEROP = "interop"
|
||||
const val KLIB_PROPERTY_PACKAGE = "package"
|
||||
const val KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations"
|
||||
const val KLIB_PROPERTY_INCLUDED_HEADERS = "includedHeaders"
|
||||
|
||||
/**
|
||||
* An abstraction for getting access to the information stored inside of Kotlin/Native library.
|
||||
*/
|
||||
interface KonanLibrary {
|
||||
|
||||
val libraryName: String
|
||||
val libraryFile: File
|
||||
|
||||
// Whether this library is default (provided by Kotlin/Native distribution)?
|
||||
val isDefault: Boolean
|
||||
|
||||
// Properties:
|
||||
val manifestProperties: Properties
|
||||
val abiVersion: String
|
||||
val linkerOpts: List<String>
|
||||
|
||||
// Paths:
|
||||
val bitcodePaths: List<String>
|
||||
val includedPaths: List<String>
|
||||
|
||||
val targetList: List<String>
|
||||
|
||||
val dataFlowGraph: ByteArray?
|
||||
val moduleHeaderData: ByteArray
|
||||
fun packageMetadata(fqName: String): ByteArray
|
||||
}
|
||||
|
||||
val KonanLibrary.uniqueName
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_UNIQUE_NAME)!!
|
||||
|
||||
val KonanLibrary.unresolvedDependencies: List<String>
|
||||
get() = manifestProperties.propertyList(KLIB_PROPERTY_DEPENDS)
|
||||
|
||||
val KonanLibrary.isInterop
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_INTEROP) == "true"
|
||||
|
||||
val KonanLibrary.packageFqName
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_PACKAGE)?.let { FqName(it) }
|
||||
|
||||
val KonanLibrary.exportForwardDeclarations
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS)
|
||||
.split(' ').asSequence()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.map { FqName(it) }
|
||||
.toList()
|
||||
|
||||
val KonanLibrary.includedHeaders
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_INCLUDED_HEADERS).split(' ')
|
||||
@@ -0,0 +1,48 @@
|
||||
/*
|
||||
* 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.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
/**
|
||||
* This scheme describes the Kotlin/Native Library (KLIB) layout.
|
||||
*/
|
||||
interface KonanLibraryLayout {
|
||||
|
||||
val libraryName: String
|
||||
|
||||
val libDir: File
|
||||
val target: KonanTarget?
|
||||
// This is a default implementation. Can't make it an assignment.
|
||||
get() = null
|
||||
|
||||
val manifestFile
|
||||
get() = File(libDir, "manifest")
|
||||
val resourcesDir
|
||||
get() = File(libDir, "resources")
|
||||
|
||||
val targetsDir
|
||||
get() = File(libDir, "targets")
|
||||
val targetDir
|
||||
get() = File(targetsDir, target!!.visibleName)
|
||||
|
||||
val kotlinDir
|
||||
get() = File(targetDir, "kotlin")
|
||||
val nativeDir
|
||||
get() = File(targetDir, "native")
|
||||
val includedDir
|
||||
get() = File(targetDir, "included")
|
||||
|
||||
val linkdataDir
|
||||
get() = File(libDir, "linkdata")
|
||||
val moduleHeaderFile
|
||||
get() = File(linkdataDir, "module")
|
||||
val dataFlowGraphFile
|
||||
get() = File(linkdataDir, "module_data_flow_graph")
|
||||
|
||||
fun packageFile(packageName: String) = File(linkdataDir, if (packageName == "") "root_package.knm" else "package_$packageName.knm")
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.impl.DefaultMetadataReaderImpl
|
||||
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
|
||||
import org.jetbrains.kotlin.konan.library.impl.zippedKonanLibraryChecks
|
||||
import org.jetbrains.kotlin.konan.library.impl.zippedKonanLibraryRoot
|
||||
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolver
|
||||
import org.jetbrains.kotlin.konan.library.resolver.impl.KonanLibraryResolverImpl
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
fun File.unpackZippedKonanLibraryTo(newDir: File) {
|
||||
|
||||
// First, run validity checks for the given KLIB file.
|
||||
zippedKonanLibraryChecks(this)
|
||||
|
||||
if (newDir.exists) {
|
||||
if (newDir.isDirectory)
|
||||
newDir.deleteRecursively()
|
||||
else
|
||||
newDir.delete()
|
||||
}
|
||||
|
||||
zippedKonanLibraryRoot(this).recursiveCopyTo(newDir)
|
||||
check(newDir.exists) { "Could not unpack $this as $newDir." }
|
||||
}
|
||||
|
||||
fun createKonanLibrary(
|
||||
libraryFile: File,
|
||||
currentAbiVersion: Int,
|
||||
target: KonanTarget? = null,
|
||||
isDefault: Boolean = false,
|
||||
metadataReader: MetadataReader = DefaultMetadataReaderImpl
|
||||
): KonanLibrary = KonanLibraryImpl(libraryFile, currentAbiVersion, target, isDefault, metadataReader)
|
||||
|
||||
fun SearchPathResolverWithTarget.libraryResolver(abiVersion: Int): KonanLibraryResolver =
|
||||
KonanLibraryResolverImpl(this, abiVersion)
|
||||
@@ -0,0 +1,11 @@
|
||||
/*
|
||||
* 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.library
|
||||
|
||||
interface MetadataReader {
|
||||
fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
|
||||
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String): ByteArray
|
||||
}
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.library.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
|
||||
import org.jetbrains.kotlin.konan.library.MetadataReader
|
||||
|
||||
internal object DefaultMetadataReaderImpl : MetadataReader {
|
||||
|
||||
override fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray =
|
||||
libraryLayout.moduleHeaderFile.readBytes()
|
||||
|
||||
override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String): ByteArray =
|
||||
libraryLayout.packageFile(fqName).readBytes()
|
||||
}
|
||||
@@ -0,0 +1,71 @@
|
||||
/*
|
||||
* 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.library.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.KLIB_PROPERTY_ABI_VERSION
|
||||
import org.jetbrains.kotlin.konan.library.KLIB_PROPERTY_LINKED_OPTS
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.MetadataReader
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jetbrains.kotlin.konan.properties.loadProperties
|
||||
import org.jetbrains.kotlin.konan.properties.propertyList
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions
|
||||
import org.jetbrains.kotlin.konan.util.substitute
|
||||
|
||||
internal class KonanLibraryImpl(
|
||||
override val libraryFile: File,
|
||||
private val currentAbiVersion: Int,
|
||||
internal val target: KonanTarget?,
|
||||
override val isDefault: Boolean,
|
||||
private val metadataReader: MetadataReader
|
||||
) : KonanLibrary {
|
||||
|
||||
// For the zipped libraries inPlace gives files from zip file system
|
||||
// whereas realFiles extracts them to /tmp.
|
||||
// For unzipped libraries inPlace and realFiles are the same
|
||||
// providing files in the library directory.
|
||||
private val inPlace = createKonanLibraryLayout(libraryFile, target)
|
||||
private val realFiles = inPlace.realFiles
|
||||
|
||||
override val libraryName
|
||||
get() = inPlace.libraryName
|
||||
|
||||
override val manifestProperties: Properties by lazy {
|
||||
val properties = inPlace.manifestFile.loadProperties()
|
||||
if (target != null) substitute(properties, defaultTargetSubstitutions(target))
|
||||
properties
|
||||
}
|
||||
|
||||
override val abiVersion: String
|
||||
get() {
|
||||
val manifestAbiVersion = manifestProperties.getProperty(KLIB_PROPERTY_ABI_VERSION)
|
||||
check(currentAbiVersion.toString() == manifestAbiVersion) {
|
||||
"ABI version mismatch. Compiler expects: $currentAbiVersion, the library is $manifestAbiVersion"
|
||||
}
|
||||
return manifestAbiVersion
|
||||
}
|
||||
|
||||
override val linkerOpts: List<String>
|
||||
get() = manifestProperties.propertyList(KLIB_PROPERTY_LINKED_OPTS, target!!.visibleName)
|
||||
|
||||
override val bitcodePaths: List<String>
|
||||
get() = (realFiles.kotlinDir.listFilesOrEmpty + realFiles.nativeDir.listFilesOrEmpty).map { it.absolutePath }
|
||||
|
||||
override val includedPaths: List<String>
|
||||
get() = realFiles.includedDir.listFilesOrEmpty.map { it.absolutePath }
|
||||
|
||||
override val targetList by lazy { inPlace.targetsDir.listFiles.map { it.name } }
|
||||
|
||||
override val dataFlowGraph by lazy { inPlace.dataFlowGraphFile.let { if (it.exists) it.readBytes() else null } }
|
||||
|
||||
override val moduleHeaderData: ByteArray by lazy { metadataReader.loadSerializedModule(inPlace) }
|
||||
|
||||
override fun packageMetadata(fqName: String) = metadataReader.loadSerializedPackageFragment(inPlace, fqName)
|
||||
|
||||
override fun toString() = "$libraryName[default=$isDefault]"
|
||||
}
|
||||
+85
@@ -0,0 +1,85 @@
|
||||
/*
|
||||
* 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.library.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.file.asZipRoot
|
||||
import org.jetbrains.kotlin.konan.file.createTempDir
|
||||
import org.jetbrains.kotlin.konan.file.createTempFile
|
||||
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION
|
||||
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION_WITH_DOT
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
private class ZippedKonanLibraryLayout(val klibFile: File, override val target: KonanTarget?) : KonanLibraryLayout {
|
||||
|
||||
init {
|
||||
zippedKonanLibraryChecks(klibFile)
|
||||
}
|
||||
|
||||
override val libraryName = klibFile.path.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT)
|
||||
|
||||
override val libDir by lazy { zippedKonanLibraryRoot(klibFile) }
|
||||
}
|
||||
|
||||
internal fun zippedKonanLibraryChecks(klibFile: File) {
|
||||
check(klibFile.exists) { "Could not find $klibFile." }
|
||||
check(klibFile.isFile) { "Expected $klibFile to be a regular file." }
|
||||
|
||||
val extension = klibFile.extension
|
||||
check(extension.isEmpty() || extension == KLIB_FILE_EXTENSION) { "Unexpected file extension: $extension" }
|
||||
}
|
||||
|
||||
internal fun zippedKonanLibraryRoot(klibFile: File) = klibFile.asZipRoot
|
||||
|
||||
private class UnzippedKonanLibraryLayout(override val libDir: File, override val target: KonanTarget?) : KonanLibraryLayout {
|
||||
override val libraryName = libDir.path
|
||||
}
|
||||
|
||||
/**
|
||||
* This class automatically extracts pieces of the library on first access. Use it if you need
|
||||
* to pass extracted files to an external tool. Otherwise, stick to [ZippedKonanLibraryLayout].
|
||||
*/
|
||||
private class FileExtractor(zippedLibraryLayout: KonanLibraryLayout) : KonanLibraryLayout by zippedLibraryLayout {
|
||||
|
||||
override val manifestFile: File by lazy { extract(super.manifestFile) }
|
||||
|
||||
override val resourcesDir: File by lazy { extractDir(super.resourcesDir) }
|
||||
|
||||
override val includedDir: File by lazy { extractDir(super.includedDir) }
|
||||
|
||||
override val kotlinDir: File by lazy { extractDir(super.kotlinDir) }
|
||||
|
||||
override val nativeDir: File by lazy { extractDir(super.nativeDir) }
|
||||
|
||||
override val linkdataDir: File by lazy { extractDir(super.linkdataDir) }
|
||||
|
||||
fun extract(file: File): File {
|
||||
val temporary = createTempFile(file.name)
|
||||
file.copyTo(temporary)
|
||||
temporary.deleteOnExit()
|
||||
return temporary
|
||||
}
|
||||
|
||||
fun extractDir(directory: File): File {
|
||||
val temporary = createTempDir(directory.name)
|
||||
directory.recursiveCopyTo(temporary)
|
||||
temporary.deleteOnExitRecursively()
|
||||
return temporary
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createKonanLibraryLayout(klib: File, target: KonanTarget? = null) =
|
||||
if (klib.isFile) ZippedKonanLibraryLayout(klib, target) else UnzippedKonanLibraryLayout(klib, target)
|
||||
|
||||
internal val KonanLibraryLayout.realFiles
|
||||
get() = when (this) {
|
||||
is ZippedKonanLibraryLayout -> FileExtractor(this)
|
||||
// Unpacked library just provides its own files.
|
||||
is UnzippedKonanLibraryLayout -> this
|
||||
else -> error("Provide an extractor for your container.")
|
||||
}
|
||||
|
||||
+64
@@ -0,0 +1,64 @@
|
||||
/*
|
||||
* 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.library.resolver
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.SearchPathResolverWithTarget
|
||||
|
||||
typealias DuplicatedLibraryLogger = (String) -> Unit
|
||||
|
||||
interface KonanLibraryResolver {
|
||||
|
||||
val searchPathResolver: SearchPathResolverWithTarget
|
||||
val abiVersion: Int
|
||||
|
||||
/**
|
||||
* Given the list of Kotlin/Native library names, ABI version and other parameters
|
||||
* resolves libraries and evaluates dependencies between them.
|
||||
*/
|
||||
fun resolveWithDependencies(
|
||||
libraryNames: List<String>,
|
||||
noStdLib: Boolean = false,
|
||||
noDefaultLibs: Boolean = false,
|
||||
logger: DuplicatedLibraryLogger? = null
|
||||
): KonanLibraryResolveResult
|
||||
}
|
||||
|
||||
interface KonanLibraryResolveResult {
|
||||
|
||||
fun filterRoots(predicate: (KonanResolvedLibrary) -> Boolean): KonanLibraryResolveResult
|
||||
|
||||
fun getFullList(order: LibraryOrder? = null): List<KonanLibrary>
|
||||
|
||||
fun forEach(action: (KonanLibrary, PackageAccessedHandler) -> Unit)
|
||||
}
|
||||
|
||||
|
||||
typealias LibraryOrder = (Iterable<KonanResolvedLibrary>) -> List<KonanResolvedLibrary>
|
||||
|
||||
val TopologicalLibraryOrder: LibraryOrder = { input ->
|
||||
val sorted = mutableListOf<KonanResolvedLibrary>()
|
||||
val visited = mutableSetOf<KonanResolvedLibrary>()
|
||||
val tempMarks = mutableSetOf<KonanResolvedLibrary>()
|
||||
|
||||
fun visit(node: KonanResolvedLibrary, result: MutableList<KonanResolvedLibrary>) {
|
||||
if (visited.contains(node)) return
|
||||
if (tempMarks.contains(node)) error("Cyclic dependency in library graph.")
|
||||
tempMarks.add(node)
|
||||
node.resolvedDependencies.forEach {
|
||||
visit(it, result)
|
||||
}
|
||||
visited.add(node)
|
||||
result += node
|
||||
}
|
||||
|
||||
input.forEach next@{
|
||||
if (visited.contains(it)) return@next
|
||||
visit(it, sorted)
|
||||
}
|
||||
|
||||
sorted
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.library.resolver
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
interface PackageAccessedHandler {
|
||||
|
||||
fun markPackageAccessed(fqName: FqName)
|
||||
}
|
||||
|
||||
/**
|
||||
* A [KonanLibrary] wrapper that is used for resolving library's dependencies.
|
||||
*/
|
||||
interface KonanResolvedLibrary: PackageAccessedHandler {
|
||||
|
||||
// The library itself.
|
||||
val library: KonanLibrary
|
||||
|
||||
// Dependencies on other libraries.
|
||||
val resolvedDependencies: List<KonanResolvedLibrary>
|
||||
|
||||
// Whether it is needed to linker.
|
||||
val isNeededForLink: Boolean
|
||||
|
||||
// Is provided by the distribution?
|
||||
val isDefault: Boolean
|
||||
}
|
||||
+142
@@ -0,0 +1,142 @@
|
||||
/*
|
||||
* 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.library.resolver.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.SearchPathResolverWithTarget
|
||||
import org.jetbrains.kotlin.konan.library.createKonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.*
|
||||
import org.jetbrains.kotlin.konan.library.unresolvedDependencies
|
||||
|
||||
internal class KonanLibraryResolverImpl(
|
||||
override val searchPathResolver: SearchPathResolverWithTarget,
|
||||
override val abiVersion: Int
|
||||
) : KonanLibraryResolver {
|
||||
|
||||
override fun resolveWithDependencies(
|
||||
libraryNames: List<String>,
|
||||
noStdLib: Boolean,
|
||||
noDefaultLibs: Boolean,
|
||||
logger: DuplicatedLibraryLogger?
|
||||
) = findLibraries(libraryNames, noStdLib, noDefaultLibs)
|
||||
.leaveDistinct(logger)
|
||||
.resolveDependencies()
|
||||
|
||||
/**
|
||||
* Returns the list of libraries based on [libraryNames], [noStdLib] and [noDefaultLibs] criteria.
|
||||
*
|
||||
* This method does not return any libraries that might be available via transitive dependencies
|
||||
* from the original library set (root set).
|
||||
*/
|
||||
private fun findLibraries(
|
||||
libraryNames: List<String>,
|
||||
noStdLib: Boolean,
|
||||
noDefaultLibs: Boolean
|
||||
): List<KonanLibrary> {
|
||||
|
||||
val userProvidedLibraries = libraryNames.asSequence()
|
||||
.map { searchPathResolver.resolve(it) }
|
||||
.map { createKonanLibrary(it, abiVersion, searchPathResolver.target) }
|
||||
.toList()
|
||||
|
||||
val defaultLibraries = searchPathResolver.defaultLinks(noStdLib, noDefaultLibs).map {
|
||||
createKonanLibrary(it, abiVersion, searchPathResolver.target, isDefault = true)
|
||||
}
|
||||
|
||||
// Make sure the user provided ones appear first, so that
|
||||
// they have precedence over defaults when duplicates are eliminated.
|
||||
return userProvidedLibraries + defaultLibraries
|
||||
}
|
||||
|
||||
/**
|
||||
* Leaves only distinct libraries (by absolute path), warns on duplicated paths.
|
||||
*/
|
||||
private fun List<KonanLibrary>.leaveDistinct(logger: DuplicatedLibraryLogger?) =
|
||||
this.groupBy { it.libraryFile.absolutePath }.let { groupedByAbsolutePath ->
|
||||
warnOnLibraryDuplicates(groupedByAbsolutePath.filter { it.value.size > 1 }.keys, logger)
|
||||
groupedByAbsolutePath.map { it.value.first() }
|
||||
}
|
||||
|
||||
private fun warnOnLibraryDuplicates(duplicatedPaths: Iterable<String>, logger: DuplicatedLibraryLogger?) {
|
||||
if (logger == null) return
|
||||
duplicatedPaths.forEach { logger("library included more than once: $it") }
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Given the list of root libraries does the following:
|
||||
*
|
||||
* 1. Evaluates other libraries that are available via transitive dependencies.
|
||||
* 2. Wraps each [KonanLibrary] into a [KonanResolvedLibrary] with information about dependencies on other libraries.
|
||||
* 3. Creates resulting [KonanLibraryResolveResult] object.
|
||||
*/
|
||||
private fun List<KonanLibrary>.resolveDependencies(): KonanLibraryResolveResult {
|
||||
|
||||
val rootLibraries = this.map { KonanResolvedLibraryImpl(it) }
|
||||
|
||||
// As far as the list of root libraries is known from the very beginning, the result can be
|
||||
// constructed from the very beginning as well.
|
||||
val result = KonanLibraryResolverResultImpl(rootLibraries)
|
||||
|
||||
val cache = mutableMapOf<File, KonanResolvedLibrary>()
|
||||
cache.putAll(rootLibraries.map { it.library.libraryFile.absoluteFile to it })
|
||||
|
||||
var newDependencies = rootLibraries
|
||||
do {
|
||||
newDependencies = newDependencies.map { library: KonanResolvedLibraryImpl ->
|
||||
library.library.unresolvedDependencies.asSequence()
|
||||
.map { searchPathResolver.resolve(it).absoluteFile }
|
||||
.mapNotNull {
|
||||
if (it in cache) {
|
||||
library.addDependency(cache[it]!!)
|
||||
null
|
||||
} else {
|
||||
val newLibrary = KonanResolvedLibraryImpl(createKonanLibrary(it, abiVersion, searchPathResolver.target))
|
||||
cache[it] = newLibrary
|
||||
library.addDependency(newLibrary)
|
||||
newLibrary
|
||||
}
|
||||
}
|
||||
.toList()
|
||||
}.flatten()
|
||||
} while (newDependencies.isNotEmpty())
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal class KonanLibraryResolverResultImpl(
|
||||
private val roots: List<KonanResolvedLibrary>
|
||||
) : KonanLibraryResolveResult {
|
||||
|
||||
private val all: List<KonanResolvedLibrary> by lazy {
|
||||
val result = mutableSetOf<KonanResolvedLibrary>().also { it.addAll(roots) }
|
||||
|
||||
var newDependencies = result.toList()
|
||||
do {
|
||||
newDependencies = newDependencies
|
||||
.map { it -> it.resolvedDependencies }.flatten()
|
||||
.filter { it !in result }
|
||||
result.addAll(newDependencies)
|
||||
} while (newDependencies.isNotEmpty())
|
||||
|
||||
result.toList()
|
||||
}
|
||||
|
||||
override fun filterRoots(predicate: (KonanResolvedLibrary) -> Boolean) =
|
||||
KonanLibraryResolverResultImpl(roots.filter(predicate))
|
||||
|
||||
override fun getFullList(order: LibraryOrder?) = (order?.invoke(all) ?: all).asPlain()
|
||||
|
||||
override fun forEach(action: (KonanLibrary, PackageAccessedHandler) -> Unit) {
|
||||
all.forEach { action(it.library, it) }
|
||||
}
|
||||
|
||||
private fun List<KonanResolvedLibrary>.asPlain() = map { it.library }
|
||||
|
||||
override fun toString() = "roots=$roots, all=$all"
|
||||
}
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.library.resolver.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.KonanResolvedLibrary
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.konan.parseModuleHeader
|
||||
|
||||
internal class KonanResolvedLibraryImpl(
|
||||
override val library: KonanLibrary
|
||||
) : KonanResolvedLibrary {
|
||||
|
||||
private val _resolvedDependencies = mutableListOf<KonanResolvedLibrary>()
|
||||
private val _emptyPackages by lazy { parseModuleHeader(library.moduleHeaderData).emptyPackageList }
|
||||
|
||||
override val resolvedDependencies: List<KonanResolvedLibrary>
|
||||
get() = _resolvedDependencies
|
||||
|
||||
internal fun addDependency(resolvedLibrary: KonanResolvedLibrary) = _resolvedDependencies.add(resolvedLibrary)
|
||||
|
||||
override var isNeededForLink: Boolean = false
|
||||
private set
|
||||
|
||||
override val isDefault: Boolean
|
||||
get() = library.isDefault
|
||||
|
||||
override fun markPackageAccessed(fqName: FqName) {
|
||||
if (!isNeededForLink // fast path
|
||||
&& !_emptyPackages.contains(fqName.asString())
|
||||
) {
|
||||
isNeededForLink = true
|
||||
}
|
||||
}
|
||||
|
||||
override fun toString() = "library=$library, dependsOn=${_resolvedDependencies.joinToString { it.library.toString() }}"
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.utils
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
|
||||
import org.jetbrains.kotlin.descriptors.konan.impl.KonanModuleDescriptorFactoryImpl
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedModuleDescriptorFactory
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedPackageFragmentsFactory
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanResolvedModuleDescriptorsFactory
|
||||
import org.jetbrains.kotlin.serialization.konan.impl.KonanDeserializedModuleDescriptorFactoryImpl
|
||||
import org.jetbrains.kotlin.serialization.konan.impl.KonanDeserializedPackageFragmentsFactoryImpl
|
||||
import org.jetbrains.kotlin.serialization.konan.impl.KonanResolvedModuleDescriptorsFactoryImpl
|
||||
|
||||
/**
|
||||
* The default Kotlin/Native factories.
|
||||
*/
|
||||
object KonanFactories {
|
||||
|
||||
/**
|
||||
* The default [KonanModuleDescriptorFactory] factory instance.
|
||||
*/
|
||||
val DefaultDescriptorFactory: KonanModuleDescriptorFactory = KonanModuleDescriptorFactoryImpl
|
||||
|
||||
/**
|
||||
* The default [KonanDeserializedPackageFragmentsFactory] factory instance.
|
||||
*/
|
||||
val DefaultPackageFragmentsFactory: KonanDeserializedPackageFragmentsFactory =
|
||||
KonanDeserializedPackageFragmentsFactoryImpl
|
||||
|
||||
/**
|
||||
* The default [KonanDeserializedModuleDescriptorFactory] factory instance.
|
||||
*/
|
||||
val DefaultDeserializedDescriptorFactory: KonanDeserializedModuleDescriptorFactory =
|
||||
createDefaultKonanDeserializedModuleDescriptorFactory(
|
||||
DefaultDescriptorFactory, DefaultPackageFragmentsFactory
|
||||
)
|
||||
|
||||
/**
|
||||
* The default [KonanResolvedModuleDescriptorsFactory] factory instance.
|
||||
*/
|
||||
val DefaultResolvedDescriptorsFactory: KonanResolvedModuleDescriptorsFactory =
|
||||
createDefaultKonanResolvedModuleDescriptorsFactory(DefaultDeserializedDescriptorFactory)
|
||||
|
||||
fun createDefaultKonanDeserializedModuleDescriptorFactory(
|
||||
descriptorFactory: KonanModuleDescriptorFactory,
|
||||
packageFragmentsFactory: KonanDeserializedPackageFragmentsFactory
|
||||
): KonanDeserializedModuleDescriptorFactory =
|
||||
KonanDeserializedModuleDescriptorFactoryImpl(descriptorFactory, packageFragmentsFactory)
|
||||
|
||||
fun createDefaultKonanResolvedModuleDescriptorsFactory(
|
||||
moduleDescriptorFactory: KonanDeserializedModuleDescriptorFactory
|
||||
): KonanResolvedModuleDescriptorsFactory = KonanResolvedModuleDescriptorsFactoryImpl(moduleDescriptorFactory)
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
/*
|
||||
* 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.resolve.konan.platform
|
||||
|
||||
import org.jetbrains.kotlin.resolve.ImportPath
|
||||
import org.jetbrains.kotlin.resolve.MultiTargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.PlatformConfigurator
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
object KonanPlatform : TargetPlatform("Konan") {
|
||||
|
||||
override fun computePlatformSpecificDefaultImports(storageManager: StorageManager, result: MutableList<ImportPath>) {
|
||||
result.add(ImportPath.fromString("kotlin.native.*"))
|
||||
}
|
||||
|
||||
override val multiTargetPlatform = MultiTargetPlatform.Specific(platformName)
|
||||
override val platformConfigurator: PlatformConfigurator = KonanPlatformConfigurator
|
||||
}
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.resolve.konan.platform
|
||||
|
||||
import org.jetbrains.kotlin.builtins.PlatformToKotlinClassMap
|
||||
import org.jetbrains.kotlin.container.StorageComponentContainer
|
||||
import org.jetbrains.kotlin.container.useInstance
|
||||
import org.jetbrains.kotlin.resolve.*
|
||||
import org.jetbrains.kotlin.resolve.calls.checkers.ReifiedTypeParameterSubstitutionChecker
|
||||
import org.jetbrains.kotlin.resolve.calls.components.SamConversionTransformer
|
||||
import org.jetbrains.kotlin.resolve.calls.results.TypeSpecificityComparator
|
||||
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker
|
||||
import org.jetbrains.kotlin.resolve.lazy.DelegationFilter
|
||||
import org.jetbrains.kotlin.resolve.scopes.SyntheticScopes
|
||||
import org.jetbrains.kotlin.types.DynamicTypesSettings
|
||||
|
||||
object KonanPlatformConfigurator : PlatformConfigurator(
|
||||
DynamicTypesSettings(),
|
||||
additionalDeclarationCheckers = listOf(ExpectedActualDeclarationChecker),
|
||||
additionalCallCheckers = listOf(
|
||||
org.jetbrains.kotlin.resolve.jvm.checkers.SuperCallWithDefaultArgumentsChecker(),
|
||||
ReifiedTypeParameterSubstitutionChecker()
|
||||
),
|
||||
additionalTypeCheckers = listOf(),
|
||||
additionalClassifierUsageCheckers = listOf(),
|
||||
additionalAnnotationCheckers = listOf(),
|
||||
identifierChecker = IdentifierChecker.Default,
|
||||
overloadFilter = OverloadFilter.Default,
|
||||
platformToKotlinClassMap = PlatformToKotlinClassMap.EMPTY,
|
||||
delegationFilter = DelegationFilter.Default,
|
||||
overridesBackwardCompatibilityHelper = OverridesBackwardCompatibilityHelper.Default,
|
||||
declarationReturnTypeSanitizer = DeclarationReturnTypeSanitizer.Default
|
||||
) {
|
||||
override fun configureModuleComponents(container: StorageComponentContainer) {
|
||||
container.useInstance(SyntheticScopes.Empty)
|
||||
container.useInstance(TypeSpecificityComparator.NONE)
|
||||
container.useInstance(SamConversionTransformer.Empty)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
|
||||
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
|
||||
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||
|
||||
class KonanClassDataFinder(
|
||||
private val fragment: KonanProtoBuf.LinkDataPackageFragment,
|
||||
private val nameResolver: NameResolver
|
||||
) : ClassDataFinder {
|
||||
|
||||
override fun findClassData(classId: ClassId): ClassData? {
|
||||
val proto = fragment.classes
|
||||
val nameList = proto.classNameList
|
||||
|
||||
val index = nameList.indexOfFirst { nameResolver.getClassId(it) == classId }
|
||||
if (index == -1)
|
||||
error("Could not find serialized class $classId")
|
||||
|
||||
val foundClass = proto.getClasses(index) ?: error("Could not find data for serialized class $classId")
|
||||
|
||||
/* TODO: binary version supposed to be read from protobuf. */
|
||||
return ClassData(nameResolver, foundClass, KonanMetadataVersion.INSTANCE, SourceElement.NO_SOURCE)
|
||||
}
|
||||
}
|
||||
+14
@@ -0,0 +1,14 @@
|
||||
/*
|
||||
* 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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
|
||||
|
||||
fun parsePackageFragment(packageMetadata: ByteArray): KonanProtoBuf.LinkDataPackageFragment =
|
||||
KonanProtoBuf.LinkDataPackageFragment.parseFrom(packageMetadata, KonanSerializerProtocol.extensionRegistry)
|
||||
|
||||
fun parseModuleHeader(libraryMetadata: ByteArray): KonanProtoBuf.LinkDataLibrary =
|
||||
KonanProtoBuf.LinkDataLibrary.parseFrom(libraryMetadata, KonanSerializerProtocol.extensionRegistry)
|
||||
+40
@@ -0,0 +1,40 @@
|
||||
/*
|
||||
* 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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
interface KonanDeserializedModuleDescriptorFactory {
|
||||
|
||||
val descriptorFactory: KonanModuleDescriptorFactory
|
||||
val packageFragmentsFactory: KonanDeserializedPackageFragmentsFactory
|
||||
|
||||
fun createDescriptor(
|
||||
library: KonanLibrary,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns,
|
||||
packageAccessedHandler: PackageAccessedHandler? = null
|
||||
): ModuleDescriptorImpl
|
||||
|
||||
/**
|
||||
* Please use this method with care: As far as it creates an instance of [KotlinBuiltIns] it should be
|
||||
* normally used for creation of the very first (e.g. "stdlib") module in the set of created modules.
|
||||
*/
|
||||
fun createDescriptorAndNewBuiltIns(
|
||||
library: KonanLibrary,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
storageManager: StorageManager,
|
||||
packageAccessedHandler: PackageAccessedHandler? = null
|
||||
): ModuleDescriptorImpl
|
||||
}
|
||||
+29
@@ -0,0 +1,29 @@
|
||||
/*
|
||||
* 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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
interface KonanDeserializedPackageFragmentsFactory {
|
||||
|
||||
fun createDeserializedPackageFragments(
|
||||
library: KonanLibrary,
|
||||
packageFragmentNames: List<String>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
packageAccessedHandler: PackageAccessedHandler?,
|
||||
storageManager: StorageManager
|
||||
): List<KonanPackageFragment>
|
||||
|
||||
fun createSyntheticPackageFragments(
|
||||
library: KonanLibrary,
|
||||
deserializedPackageFragments: List<KonanPackageFragment>,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
): List<PackageFragmentDescriptor>
|
||||
}
|
||||
@@ -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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
|
||||
class KonanMetadataVersion(vararg numbers: Int) : BinaryVersion(*numbers) {
|
||||
|
||||
override fun isCompatible(): Boolean = this.major == 1 && this.minor == 0
|
||||
|
||||
companion object {
|
||||
@JvmField
|
||||
val INSTANCE = KonanMetadataVersion(1, 0, 0)
|
||||
|
||||
@JvmField
|
||||
val INVALID_VERSION = KonanMetadataVersion()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
/*
|
||||
* 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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
|
||||
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
|
||||
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializedPackageFragment
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
|
||||
import org.jetbrains.kotlin.serialization.deserialization.getClassId
|
||||
import org.jetbrains.kotlin.serialization.deserialization.getName
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
class KonanPackageFragment(
|
||||
fqName: FqName,
|
||||
private val library: KonanLibrary,
|
||||
private val packageAccessedHandler: PackageAccessedHandler?,
|
||||
storageManager: StorageManager,
|
||||
module: ModuleDescriptor
|
||||
) : DeserializedPackageFragment(fqName, storageManager, module) {
|
||||
|
||||
lateinit var components: DeserializationComponents
|
||||
|
||||
override fun initialize(components: DeserializationComponents) {
|
||||
this.components = components
|
||||
}
|
||||
|
||||
// The proto field is lazy so that we can load only needed
|
||||
// packages from the library.
|
||||
private val protoForNames: KonanProtoBuf.LinkDataPackageFragment by lazy {
|
||||
parsePackageFragment(library.packageMetadata(fqName.asString()))
|
||||
}
|
||||
|
||||
val proto: KonanProtoBuf.LinkDataPackageFragment
|
||||
get() = protoForNames.also { packageAccessedHandler?.markPackageAccessed(fqName) }
|
||||
|
||||
private val nameResolver by lazy {
|
||||
NameResolverImpl(protoForNames.stringTable, protoForNames.nameTable)
|
||||
}
|
||||
|
||||
override val classDataFinder by lazy {
|
||||
KonanClassDataFinder(proto, nameResolver)
|
||||
}
|
||||
|
||||
private val _memberScope by lazy {
|
||||
/* TODO: we fake proto binary versioning for now. */
|
||||
DeserializedPackageMemberScope(
|
||||
this,
|
||||
proto.getPackage(),
|
||||
nameResolver,
|
||||
KonanMetadataVersion.INSTANCE,
|
||||
/* containerSource = */ null,
|
||||
components
|
||||
) { loadClassNames() }
|
||||
}
|
||||
|
||||
override fun getMemberScope(): DeserializedPackageMemberScope = _memberScope
|
||||
|
||||
private val classifierNames: Set<Name> by lazy {
|
||||
val result = mutableSetOf<Name>()
|
||||
result.addAll(loadClassNames())
|
||||
protoForNames.getPackage().typeAliasList.mapTo(result) { nameResolver.getName(it.name) }
|
||||
result
|
||||
}
|
||||
|
||||
fun hasTopLevelClassifier(name: Name): Boolean = name in classifierNames
|
||||
|
||||
private fun loadClassNames(): Collection<Name> {
|
||||
|
||||
val classNameList = protoForNames.classes.classNameList
|
||||
|
||||
val names = classNameList.mapNotNull {
|
||||
val classId = nameResolver.getClassId(it)
|
||||
val shortName = classId.shortClassName
|
||||
if (!classId.isNestedClass) shortName else null
|
||||
}
|
||||
|
||||
return names
|
||||
}
|
||||
}
|
||||
+54
@@ -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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolveResult
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
interface KonanResolvedModuleDescriptorsFactory {
|
||||
|
||||
val moduleDescriptorFactory: KonanDeserializedModuleDescriptorFactory
|
||||
|
||||
/**
|
||||
* Given the [resolvedLibraries] creates the list of [ModuleDescriptorImpl]s with properly installed
|
||||
* inter-dependencies. The result of this method is returned in a form of [KonanResolvedModuleDescriptors] instance.
|
||||
*
|
||||
* Please use this method with care: Unless this method accepts `null` for [builtIns], it is not recommended to
|
||||
* invoke it this way. If you are compiling a source module, please supply the non-null [builtIns] from the
|
||||
* source module, so that all modules created in your compilation session will share the same built-ins instance.
|
||||
*
|
||||
* Otherwise (if `null` was supplied), a new instance of [KotlinBuiltIns] will be created. The created built-ins
|
||||
* instance will be shared by all modules created in this method. But this instance will have no connection
|
||||
* with probably existing built-ins instance of your source module(s).
|
||||
*/
|
||||
fun createResolved(
|
||||
resolvedLibraries: KonanLibraryResolveResult,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns?,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
customAction: ((KonanLibrary, ModuleDescriptorImpl) -> Unit)? = null
|
||||
): KonanResolvedModuleDescriptors
|
||||
}
|
||||
|
||||
class KonanResolvedModuleDescriptors(
|
||||
|
||||
/**
|
||||
* The list of modules each representing an individual Kotlin/Native library. All modules
|
||||
* in this list have properly installed dependencies, i.e. module has all necessary dependencies
|
||||
* on other modules plus a dependency on the [forwardDeclarationsModule].
|
||||
*/
|
||||
val resolvedDescriptors: List<ModuleDescriptorImpl>,
|
||||
|
||||
/**
|
||||
* This is a module which "contains" forward declarations.
|
||||
* Note: this module should be unique per compilation and should always be the last dependency of any module.
|
||||
*/
|
||||
val forwardDeclarationsModule: ModuleDescriptorImpl
|
||||
)
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
|
||||
import org.jetbrains.kotlin.protobuf.ExtensionRegistryLite
|
||||
import org.jetbrains.kotlin.serialization.SerializerExtensionProtocol
|
||||
|
||||
object KonanSerializerProtocol : SerializerExtensionProtocol(
|
||||
ExtensionRegistryLite.newInstance().apply { KonanProtoBuf.registerAllExtensions(this) },
|
||||
KonanProtoBuf.packageFqName,
|
||||
KonanProtoBuf.constructorAnnotation,
|
||||
KonanProtoBuf.classAnnotation,
|
||||
KonanProtoBuf.functionAnnotation,
|
||||
KonanProtoBuf.propertyAnnotation,
|
||||
KonanProtoBuf.enumEntryAnnotation,
|
||||
KonanProtoBuf.compileTimeValue,
|
||||
KonanProtoBuf.parameterAnnotation,
|
||||
KonanProtoBuf.typeAnnotation,
|
||||
KonanProtoBuf.typeParameterAnnotation
|
||||
)
|
||||
+20
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.serialization.konan
|
||||
|
||||
import org.jetbrains.kotlin.metadata.ProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.deserialization.FlexibleTypeDeserializer
|
||||
import org.jetbrains.kotlin.types.SimpleType
|
||||
|
||||
object NullFlexibleTypeDeserializer : FlexibleTypeDeserializer {
|
||||
|
||||
override fun create(
|
||||
proto: ProtoBuf.Type,
|
||||
flexibleId: String,
|
||||
lowerBound: SimpleType,
|
||||
upperBound: SimpleType
|
||||
) = error("Illegal use of flexible type deserializer.")
|
||||
}
|
||||
+130
@@ -0,0 +1,130 @@
|
||||
/*
|
||||
* 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.serialization.konan.impl
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.NotFoundClasses
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentProviderImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin
|
||||
import org.jetbrains.kotlin.descriptors.konan.KonanModuleDescriptorFactory
|
||||
import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import org.jetbrains.kotlin.serialization.konan.*
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
|
||||
internal class KonanDeserializedModuleDescriptorFactoryImpl(
|
||||
override val descriptorFactory: KonanModuleDescriptorFactory,
|
||||
override val packageFragmentsFactory: KonanDeserializedPackageFragmentsFactory
|
||||
) : KonanDeserializedModuleDescriptorFactory {
|
||||
|
||||
override fun createDescriptor(
|
||||
library: KonanLibrary,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns,
|
||||
packageAccessedHandler: PackageAccessedHandler?
|
||||
) = createDescriptorOptionalBuiltIns(library, languageVersionSettings, storageManager, builtIns, packageAccessedHandler)
|
||||
|
||||
override fun createDescriptorAndNewBuiltIns(
|
||||
library: KonanLibrary,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
storageManager: StorageManager,
|
||||
packageAccessedHandler: PackageAccessedHandler?
|
||||
) = createDescriptorOptionalBuiltIns(library, languageVersionSettings, storageManager, null, packageAccessedHandler)
|
||||
|
||||
private fun createDescriptorOptionalBuiltIns(
|
||||
library: KonanLibrary,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns?,
|
||||
packageAccessedHandler: PackageAccessedHandler?
|
||||
): ModuleDescriptorImpl {
|
||||
|
||||
val libraryProto = parseModuleHeader(library.moduleHeaderData)
|
||||
|
||||
val moduleName = Name.special(libraryProto.moduleName)
|
||||
val moduleOrigin = DeserializedKonanModuleOrigin(library)
|
||||
|
||||
val moduleDescriptor = if (builtIns != null)
|
||||
descriptorFactory.createDescriptor(moduleName, storageManager, builtIns, moduleOrigin)
|
||||
else
|
||||
descriptorFactory.createDescriptorAndNewBuiltIns(moduleName, storageManager, moduleOrigin)
|
||||
|
||||
val deserializationConfiguration = CompilerDeserializationConfiguration(languageVersionSettings)
|
||||
|
||||
val provider = createPackageFragmentProvider(
|
||||
library,
|
||||
packageAccessedHandler,
|
||||
libraryProto.packageFragmentNameList,
|
||||
storageManager,
|
||||
moduleDescriptor,
|
||||
deserializationConfiguration
|
||||
)
|
||||
|
||||
moduleDescriptor.initialize(provider)
|
||||
|
||||
return moduleDescriptor
|
||||
}
|
||||
|
||||
private fun createPackageFragmentProvider(
|
||||
library: KonanLibrary,
|
||||
packageAccessedHandler: PackageAccessedHandler?,
|
||||
packageFragmentNames: List<String>,
|
||||
storageManager: StorageManager,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
configuration: DeserializationConfiguration
|
||||
): PackageFragmentProvider {
|
||||
|
||||
val deserializedPackageFragments = packageFragmentsFactory.createDeserializedPackageFragments(
|
||||
library, packageFragmentNames, moduleDescriptor, packageAccessedHandler, storageManager
|
||||
)
|
||||
|
||||
val syntheticPackageFragments = packageFragmentsFactory.createSyntheticPackageFragments(
|
||||
library, deserializedPackageFragments, moduleDescriptor
|
||||
)
|
||||
|
||||
val provider = PackageFragmentProviderImpl(deserializedPackageFragments + syntheticPackageFragments)
|
||||
|
||||
val notFoundClasses = NotFoundClasses(storageManager, moduleDescriptor)
|
||||
|
||||
val annotationAndConstantLoader = AnnotationAndConstantLoaderImpl(
|
||||
moduleDescriptor,
|
||||
notFoundClasses,
|
||||
KonanSerializerProtocol
|
||||
)
|
||||
|
||||
val components = DeserializationComponents(
|
||||
storageManager,
|
||||
moduleDescriptor,
|
||||
configuration,
|
||||
DeserializedClassDataFinder(provider),
|
||||
annotationAndConstantLoader,
|
||||
provider,
|
||||
LocalClassifierTypeSettings.Default,
|
||||
ErrorReporter.DO_NOTHING,
|
||||
LookupTracker.DO_NOTHING,
|
||||
NullFlexibleTypeDeserializer,
|
||||
emptyList(),
|
||||
notFoundClasses,
|
||||
ContractDeserializer.DEFAULT,
|
||||
extensionRegistryLite = KonanSerializerProtocol.extensionRegistry
|
||||
)
|
||||
|
||||
for (packageFragment in deserializedPackageFragments) {
|
||||
packageFragment.initialize(components)
|
||||
}
|
||||
|
||||
return provider
|
||||
}
|
||||
}
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
* 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.serialization.konan.impl
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.exportForwardDeclarations
|
||||
import org.jetbrains.kotlin.konan.library.isInterop
|
||||
import org.jetbrains.kotlin.konan.library.packageFqName
|
||||
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedPackageFragmentsFactory
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanPackageFragment
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
|
||||
|
||||
// FIXME(ddol): decouple and move interop-specific logic back to Kotlin/Native.
|
||||
internal object KonanDeserializedPackageFragmentsFactoryImpl : KonanDeserializedPackageFragmentsFactory {
|
||||
|
||||
override fun createDeserializedPackageFragments(
|
||||
library: KonanLibrary,
|
||||
packageFragmentNames: List<String>,
|
||||
moduleDescriptor: ModuleDescriptor,
|
||||
packageAccessedHandler: PackageAccessedHandler?,
|
||||
storageManager: StorageManager
|
||||
) = packageFragmentNames.map {
|
||||
KonanPackageFragment(FqName(it), library, packageAccessedHandler, storageManager, moduleDescriptor)
|
||||
}
|
||||
|
||||
override fun createSyntheticPackageFragments(
|
||||
library: KonanLibrary,
|
||||
deserializedPackageFragments: List<KonanPackageFragment>,
|
||||
moduleDescriptor: ModuleDescriptor
|
||||
): List<PackageFragmentDescriptor> {
|
||||
|
||||
if (!library.isInterop) return emptyList()
|
||||
|
||||
val mainPackageFqName = library.packageFqName
|
||||
?: error("Inconsistent manifest: interop library ${library.libraryName} should have `package` specified")
|
||||
val exportForwardDeclarations = library.exportForwardDeclarations
|
||||
|
||||
val aliasedPackageFragments = deserializedPackageFragments.filter { it.fqName == mainPackageFqName }
|
||||
|
||||
val result = mutableListOf<PackageFragmentDescriptor>()
|
||||
listOf(
|
||||
ForwardDeclarationsFqNames.cNamesStructs,
|
||||
ForwardDeclarationsFqNames.objCNamesClasses,
|
||||
ForwardDeclarationsFqNames.objCNamesProtocols
|
||||
).mapTo(result) { fqName ->
|
||||
ClassifierAliasingPackageFragmentDescriptor(aliasedPackageFragments, moduleDescriptor, fqName)
|
||||
}
|
||||
|
||||
result.add(ExportedForwardDeclarationsPackageFragmentDescriptor(moduleDescriptor, mainPackageFqName, exportForwardDeclarations))
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* The package fragment to export forward declarations from interop package namespace, i.e.
|
||||
* redirect "$pkg.$name" to e.g. "cnames.structs.$name".
|
||||
*/
|
||||
class ExportedForwardDeclarationsPackageFragmentDescriptor(
|
||||
module: ModuleDescriptor,
|
||||
fqName: FqName,
|
||||
declarations: List<FqName>
|
||||
) : PackageFragmentDescriptorImpl(module, fqName) {
|
||||
|
||||
private val memberScope = object : MemberScopeImpl() {
|
||||
|
||||
private val nameToFqName = declarations.map { it.shortName() to it }.toMap()
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation): ClassifierDescriptor? {
|
||||
val declFqName = nameToFqName[name] ?: return null
|
||||
|
||||
val packageView = module.getPackage(declFqName.parent())
|
||||
return packageView.memberScope.getContributedClassifier(name, location)
|
||||
}
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(this::class.java.simpleName, " {")
|
||||
p.pushIndent()
|
||||
|
||||
p.println("declarations = $declarations")
|
||||
|
||||
p.popIndent()
|
||||
p.println("}")
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
override fun getMemberScope() = memberScope
|
||||
}
|
||||
|
||||
/**
|
||||
* The package fragment that redirects all requests for classifier lookup to its targets.
|
||||
*/
|
||||
class ClassifierAliasingPackageFragmentDescriptor(
|
||||
targets: List<KonanPackageFragment>,
|
||||
module: ModuleDescriptor,
|
||||
fqName: FqName
|
||||
) : PackageFragmentDescriptorImpl(module, fqName) {
|
||||
|
||||
private val memberScope = object : MemberScopeImpl() {
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation) =
|
||||
targets.firstNotNullResult {
|
||||
if (it.hasTopLevelClassifier(name)) {
|
||||
it.getMemberScope().getContributedClassifier(name, location)
|
||||
} else {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(this::class.java.simpleName, " {")
|
||||
p.pushIndent()
|
||||
|
||||
p.println("targets = $targets")
|
||||
|
||||
p.popIndent()
|
||||
p.println("}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMemberScope(): MemberScope = memberScope
|
||||
}
|
||||
+189
@@ -0,0 +1,189 @@
|
||||
/*
|
||||
* 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.serialization.konan.impl
|
||||
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.impl.PackageFragmentDescriptorImpl
|
||||
import org.jetbrains.kotlin.descriptors.konan.KonanModuleOrigin
|
||||
import org.jetbrains.kotlin.descriptors.konan.SyntheticModulesOrigin
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolveResult
|
||||
import org.jetbrains.kotlin.konan.library.resolver.PackageAccessedHandler
|
||||
import org.jetbrains.kotlin.konan.util.profile
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||
import org.jetbrains.kotlin.resolve.scopes.MemberScopeImpl
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanDeserializedModuleDescriptorFactory
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanResolvedModuleDescriptors
|
||||
import org.jetbrains.kotlin.serialization.konan.KonanResolvedModuleDescriptorsFactory
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.storage.StorageManager
|
||||
import org.jetbrains.kotlin.storage.getValue
|
||||
import org.jetbrains.kotlin.utils.Printer
|
||||
|
||||
class KonanResolvedModuleDescriptorsFactoryImpl(
|
||||
override val moduleDescriptorFactory: KonanDeserializedModuleDescriptorFactory
|
||||
) : KonanResolvedModuleDescriptorsFactory {
|
||||
|
||||
override fun createResolved(
|
||||
resolvedLibraries: KonanLibraryResolveResult,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns?,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
customAction: ((KonanLibrary, ModuleDescriptorImpl) -> Unit)?
|
||||
): KonanResolvedModuleDescriptors {
|
||||
|
||||
val moduleDescriptors = mutableListOf<ModuleDescriptorImpl>()
|
||||
@Suppress("NAME_SHADOWING")
|
||||
var builtIns = builtIns
|
||||
|
||||
// Build module descriptors.
|
||||
resolvedLibraries.forEach { library, packageAccessedHandler ->
|
||||
profile("Loading ${library.libraryName}") {
|
||||
|
||||
// MutableModuleContext needs ModuleDescriptorImpl, rather than ModuleDescriptor.
|
||||
val moduleDescriptor = createDescriptorOptionalBuiltsIns(
|
||||
library, languageVersionSettings, storageManager, builtIns, packageAccessedHandler
|
||||
)
|
||||
builtIns = moduleDescriptor.builtIns
|
||||
moduleDescriptors.add(moduleDescriptor)
|
||||
|
||||
customAction?.invoke(library, moduleDescriptor)
|
||||
}
|
||||
}
|
||||
|
||||
val forwardDeclarationsModule = createForwardDeclarationsModule(builtIns, storageManager)
|
||||
|
||||
// Set inter-dependencies between module descriptors, add forwarding declarations module.
|
||||
for (module in moduleDescriptors) {
|
||||
// Yes, just to all of them.
|
||||
module.setDependencies(moduleDescriptors + forwardDeclarationsModule)
|
||||
}
|
||||
|
||||
return KonanResolvedModuleDescriptors(moduleDescriptors, forwardDeclarationsModule)
|
||||
}
|
||||
|
||||
private fun createForwardDeclarationsModule(
|
||||
builtIns: KotlinBuiltIns?,
|
||||
storageManager: StorageManager
|
||||
): ModuleDescriptorImpl {
|
||||
|
||||
val name = Name.special("<forward declarations>")
|
||||
val module = createDescriptorOptionalBuiltsIns(name, storageManager, builtIns, SyntheticModulesOrigin)
|
||||
|
||||
fun createPackage(fqName: FqName, supertypeName: String, classKind: ClassKind) =
|
||||
ForwardDeclarationsPackageFragmentDescriptor(
|
||||
storageManager,
|
||||
module,
|
||||
fqName,
|
||||
Name.identifier(supertypeName),
|
||||
classKind
|
||||
)
|
||||
|
||||
val packageFragmentProvider = PackageFragmentProviderImpl(
|
||||
listOf(
|
||||
createPackage(ForwardDeclarationsFqNames.cNamesStructs, "COpaque", ClassKind.CLASS),
|
||||
createPackage(ForwardDeclarationsFqNames.objCNamesClasses, "ObjCObjectBase", ClassKind.CLASS),
|
||||
createPackage(ForwardDeclarationsFqNames.objCNamesProtocols, "ObjCObject", ClassKind.INTERFACE)
|
||||
)
|
||||
)
|
||||
|
||||
module.initialize(packageFragmentProvider)
|
||||
module.setDependencies(module)
|
||||
|
||||
return module
|
||||
}
|
||||
|
||||
private fun createDescriptorOptionalBuiltsIns(
|
||||
name: Name,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns?,
|
||||
moduleOrigin: KonanModuleOrigin
|
||||
) = if (builtIns != null)
|
||||
moduleDescriptorFactory.descriptorFactory.createDescriptor(name, storageManager, builtIns, moduleOrigin)
|
||||
else
|
||||
moduleDescriptorFactory.descriptorFactory.createDescriptorAndNewBuiltIns(name, storageManager, moduleOrigin)
|
||||
|
||||
private fun createDescriptorOptionalBuiltsIns(
|
||||
library: KonanLibrary,
|
||||
languageVersionSettings: LanguageVersionSettings,
|
||||
storageManager: StorageManager,
|
||||
builtIns: KotlinBuiltIns?,
|
||||
packageAccessedHandler: PackageAccessedHandler?
|
||||
) = if (builtIns != null)
|
||||
moduleDescriptorFactory.createDescriptor(library, languageVersionSettings, storageManager, builtIns, packageAccessedHandler)
|
||||
else
|
||||
moduleDescriptorFactory.createDescriptorAndNewBuiltIns(library, languageVersionSettings, storageManager, packageAccessedHandler)
|
||||
}
|
||||
|
||||
/**
|
||||
* Package fragment which creates descriptors for forward declarations on demand.
|
||||
*/
|
||||
private class ForwardDeclarationsPackageFragmentDescriptor(
|
||||
storageManager: StorageManager,
|
||||
module: ModuleDescriptor,
|
||||
fqName: FqName,
|
||||
supertypeName: Name,
|
||||
classKind: ClassKind
|
||||
) : PackageFragmentDescriptorImpl(module, fqName) {
|
||||
|
||||
private val memberScope = object : MemberScopeImpl() {
|
||||
|
||||
private val declarations = storageManager.createMemoizedFunction(this::createDeclaration)
|
||||
|
||||
private val supertype by storageManager.createLazyValue {
|
||||
val descriptor = builtIns.builtInsModule.getPackage(ForwardDeclarationsFqNames.packageName)
|
||||
.memberScope
|
||||
.getContributedClassifier(supertypeName, NoLookupLocation.FROM_BACKEND) as ClassDescriptor
|
||||
|
||||
descriptor.defaultType
|
||||
}
|
||||
|
||||
private fun createDeclaration(name: Name): ClassDescriptor {
|
||||
return ClassDescriptorImpl(
|
||||
this@ForwardDeclarationsPackageFragmentDescriptor,
|
||||
name,
|
||||
Modality.FINAL,
|
||||
classKind,
|
||||
listOf(supertype),
|
||||
SourceElement.NO_SOURCE,
|
||||
false,
|
||||
LockBasedStorageManager.NO_LOCKS
|
||||
).apply {
|
||||
this.initialize(MemberScope.Empty, emptySet(), null)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getContributedClassifier(name: Name, location: LookupLocation) = declarations(name)
|
||||
|
||||
override fun printScopeStructure(p: Printer) {
|
||||
p.println(this::class.java.simpleName, "{}")
|
||||
}
|
||||
}
|
||||
|
||||
override fun getMemberScope(): MemberScope = memberScope
|
||||
}
|
||||
|
||||
// FIXME(ddol): decouple and move interop-specific logic back to Kotlin/Native.
|
||||
internal object ForwardDeclarationsFqNames {
|
||||
|
||||
val packageName = FqName("kotlinx.cinterop")
|
||||
|
||||
val cNames = FqName("cnames")
|
||||
val cNamesStructs = cNames.child(Name.identifier("structs"))
|
||||
|
||||
val objCNames = FqName("objcnames")
|
||||
val objCNamesClasses = objCNames.child(Name.identifier("classes"))
|
||||
val objCNamesProtocols = objCNames.child(Name.identifier("protocols"))
|
||||
}
|
||||
@@ -0,0 +1,245 @@
|
||||
/*
|
||||
* 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.file
|
||||
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
import java.net.URI
|
||||
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()
|
||||
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 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
|
||||
}
|
||||
|
||||
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()
|
||||
|
||||
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 File.mutableZipFileSystem() = this.zipFileSystem(mutable = true)
|
||||
|
||||
fun File.zipPath(path: String): Path = this.zipFileSystem().getPath(path)
|
||||
|
||||
val File.asZipRoot: File
|
||||
get() = File(this.zipPath("/"))
|
||||
|
||||
val File.asWritableZipRoot: File
|
||||
get() = File(this.mutableZipFileSystem().getPath("/"))
|
||||
|
||||
private fun File.toPath() = Paths.get(this.path)
|
||||
|
||||
fun File.zipDirAs(unixFile: File) {
|
||||
val zipRoot = unixFile.asWritableZipRoot
|
||||
this.recursiveCopyTo(zipRoot)
|
||||
zipRoot.javaPath.fileSystem.close()
|
||||
}
|
||||
|
||||
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()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
/*
|
||||
* 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.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
const val KLIB_FILE_EXTENSION = "klib"
|
||||
const val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION"
|
||||
|
||||
const val KONAN_STDLIB_NAME = "stdlib"
|
||||
|
||||
interface SearchPathResolver {
|
||||
val searchRoots: List<File>
|
||||
fun resolve(givenPath: String): File
|
||||
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<File>
|
||||
}
|
||||
|
||||
interface SearchPathResolverWithTarget: SearchPathResolver {
|
||||
val target: KonanTarget
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.properties
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.*
|
||||
|
||||
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): List<String> {
|
||||
val value = this.getProperty(key.suffix(suffix)) ?: this.getProperty(key)
|
||||
if (value?.isBlank() == true) return emptyList()
|
||||
|
||||
return 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"
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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 kotlin.system.measureTimeMillis
|
||||
|
||||
fun printMillisec(message: String, body: () -> Unit) {
|
||||
val msec = measureTimeMillis {
|
||||
body()
|
||||
}
|
||||
println("$message: $msec msec")
|
||||
}
|
||||
|
||||
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()
|
||||
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* 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 org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.util.*
|
||||
|
||||
fun defaultTargetSubstitutions(target: KonanTarget) =
|
||||
mapOf(
|
||||
"target" to target.visibleName,
|
||||
"arch" to target.architecture.visibleName,
|
||||
"family" to target.family.visibleName
|
||||
)
|
||||
|
||||
// Performs substitution similar to:
|
||||
// foo = ${foo} ${foo.${arch}} ${foo.${os}}
|
||||
fun substitute(properties: Properties, substitutions: Map<String, String>) {
|
||||
for (key in properties.stringPropertyNames()) {
|
||||
for (substitution in substitutions.values) {
|
||||
val suffix = ".$substitution"
|
||||
if (key.endsWith(suffix)) {
|
||||
val baseKey = key.removeSuffix(suffix)
|
||||
val oldValue = properties.getProperty(baseKey, "")
|
||||
val appendedValue = properties.getProperty(key, "")
|
||||
val newValue = if (oldValue != "") "$oldValue $appendedValue" else appendedValue
|
||||
properties.setProperty(baseKey, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -51,6 +51,7 @@ include ":kotlin-build-common",
|
||||
":js:js.tests",
|
||||
":konan:konan-utils",
|
||||
":konan:konan-metadata",
|
||||
":konan:konan-serializer",
|
||||
":jps-plugin",
|
||||
":kotlin-jps-plugin",
|
||||
":core:descriptors",
|
||||
@@ -240,6 +241,7 @@ project(':compiler:ir.backend.common').projectDir = "$rootDir/compiler/ir/backen
|
||||
project(':compiler:backend.js').projectDir = "$rootDir/compiler/ir/backend.js" as File
|
||||
project(':konan:konan-utils').projectDir = "$rootDir/konan/utils" as File
|
||||
project(':konan:konan-metadata').projectDir = "$rootDir/konan/metadata" as File
|
||||
project(':konan:konan-serializer').projectDir = "$rootDir/konan/serializer" 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