KLIB reader: better isolation of implementation details (#1917)

KLIB reader:
- better isolation of implementation details
- rename entities closer to their meaning: KonanLibrary -> KonanLibraryLayout, KonanLibraryReader -> KonanLibrary
This commit is contained in:
Dmitriy Dolovov
2018-08-23 10:46:58 +03:00
committed by GitHub
parent a216bf8903
commit 314cd0993b
21 changed files with 391 additions and 329 deletions
-2
View File
@@ -138,8 +138,6 @@ dependencies {
compilerCompile kotlinNativeInterop['llvm'].configuration compilerCompile kotlinNativeInterop['llvm'].configuration
compilerCompile kotlinNativeInterop['hash'].configuration compilerCompile kotlinNativeInterop['hash'].configuration
compilerCompile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion" compilerCompile "org.jetbrains.kotlin:kotlin-native-shared:$konanVersion"
compilerCompile "org.jetbrains.kotlin:konan.descriptors:$konanVersion"
compilerCompile "org.jetbrains.kotlin:konan.metadata:$konanVersion"
compilerCompile "org.jetbrains.kotlin:konan.serializer:$konanVersion" compilerCompile "org.jetbrains.kotlin:konan.serializer:$konanVersion"
cli_bcCompile kotlinCompilerModule cli_bcCompile kotlinCompilerModule
@@ -32,7 +32,7 @@ import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.interop.createForwardDeclarationsModule import org.jetbrains.kotlin.descriptors.konan.interop.createForwardDeclarationsModule
import org.jetbrains.kotlin.konan.TempFiles import org.jetbrains.kotlin.konan.TempFiles
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KonanLibraryReader import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.defaultResolver import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.profile import org.jetbrains.kotlin.konan.util.profile
@@ -93,8 +93,10 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES) private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES)
private val resolver = defaultResolver(repositories, target, distribution) private val resolver = defaultResolver(repositories, target, distribution)
internal val immediateLibraries: List<KonanLibraryReader> by lazy { internal val immediateLibraries: List<KonanLibrary> by lazy {
val result = resolver.resolveImmediateLibraries(libraryNames, target, val result = resolver.resolveImmediateLibraries(
libraryNames,
target,
currentAbiVersion, currentAbiVersion,
configuration.getBoolean(KonanConfigKeys.NOSTDLIB), configuration.getBoolean(KonanConfigKeys.NOSTDLIB),
configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS), configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS),
@@ -103,7 +105,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
result result
} }
fun librariesWithDependencies(moduleDescriptor: ModuleDescriptor?): List<KonanLibraryReader> { fun librariesWithDependencies(moduleDescriptor: ModuleDescriptor?): List<KonanLibrary> {
if (moduleDescriptor == null) error("purgeUnneeded() only works correctly after resolve is over, and we have successfully marked package files as needed or not needed.") if (moduleDescriptor == null) error("purgeUnneeded() only works correctly after resolve is over, and we have successfully marked package files as needed or not needed.")
return immediateLibraries.purgeUnneeded(this).withResolvedDependencies() return immediateLibraries.purgeUnneeded(this).withResolvedDependencies()
@@ -175,5 +177,5 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String) fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String)
= this.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(priority, message) = this.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(priority, message)
private fun <T: KonanLibraryReader> List<T>.purgeUnneeded(config: KonanConfig): List<T> = private fun <T: KonanLibrary> List<T>.purgeUnneeded(config: KonanConfig): List<T> =
this.filter{ (!it.isDefaultLibrary && !config.purgeUserLibs) || it.isNeededForLink } this.filter{ (!it.isDefaultLibrary && !config.purgeUserLibs) || it.isNeededForLink }
@@ -17,14 +17,14 @@
package org.jetbrains.kotlin.backend.konan.library package org.jetbrains.kotlin.backend.konan.library
import llvm.LLVMModuleRef import llvm.LLVMModuleRef
import org.jetbrains.kotlin.konan.library.KonanLibraryReader import org.jetbrains.kotlin.konan.library.KonanLibrary
interface KonanLibraryWriter { interface KonanLibraryWriter {
fun addLinkData(linkData: LinkData) fun addLinkData(linkData: LinkData)
fun addNativeBitcode(library: String) fun addNativeBitcode(library: String)
fun addIncludedBinary(library: String) fun addIncludedBinary(library: String)
fun addKotlinBitcode(llvmModule: LLVMModuleRef) fun addKotlinBitcode(llvmModule: LLVMModuleRef)
fun addLinkDependencies(libraries: List<KonanLibraryReader>) fun addLinkDependencies(libraries: List<KonanLibrary>)
fun addManifestAddend(path: String) fun addManifestAddend(path: String)
fun addDataFlowGraph(dataFlowGraph: ByteArray) fun addDataFlowGraph(dataFlowGraph: ByteArray)
val mainBitcodeFileName: String val mainBitcodeFileName: String
@@ -17,15 +17,16 @@
package org.jetbrains.kotlin.backend.konan.library package org.jetbrains.kotlin.backend.konan.library
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KonanLibraryReader import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.SearchPathResolver import org.jetbrains.kotlin.konan.library.SearchPathResolver
import org.jetbrains.kotlin.konan.library.impl.LibraryReaderImpl import org.jetbrains.kotlin.konan.library.createKonanLibraryReader
import org.jetbrains.kotlin.konan.library.unresolvedDependencies
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
const val KONAN_CURRENT_ABI_VERSION = 1 const val KONAN_CURRENT_ABI_VERSION = 1
/** /**
* Returns the list of [KonanLibraryReader]s given the list of user provided [libraryNames] along with * Returns the list of [KonanLibrary]s given the list of user provided [libraryNames] along with
* other parameters: [target], [abiVersion], [noStdLib], [noDefaultLibs]. * other parameters: [target], [abiVersion], [noStdLib], [noDefaultLibs].
*/ */
fun SearchPathResolver.resolveImmediateLibraries(libraryNames: List<String>, fun SearchPathResolver.resolveImmediateLibraries(libraryNames: List<String>,
@@ -33,13 +34,13 @@ fun SearchPathResolver.resolveImmediateLibraries(libraryNames: List<String>,
abiVersion: Int = KONAN_CURRENT_ABI_VERSION, abiVersion: Int = KONAN_CURRENT_ABI_VERSION,
noStdLib: Boolean = false, noStdLib: Boolean = false,
noDefaultLibs: Boolean = false, noDefaultLibs: Boolean = false,
logger: ((String) -> Unit)?): List<KonanLibraryReader> { logger: ((String) -> Unit)?): List<KonanLibrary> {
val userProvidedLibraries = libraryNames val userProvidedLibraries = libraryNames
.map { resolve(it) } .map { resolve(it) }
.map{ LibraryReaderImpl(it, abiVersion, target) } .map{ createKonanLibraryReader(it, abiVersion, target) }
val defaultLibraries = defaultLinks(noStdLib = noStdLib, noDefaultLibs = noDefaultLibs).map { val defaultLibraries = defaultLinks(noStdLib = noStdLib, noDefaultLibs = noDefaultLibs).map {
LibraryReaderImpl(it, abiVersion, target, isDefaultLibrary = true) createKonanLibraryReader(it, abiVersion, target, isDefaultLibrary = true)
} }
// Make sure the user provided ones appear first, so that // Make sure the user provided ones appear first, so that
@@ -64,16 +65,16 @@ private fun warnOnLibraryDuplicates(resolvedLibraries: List<File>, logger: ((Str
/** /**
* For each of the given [immediateLibraries] fills in `resolvedDependencies` field with the * For each of the given [immediateLibraries] fills in `resolvedDependencies` field with the
* [KonanLibraryReader]s the library !!directly!! depends on. * [KonanLibrary]s the library !!directly!! depends on.
*/ */
fun SearchPathResolver.resolveLibrariesRecursive(immediateLibraries: List<KonanLibraryReader>, fun SearchPathResolver.resolveLibrariesRecursive(immediateLibraries: List<KonanLibrary>,
target: KonanTarget, target: KonanTarget,
abiVersion: Int) { abiVersion: Int) {
val cache = mutableMapOf<File, KonanLibraryReader>() val cache = mutableMapOf<File, KonanLibrary>()
cache.putAll(immediateLibraries.map { it.libraryFile.absoluteFile to it }) cache.putAll(immediateLibraries.map { it.libraryFile.absoluteFile to it })
var newDependencies = cache.values.toList() var newDependencies = cache.values.toList()
do { do {
newDependencies = newDependencies.map { library: KonanLibraryReader -> newDependencies = newDependencies.map { library: KonanLibrary ->
library.unresolvedDependencies library.unresolvedDependencies
.map { resolve(it).absoluteFile } .map { resolve(it).absoluteFile }
.mapNotNull { .mapNotNull {
@@ -81,7 +82,7 @@ fun SearchPathResolver.resolveLibrariesRecursive(immediateLibraries: List<KonanL
library.resolvedDependencies.add(cache[it]!!) library.resolvedDependencies.add(cache[it]!!)
null null
} else { } else {
val reader = LibraryReaderImpl(it, abiVersion, target) val reader = createKonanLibraryReader(it, abiVersion, target)
cache[it] = reader cache[it] = reader
library.resolvedDependencies.add(reader) library.resolvedDependencies.add(reader)
reader reader
@@ -92,11 +93,11 @@ fun SearchPathResolver.resolveLibrariesRecursive(immediateLibraries: List<KonanL
} }
/** /**
* For the given list of [KonanLibraryReader]s returns the list of [KonanLibraryReader]s * For the given list of [KonanLibrary]s returns the list of [KonanLibrary]s
* that includes the same libraries plus all their (transitive) dependencies. * that includes the same libraries plus all their (transitive) dependencies.
*/ */
fun List<KonanLibraryReader>.withResolvedDependencies(): List<KonanLibraryReader> { fun List<KonanLibrary>.withResolvedDependencies(): List<KonanLibrary> {
val result = mutableSetOf<KonanLibraryReader>() val result = mutableSetOf<KonanLibrary>()
result.addAll(this) result.addAll(this)
var newDependencies = result.toList() var newDependencies = result.toList()
do { do {
@@ -112,7 +113,7 @@ fun SearchPathResolver.resolveLibrariesRecursive(libraryNames: List<String>,
target: KonanTarget, target: KonanTarget,
abiVersion: Int = KONAN_CURRENT_ABI_VERSION, abiVersion: Int = KONAN_CURRENT_ABI_VERSION,
noStdLib: Boolean = false, noStdLib: Boolean = false,
noDefaultLibs: Boolean = false): List<KonanLibraryReader> { noDefaultLibs: Boolean = false): List<KonanLibrary> {
val immediateLibraries = resolveImmediateLibraries( val immediateLibraries = resolveImmediateLibraries(
libraryNames = libraryNames, libraryNames = libraryNames,
target = target, target = target,
@@ -16,31 +16,34 @@
package org.jetbrains.kotlin.backend.konan.library.impl package org.jetbrains.kotlin.backend.konan.library.impl
import org.jetbrains.kotlin.konan.library.KonanLibraryReader
import llvm.LLVMModuleRef import llvm.LLVMModuleRef
import llvm.LLVMWriteBitcodeToFile import llvm.LLVMWriteBitcodeToFile
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.konan.file.* import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.properties.* import org.jetbrains.kotlin.konan.properties.*
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
abstract class FileBasedLibraryWriter ( abstract class FileBasedLibraryWriter (val file: File, val currentAbiVersion: Int): KonanLibraryWriter
val file: File, val currentAbiVersion: Int): KonanLibraryWriter {
}
class LibraryWriterImpl(override val libDir: File, moduleName: String, currentAbiVersion: Int, /**
override val target: KonanTarget?, val nopack: Boolean = false): * Requires non-null [target].
FileBasedLibraryWriter(libDir, currentAbiVersion), KonanLibrary { */
class LibraryWriterImpl(
override val libDir: File,
moduleName: String,
currentAbiVersion: Int,
override val target: KonanTarget,
val nopack: Boolean = false
): FileBasedLibraryWriter(libDir, currentAbiVersion), KonanLibraryLayout {
public constructor(path: String, moduleName: String, currentAbiVersion: Int, constructor(path: String, moduleName: String, currentAbiVersion: Int, target: KonanTarget, nopack: Boolean):
target:KonanTarget?, nopack: Boolean):
this(File(path), moduleName, currentAbiVersion, target, nopack) this(File(path), moduleName, currentAbiVersion, target, nopack)
override val libraryName = libDir.path override val libraryName = libDir.path
val klibFile val klibFile
get() = File("${libDir.path}.klib") get() = File("${libDir.path}.$KLIB_FILE_EXTENSION")
// TODO: Experiment with separate bitcode files. // TODO: Experiment with separate bitcode files.
// Per package or per class. // Per package or per class.
@@ -60,8 +63,8 @@ class LibraryWriterImpl(override val libDir: File, moduleName: String, currentAb
includedDir.mkdirs() includedDir.mkdirs()
resourcesDir.mkdirs() resourcesDir.mkdirs()
// TODO: <name>:<hash> will go somewhere around here. // TODO: <name>:<hash> will go somewhere around here.
manifestProperties.setProperty("unique_name", "$moduleName") manifestProperties.setProperty(KLIB_PROPERTY_UNIQUE_NAME, moduleName)
manifestProperties.setProperty("abi_version", "$currentAbiVersion") manifestProperties.setProperty(KLIB_PROPERTY_ABI_VERSION, currentAbiVersion.toString())
} }
var llvmModule: LLVMModuleRef? = null var llvmModule: LLVMModuleRef? = null
@@ -85,14 +88,14 @@ class LibraryWriterImpl(override val libDir: File, moduleName: String, currentAb
File(library).copyTo(File(includedDir, basename)) File(library).copyTo(File(includedDir, basename))
} }
override fun addLinkDependencies(libraries: List<KonanLibraryReader>) { override fun addLinkDependencies(libraries: List<KonanLibrary>) {
if (libraries.isEmpty()) { if (libraries.isEmpty()) {
manifestProperties.remove("depends") manifestProperties.remove(KLIB_PROPERTY_DEPENDS)
// make sure there are no leftovers from the .def file. // make sure there are no leftovers from the .def file.
return return
} else { } else {
val newValue = libraries .map { it.uniqueName } . joinToString(" ") val newValue = libraries.joinToString(" ") { it.uniqueName }
manifestProperties.setProperty("depends", newValue) manifestProperties.setProperty(KLIB_PROPERTY_DEPENDS, newValue)
} }
} }
@@ -115,18 +118,18 @@ class LibraryWriterImpl(override val libDir: File, moduleName: String, currentAb
} }
internal fun buildLibrary( internal fun buildLibrary(
natives: List<String>, natives: List<String>,
included: List<String>, included: List<String>,
linkDependencies: List<KonanLibraryReader>, linkDependencies: List<KonanLibrary>,
linkData: LinkData, linkData: LinkData,
abiVersion: Int, abiVersion: Int,
target: KonanTarget, target: KonanTarget,
output: String, output: String,
moduleName: String, moduleName: String,
llvmModule: LLVMModuleRef, llvmModule: LLVMModuleRef,
nopack: Boolean, nopack: Boolean,
manifest: String?, manifest: String?,
dataFlowGraph: ByteArray?): KonanLibraryWriter { dataFlowGraph: ByteArray?): KonanLibraryWriter {
val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack) val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack)
@@ -16,10 +16,10 @@
package org.jetbrains.kotlin.backend.konan.library.impl package org.jetbrains.kotlin.backend.konan.library.impl
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
internal class MetadataWriterImpl(library: KonanLibrary): KonanLibrary by library { internal class MetadataWriterImpl(libraryLayout: KonanLibraryLayout): KonanLibraryLayout by libraryLayout {
fun addLinkData(linkData: LinkData) { fun addLinkData(linkData: LinkData) {
moduleHeaderFile.writeBytes(linkData.module) moduleHeaderFile.writeBytes(linkData.module)
@@ -20,7 +20,7 @@ import llvm.LLVMTypeRef
import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract import org.jetbrains.kotlin.backend.konan.descriptors.isAbstract
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.backend.konan.isInlined import org.jetbrains.kotlin.backend.konan.isInlined
import org.jetbrains.kotlin.konan.library.KonanLibraryReader import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR import org.jetbrains.kotlin.backend.konan.optimizations.DataFlowIR
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor import org.jetbrains.kotlin.descriptors.PropertyAccessorDescriptor
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor
import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.konan.library.uniqueName
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.constants.StringValue import org.jetbrains.kotlin.resolve.constants.StringValue
@@ -322,5 +323,5 @@ internal fun ModuleDescriptor.privateClassSymbolName(index: Int, className: Stri
internal val String.moduleConstructorName internal val String.moduleConstructorName
get() = "_Konan_init_${this}" get() = "_Konan_init_${this}"
internal val KonanLibraryReader.moduleConstructorName internal val KonanLibrary.moduleConstructorName
get() = uniqueName.moduleConstructorName get() = uniqueName.moduleConstructorName
@@ -25,7 +25,7 @@ import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.descriptors.findPackage import org.jetbrains.kotlin.backend.konan.descriptors.findPackage
import org.jetbrains.kotlin.backend.konan.hash.GlobalHash import org.jetbrains.kotlin.backend.konan.hash.GlobalHash
import org.jetbrains.kotlin.backend.konan.irasdescriptors.* import org.jetbrains.kotlin.backend.konan.irasdescriptors.*
import org.jetbrains.kotlin.konan.library.KonanLibraryReader import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.withResolvedDependencies import org.jetbrains.kotlin.backend.konan.library.withResolvedDependencies
import org.jetbrains.kotlin.descriptors.konan.CompiledKonanModuleOrigin import org.jetbrains.kotlin.descriptors.konan.CompiledKonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin import org.jetbrains.kotlin.descriptors.konan.CurrentKonanModuleOrigin
@@ -323,7 +323,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
return function return function
} }
private val usedLibraries = mutableSetOf<KonanLibraryReader>() private val usedLibraries = mutableSetOf<KonanLibrary>()
val imports = object : LlvmImports { val imports = object : LlvmImports {
@@ -332,7 +332,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
override fun add(origin: CompiledKonanModuleOrigin) { override fun add(origin: CompiledKonanModuleOrigin) {
val reader = when (origin) { val reader = when (origin) {
CurrentKonanModuleOrigin -> return CurrentKonanModuleOrigin -> return
is DeserializedKonanModuleOrigin -> origin.reader as KonanLibraryReader is DeserializedKonanModuleOrigin -> origin.reader as KonanLibrary
} }
if (reader !in allLibraries) { if (reader !in allLibraries) {
@@ -343,19 +343,19 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
} }
} }
val librariesToLink: List<KonanLibraryReader> by lazy { val librariesToLink: List<KonanLibrary> by lazy {
context.config.immediateLibraries context.config.immediateLibraries
.filter { (!it.isDefaultLibrary && !context.config.purgeUserLibs) || it in usedLibraries } .filter { (!it.isDefaultLibrary && !context.config.purgeUserLibs) || it in usedLibraries }
.withResolvedDependencies() .withResolvedDependencies()
.topoSort() .topoSort()
} }
private fun List<KonanLibraryReader>.topoSort(): List<KonanLibraryReader> { private fun List<KonanLibrary>.topoSort(): List<KonanLibrary> {
var sorted = mutableListOf<KonanLibraryReader>() var sorted = mutableListOf<KonanLibrary>()
val visited = mutableSetOf<KonanLibraryReader>() val visited = mutableSetOf<KonanLibrary>()
val tempMarks = mutableSetOf<KonanLibraryReader>() val tempMarks = mutableSetOf<KonanLibrary>()
fun visit(node: KonanLibraryReader, result: MutableList<KonanLibraryReader>) { fun visit(node: KonanLibrary, result: MutableList<KonanLibrary>) {
if (visited.contains(node)) return if (visited.contains(node)) return
if (tempMarks.contains(node)) error("Cyclic dependency in library graph.") if (tempMarks.contains(node)) error("Cyclic dependency in library graph.")
tempMarks.add(node) tempMarks.add(node)
@@ -373,7 +373,7 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
return sorted return sorted
} }
val librariesForLibraryManifest: List<KonanLibraryReader> get() { val librariesForLibraryManifest: List<KonanLibrary> get() {
// Note: library manifest should contain the list of all user libraries and frontend-used default libraries. // Note: library manifest should contain the list of all user libraries and frontend-used default libraries.
// However this would result into linking too many default libraries into the application which uses current // However this would result into linking too many default libraries into the application which uses current
// library. This problem should probably be fixed by adding different kind of dependencies to library // library. This problem should probably be fixed by adding different kind of dependencies to library
@@ -1,44 +1,64 @@
package org.jetbrains.kotlin.konan.library package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.propertyList
import org.jetbrains.kotlin.name.FqName
// This scheme describes the Kotlin/Native Library (klib) layout. const val KLIB_PROPERTY_ABI_VERSION = "abi_version"
interface KonanLibraryLayout { 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"
val libDir: File interface KonanLibrary {
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")
}
interface KonanLibrary: KonanLibraryLayout {
val libraryName: String val libraryName: String
val libraryFile: File
// 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
// FIXME: ddol: to be refactored into some global resolution context
val isDefaultLibrary: Boolean get() = false
val isNeededForLink: Boolean get() = true
val resolvedDependencies: MutableList<KonanLibrary>
fun markPackageAccessed(fqName: String)
} }
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(' ')
.map { it.trim() }
.filter { it.isNotEmpty() }
.map { FqName(it) }
val KonanLibrary.includedHeaders
get() = manifestProperties.getProperty(KLIB_PROPERTY_INCLUDED_HEADERS).split(' ')
@@ -0,0 +1,45 @@
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"
// 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")
}
@@ -1,28 +0,0 @@
package org.jetbrains.kotlin.konan.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.properties.Properties
interface KonanLibraryReader {
val libraryFile: File
val libraryName: String
val manifestProperties: Properties
val uniqueName: String
val linkerOpts: List<String>
val unresolvedDependencies: List<String>
val bitcodePaths: List<String>
val includedPaths: List<String>
val dataFlowGraph: ByteArray?
val moduleHeaderData: ByteArray
fun packageMetadata(fqName: String): ByteArray
val isDefaultLibrary: Boolean get() = false
// FIXME: ddol: to be refactored into some global resolution context
val isNeededForLink: Boolean get() = true
val resolvedDependencies: MutableList<KonanLibraryReader>
fun markPackageAccessed(fqName: String)
}
@@ -0,0 +1,32 @@
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.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 createKonanLibraryReader(
libraryFile: File,
currentAbiVersion: Int,
target: KonanTarget? = null,
isDefaultLibrary: Boolean = false,
metadataReader: MetadataReader = DefaultMetadataReaderImpl
): KonanLibrary = KonanLibraryImpl(libraryFile, currentAbiVersion, target, isDefaultLibrary, metadataReader)
@@ -1,6 +1,6 @@
package org.jetbrains.kotlin.konan.library package org.jetbrains.kotlin.konan.library
interface MetadataReader { interface MetadataReader {
fun loadSerializedModule(library: KonanLibrary): ByteArray fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
fun loadSerializedPackageFragment(library: KonanLibrary, fqName: String): ByteArray fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String): ByteArray
} }
@@ -1,12 +1,13 @@
package org.jetbrains.kotlin.konan.library.impl package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.library.KonanLibrary import org.jetbrains.kotlin.konan.library.KonanLibraryLayout
import org.jetbrains.kotlin.konan.library.MetadataReader import org.jetbrains.kotlin.konan.library.MetadataReader
object DefaultMetadataReaderImpl : MetadataReader { internal object DefaultMetadataReaderImpl : MetadataReader {
override fun loadSerializedModule(library: KonanLibrary): ByteArray = library.moduleHeaderFile.readBytes() override fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray =
libraryLayout.moduleHeaderFile.readBytes()
override fun loadSerializedPackageFragment(library: KonanLibrary, fqName: String): ByteArray = override fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String): ByteArray =
library.packageFile(fqName).readBytes() libraryLayout.packageFile(fqName).readBytes()
} }
@@ -1,85 +1,79 @@
package org.jetbrains.kotlin.konan.library.impl 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.KonanLibrary
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent import org.jetbrains.kotlin.konan.library.MetadataReader
import org.jetbrains.kotlin.konan.file.* 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.target.KonanTarget
import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions
import org.jetbrains.kotlin.konan.util.substitute
import org.jetbrains.kotlin.serialization.konan.emptyPackages
const val KLIB_FILE_EXTENSION = "klib" internal class KonanLibraryImpl(
const val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION" override val libraryFile: File,
private val currentAbiVersion: Int,
internal val target: KonanTarget?,
override val isDefaultLibrary: Boolean,
private val metadataReader: MetadataReader
) : KonanLibrary {
class ZippedKonanLibrary(val klibFile: File, override val target: KonanTarget? = null): KonanLibrary { // For the zipped libraries inPlace gives files from zip file system
init { // whereas realFiles extracts them to /tmp.
check(klibFile.exists) { "Could not find $klibFile." } // For unzipped libraries inPlace and realFiles are the same
check(klibFile.isFile) { "Expected $klibFile to be a regular file." } // providing files in the library directory.
private val inPlace = createKonanLibraryLayout(libraryFile, target)
private val realFiles = inPlace.realFiles
val extension = klibFile.extension override val libraryName
check(extension.isEmpty() || extension == KLIB_FILE_EXTENSION) { "Unexpected file extension: $extension" } get() = inPlace.libraryName
override val manifestProperties: Properties by lazy {
val properties = inPlace.manifestFile.loadProperties()
if (target != null) substitute(properties, defaultTargetSubstitutions(target))
properties
} }
override val libraryName = klibFile.path.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT) override val abiVersion: String
get() {
override val libDir by lazy { klibFile.asZipRoot } val manifestAbiVersion = manifestProperties.getProperty(KLIB_PROPERTY_ABI_VERSION)
check(currentAbiVersion.toString() == manifestAbiVersion) {
fun unpackTo(newDir: File) { "ABI version mismatch. Compiler expects: $currentAbiVersion, the library is $manifestAbiVersion"
if (newDir.exists) { }
if (newDir.isDirectory) return manifestAbiVersion
newDir.deleteRecursively() }
else
newDir.delete() 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 var isNeededForLink: Boolean = false
private set
override val resolvedDependencies = mutableListOf<KonanLibrary>()
override fun markPackageAccessed(fqName: String) {
if (!isNeededForLink // fast path
&& !emptyPackages.contains(fqName)) {
isNeededForLink = true
} }
libDir.recursiveCopyTo(newDir)
check(newDir.exists) { "Could not unpack $klibFile as $newDir." }
} }
private val emptyPackages by lazy { emptyPackages(moduleHeaderData) }
} }
// 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 ZippedKonanLibrary.
private class FileExtractor(zippedLibrary: KonanLibrary): KonanLibrary by zippedLibrary {
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
}
}
class UnzippedKonanLibrary(override val libDir: File, override val target: KonanTarget? = null): KonanLibrary {
override val libraryName = libDir.path
val targetList: List<String> by lazy { targetsDir.listFiles.map { it.name } }
}
fun KonanLibrary(klib: File, target: KonanTarget? = null) =
if (klib.isFile) ZippedKonanLibrary(klib, target) else UnzippedKonanLibrary(klib, target)
internal val KonanLibrary.realFiles
get() = when (this) {
is ZippedKonanLibrary -> FileExtractor(this)
// Unpacked library just provides its own files.
is UnzippedKonanLibrary -> this
else -> error("Provide an extractor for your container.")
}
@@ -0,0 +1,79 @@
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
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
private class ZippedKonanLibraryLayout(val klibFile: File, override val target: KonanTarget? = null): KonanLibraryLayout {
init { zippedKonanLibraryChecks(klibFile) }
override val libraryName = klibFile.path.removeSuffixIfPresent(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? = null): 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 ZippedKonanLibrary.
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.")
}
@@ -1,83 +0,0 @@
package org.jetbrains.kotlin.konan.library.impl
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KonanLibraryReader
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.properties.propertyString
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions
import org.jetbrains.kotlin.konan.util.substitute
import org.jetbrains.kotlin.serialization.konan.emptyPackages
class LibraryReaderImpl(
override val libraryFile: File,
val currentAbiVersion: Int,
val target: KonanTarget? = null,
override val isDefaultLibrary: Boolean = false,
private val metadataReader: MetadataReader = DefaultMetadataReaderImpl
) : KonanLibraryReader {
// 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 = KonanLibrary(libraryFile, target)
private val realFiles = inPlace.realFiles
override val manifestProperties: Properties by lazy {
val properties = inPlace.manifestFile.loadProperties()
if (target != null) substitute(properties, defaultTargetSubstitutions(target))
properties
}
val abiVersion: String
get() {
val manifestAbiVersion = manifestProperties.getProperty("abi_version")
check("$currentAbiVersion" == manifestAbiVersion) {
"ABI version mismatch. Compiler expects: $currentAbiVersion, the library is $manifestAbiVersion"
}
return manifestAbiVersion
}
val targetList = inPlace.targetsDir.listFiles.map { it.name }
override val dataFlowGraph by lazy { inPlace.dataFlowGraphFile.let { if (it.exists) it.readBytes() else null } }
override val libraryName
get() = inPlace.libraryName
override val uniqueName
get() = manifestProperties.propertyString("unique_name")!!
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 linkerOpts: List<String>
get() = manifestProperties.propertyList("linkerOpts", target!!.visibleName)
override val unresolvedDependencies: List<String>
get() = manifestProperties.propertyList("depends")
override val resolvedDependencies = mutableListOf<KonanLibraryReader>()
override val moduleHeaderData: ByteArray by lazy { metadataReader.loadSerializedModule(inPlace) }
override var isNeededForLink: Boolean = false
private set
private val emptyPackages by lazy { emptyPackages(moduleHeaderData) }
override fun markPackageAccessed(fqName: String) {
if (!isNeededForLink // fast path
&& !emptyPackages.contains(fqName)) {
isNeededForLink = true
}
}
override fun packageMetadata(fqName: String) = metadataReader.loadSerializedPackageFragment(inPlace, fqName)
}
@@ -7,8 +7,10 @@ import org.jetbrains.kotlin.descriptors.konan.DeserializedKonanModuleOrigin
import org.jetbrains.kotlin.descriptors.konan.createKonanModuleDescriptor import org.jetbrains.kotlin.descriptors.konan.createKonanModuleDescriptor
import org.jetbrains.kotlin.descriptors.konan.interop.InteropFqNames import org.jetbrains.kotlin.descriptors.konan.interop.InteropFqNames
import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.konan.library.KonanLibraryReader import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.name.FqName 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.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration import org.jetbrains.kotlin.resolve.CompilerDeserializationConfiguration
import org.jetbrains.kotlin.serialization.deserialization.* import org.jetbrains.kotlin.serialization.deserialization.*
@@ -19,7 +21,7 @@ import org.jetbrains.kotlin.storage.StorageManager
interface KonanModuleDescriptorFactory { interface KonanModuleDescriptorFactory {
fun createModuleDescriptor( fun createModuleDescriptor(
libraryReader: KonanLibraryReader, libraryReader: KonanLibrary,
specifics: LanguageVersionSettings, specifics: LanguageVersionSettings,
storageManager: StorageManager = LockBasedStorageManager() storageManager: StorageManager = LockBasedStorageManager()
): ModuleDescriptor ): ModuleDescriptor
@@ -28,7 +30,7 @@ interface KonanModuleDescriptorFactory {
object DefaultKonanModuleDescriptorFactory: KonanModuleDescriptorFactory { object DefaultKonanModuleDescriptorFactory: KonanModuleDescriptorFactory {
override fun createModuleDescriptor( override fun createModuleDescriptor(
libraryReader: KonanLibraryReader, libraryReader: KonanLibrary,
specifics: LanguageVersionSettings, specifics: LanguageVersionSettings,
storageManager: StorageManager storageManager: StorageManager
): ModuleDescriptorImpl { ): ModuleDescriptorImpl {
@@ -57,7 +59,7 @@ object DefaultKonanModuleDescriptorFactory: KonanModuleDescriptorFactory {
} }
private fun createPackageFragmentProvider( private fun createPackageFragmentProvider(
libraryReader: KonanLibraryReader, libraryReader: KonanLibrary,
fragmentNames: List<String>, fragmentNames: List<String>,
storageManager: StorageManager, storageManager: StorageManager,
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
@@ -106,21 +108,17 @@ object DefaultKonanModuleDescriptorFactory: KonanModuleDescriptorFactory {
} }
private fun getSyntheticPackageFragments( private fun getSyntheticPackageFragments(
libraryReader: KonanLibraryReader, libraryReader: KonanLibrary,
moduleDescriptor: ModuleDescriptor, moduleDescriptor: ModuleDescriptor,
konanPackageFragments: List<KonanPackageFragment> konanPackageFragments: List<KonanPackageFragment>
): List<PackageFragmentDescriptor> { ): List<PackageFragmentDescriptor> {
if (libraryReader.manifestProperties.getProperty("interop") != "true") return emptyList() if (!libraryReader.isInterop) return emptyList()
val packageFqName = libraryReader.manifestProperties.getProperty("package")?.let { FqName(it) } val packageFqName = libraryReader.packageFqName
?: error("Inconsistent manifest: interop library ${libraryReader.libraryName} should have `package` specified") ?: error("Inconsistent manifest: interop library ${libraryReader.libraryName} should have `package` specified")
val exportForwardDeclarations = libraryReader.manifestProperties.getProperty("exportForwardDeclarations") val exportForwardDeclarations = libraryReader.exportForwardDeclarations
.split(' ')
.map { it.trim() }
.filter { it.isNotEmpty() }
.map { FqName(it) }
val interopPackageFragments = konanPackageFragments.filter { it.fqName == packageFqName } val interopPackageFragments = konanPackageFragments.filter { it.fqName == packageFqName }
@@ -1,7 +1,7 @@
package org.jetbrains.kotlin.serialization.konan package org.jetbrains.kotlin.serialization.konan
import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.library.KonanLibraryReader import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl import org.jetbrains.kotlin.metadata.deserialization.NameResolverImpl
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.storage.StorageManager
class KonanPackageFragment( class KonanPackageFragment(
val fqNameString: String, val fqNameString: String,
val reader: KonanLibraryReader, val reader: KonanLibrary,
storageManager: StorageManager, storageManager: StorageManager,
module: ModuleDescriptor module: ModuleDescriptor
) : DeserializedPackageFragment(FqName(fqNameString), storageManager, module) { ) : DeserializedPackageFragment(FqName(fqNameString), storageManager, module) {
@@ -24,11 +24,10 @@ import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION_WITH_DOT
import org.jetbrains.kotlin.konan.library.KonanLibrarySearchPathResolver import org.jetbrains.kotlin.konan.library.KonanLibrarySearchPathResolver
import org.jetbrains.kotlin.konan.library.impl.KLIB_FILE_EXTENSION_WITH_DOT import org.jetbrains.kotlin.konan.library.createKonanLibraryReader
import org.jetbrains.kotlin.konan.library.impl.LibraryReaderImpl import org.jetbrains.kotlin.konan.library.unpackZippedKonanLibraryTo
import org.jetbrains.kotlin.konan.library.impl.UnzippedKonanLibrary
import org.jetbrains.kotlin.konan.library.impl.ZippedKonanLibrary
import org.jetbrains.kotlin.konan.target.Distribution import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.konan.target.PlatformManager import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.konan.util.DependencyProcessor import org.jetbrains.kotlin.konan.util.DependencyProcessor
@@ -107,7 +106,7 @@ class Library(val name: String, val requestedRepository: String?, val target: St
val repository = requestedRepository?.File() ?: defaultRepository val repository = requestedRepository?.File() ?: defaultRepository
fun info() { fun info() {
val library = libraryInRepoOrCurrentDir(repository, name) val library = libraryInRepoOrCurrentDir(repository, name)
val reader = LibraryReaderImpl(library, currentAbiVersion) val reader = createKonanLibraryReader(library, currentAbiVersion)
val headerAbiVersion = reader.abiVersion val headerAbiVersion = reader.abiVersion
val moduleName = ModuleDeserializer(reader.moduleHeaderData).moduleName val moduleName = ModuleDeserializer(reader.moduleHeaderData).moduleName
@@ -122,30 +121,30 @@ class Library(val name: String, val requestedRepository: String?, val target: St
fun install() { fun install() {
Library(File(name).name.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT), requestedRepository, target).remove(true) Library(File(name).name.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT), requestedRepository, target).remove(true)
val library = ZippedKonanLibrary(libraryInCurrentDir(name)) val klibFile = libraryInCurrentDir(name)
val newLibDir = File(repository, library.libraryName.File().name) val newLibDir = File(repository, klibFile.name.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT))
newLibDir.mkdirs()
library.unpackTo(newLibDir) klibFile.unpackZippedKonanLibraryTo(newLibDir)
} }
fun remove(blind: Boolean = false) { fun remove(blind: Boolean = false) {
if (!repository.exists) error("Repository does not exist: $repository") if (!repository.exists) error("Repository does not exist: $repository")
val reader = try { val libDir = try {
val library = libraryInRepo(repository, name) val library = libraryInRepo(repository, name)
if (blind) warn("Removing The previously installed $name from $repository.") if (blind) warn("Removing The previously installed $name from $repository.")
UnzippedKonanLibrary(library) library
} catch (e: Throwable) { } catch (e: Throwable) {
if (!blind) println(e.message) if (!blind) println(e.message)
null null
} }
reader?.libDir?.deleteRecursively() libDir?.deleteRecursively()
} }
fun contents(output: Appendable = out) { fun contents(output: Appendable = out) {
val reader = LibraryReaderImpl(libraryInRepoOrCurrentDir(repository, name), currentAbiVersion) val reader = createKonanLibraryReader(libraryInRepoOrCurrentDir(repository, name), currentAbiVersion)
val versionSpec = LanguageVersionSettingsImpl(currentLanguageVersion, currentApiVersion) val versionSpec = LanguageVersionSettingsImpl(currentLanguageVersion, currentApiVersion)
val module = DefaultKonanModuleDescriptorFactory.createModuleDescriptor(reader, versionSpec) val module = DefaultKonanModuleDescriptorFactory.createModuleDescriptor(reader, versionSpec)
val defaultModules = mutableListOf<ModuleDescriptorImpl>() val defaultModules = mutableListOf<ModuleDescriptorImpl>()
@@ -158,7 +157,7 @@ class Library(val name: String, val requestedRepository: String?, val target: St
resolver.defaultLinks(false, true) resolver.defaultLinks(false, true)
.mapTo(defaultModules) { .mapTo(defaultModules) {
DefaultKonanModuleDescriptorFactory.createModuleDescriptor( DefaultKonanModuleDescriptorFactory.createModuleDescriptor(
LibraryReaderImpl(it, currentAbiVersion), versionSpec) createKonanLibraryReader(it, currentAbiVersion), versionSpec)
} }
} }
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.cli.utilities
import org.jetbrains.kotlin.backend.konan.library.resolveLibrariesRecursive import org.jetbrains.kotlin.backend.konan.library.resolveLibrariesRecursive
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.defaultResolver import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.library.includedHeaders
import org.jetbrains.kotlin.konan.library.packageFqName
import org.jetbrains.kotlin.konan.target.PlatformManager import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.native.interop.gen.jvm.interop import org.jetbrains.kotlin.native.interop.gen.jvm.interop
import org.jetbrains.kotlin.utils.addIfNotNull import org.jetbrains.kotlin.utils.addIfNotNull
@@ -71,13 +73,11 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String> {
libraries, target, noStdLib = true, noDefaultLibs = noDefaultLibs libraries, target, noStdLib = true, noDefaultLibs = noDefaultLibs
) )
val importArgs = allLibraries.flatMap { val importArgs = allLibraries.flatMap {libraryReader ->
val manifestProperties = it.manifestProperties
// TODO: handle missing properties? // TODO: handle missing properties?
manifestProperties["package"]?.let { libraryReader.packageFqName?.asString()?.let { packageFqName ->
val pkg = it as String val headerIds = libraryReader.includedHeaders
val headerIds = (manifestProperties["includedHeaders"] as String).split(' ') val arg = "$packageFqName:${headerIds.joinToString(";")}"
val arg = "$pkg:${headerIds.joinToString(";")}"
listOf("-import", arg) listOf("-import", arg)
} ?: emptyList() } ?: emptyList()
} }