Splitted library writer into kotlin and konan parts
Moved to util-io and util-klib for klib code commonization Moved the common writer to Kotlin workspace
This commit is contained in:
committed by
alexander-gorshenev
parent
63d763338d
commit
df02804be1
@@ -63,4 +63,6 @@ jar {
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
|
||||
compile "org.jetbrains.kotlin:kotlin-native-utils:$kotlinVersion"
|
||||
compile "org.jetbrains.kotlin:kotlin-util-io:$kotlinVersion"
|
||||
compile "org.jetbrains.kotlin:kotlin-util-klib:$kotlinVersion"
|
||||
}
|
||||
|
||||
@@ -3,63 +3,30 @@ 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.library.*
|
||||
|
||||
const val KLIB_PROPERTY_ABI_VERSION = "abi_version"
|
||||
const val KLIB_PROPERTY_COMPILER_VERSION = "compiler_version"
|
||||
const val KLIB_PROPERTY_DEPENDENCY_VERSION = "dependency_version"
|
||||
const val KLIB_PROPERTY_LIBRARY_VERSION = "library_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 linkerOpts: List<String>
|
||||
|
||||
// Paths:
|
||||
val bitcodePaths: List<String>
|
||||
val includedPaths: List<String>
|
||||
|
||||
interface TargetedLibrary {
|
||||
val targetList: List<String>
|
||||
val versions: KonanLibraryVersioning
|
||||
|
||||
val dataFlowGraph: ByteArray?
|
||||
val moduleHeaderData: ByteArray
|
||||
fun packageMetadataParts(fqName: String): Set<String>
|
||||
fun packageMetadata(fqName: String, partName: String): ByteArray
|
||||
|
||||
val irHeader: ByteArray?
|
||||
fun irDeclaration(index: Long, isLocal: Boolean): ByteArray
|
||||
val includedPaths: List<String>
|
||||
}
|
||||
|
||||
val KonanLibrary.uniqueName
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_UNIQUE_NAME)!!
|
||||
interface BitcodeLibrary : TargetedLibrary {
|
||||
val bitcodePaths: List<String>
|
||||
}
|
||||
|
||||
val KonanLibrary.unresolvedDependencies: List<UnresolvedLibrary>
|
||||
get() = manifestProperties.propertyList(KLIB_PROPERTY_DEPENDS, escapeInQuotes = true)
|
||||
.map {
|
||||
UnresolvedLibrary(it, manifestProperties.getProperty("dependency_version_$it"))
|
||||
}
|
||||
interface KonanLibrary : BitcodeLibrary, KotlinLibrary {
|
||||
val linkerOpts: List<String>
|
||||
}
|
||||
|
||||
val KonanLibrary.isInterop
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_INTEROP) == "true"
|
||||
|
||||
val KonanLibrary.packageFqName
|
||||
val KonanLibrary.packageFqName: String?
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_PACKAGE)
|
||||
|
||||
val KonanLibrary.exportForwardDeclarations
|
||||
|
||||
+16
-37
@@ -18,55 +18,34 @@ package org.jetbrains.kotlin.konan.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.library.IrKotlinLibraryLayout
|
||||
import org.jetbrains.kotlin.library.KotlinLibraryLayout
|
||||
import org.jetbrains.kotlin.library.MetadataKotlinLibraryLayout
|
||||
|
||||
/**
|
||||
* This scheme describes the Kotlin/Native Library (KLIB) layout.
|
||||
*/
|
||||
interface KonanLibraryLayout {
|
||||
|
||||
val libraryName: String
|
||||
|
||||
val libDir: File
|
||||
interface TargetedKotlinLibraryLayout : KotlinLibraryLayout {
|
||||
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 includedDir
|
||||
get() = File(targetDir, "included")
|
||||
}
|
||||
|
||||
interface BitcodeKotlinLibraryLayout : TargetedKotlinLibraryLayout, KotlinLibraryLayout {
|
||||
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 packageFragmentsDir(packageName: String)
|
||||
= File(linkdataDir, if (packageName == "") "root_package" else "package_$packageName")
|
||||
|
||||
fun packageFragmentFile(packageFqName: String, partName: String) =
|
||||
File(packageFragmentsDir(packageFqName), "$partName$KLIB_METADATA_FILE_EXTENSION_WITH_DOT")
|
||||
val irDir
|
||||
get() = File(libDir, "ir")
|
||||
val irFile
|
||||
get() = File(irDir, "irCombined.knd")
|
||||
val irHeader
|
||||
get() = File(irDir, "irHeaders.kni")
|
||||
val irIndex: File
|
||||
get() = File(irDir, "uniqIdTableDump.txt")
|
||||
|
||||
// TODO: Experiment with separate bitcode files.
|
||||
// Per package or per class.
|
||||
val mainBitcodeFile
|
||||
get() = File(kotlinDir, "program.kt.bc")
|
||||
val mainBitcodeFileName
|
||||
get() = mainBitcodeFile.path
|
||||
}
|
||||
|
||||
interface KonanLibraryLayout : MetadataKotlinLibraryLayout, BitcodeKotlinLibraryLayout, IrKotlinLibraryLayout
|
||||
|
||||
@@ -1,49 +0,0 @@
|
||||
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.file.withMutableZipFileSystem
|
||||
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.target.KonanTarget
|
||||
|
||||
const val KLIB_FILE_EXTENSION = "klib"
|
||||
const val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION"
|
||||
|
||||
const val KLIB_METADATA_FILE_EXTENSION = "knm"
|
||||
const val KLIB_METADATA_FILE_EXTENSION_WITH_DOT = ".$KLIB_METADATA_FILE_EXTENSION"
|
||||
|
||||
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()
|
||||
}
|
||||
|
||||
this.withMutableZipFileSystem {
|
||||
it.file("/").recursiveCopyTo(newDir)
|
||||
}
|
||||
check(newDir.exists) { "Could not unpack $this as $newDir." }
|
||||
}
|
||||
|
||||
val List<String>.toUnresolvedLibraries
|
||||
get() = this.map {
|
||||
|
||||
val version = it.substringAfterLast('@', "")
|
||||
.let { if (it.isEmpty()) null else it}
|
||||
val name = it.substringBeforeLast('@')
|
||||
UnresolvedLibrary(name, version)
|
||||
}
|
||||
|
||||
fun createKonanLibrary(
|
||||
libraryFile: File,
|
||||
target: KonanTarget? = null,
|
||||
isDefault: Boolean = false,
|
||||
metadataReader: MetadataReader = DefaultMetadataReaderImpl
|
||||
): KonanLibrary = KonanLibraryImpl(libraryFile, target, isDefault, metadataReader)
|
||||
-28
@@ -1,28 +0,0 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.parseKonanVersion
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jetbrains.kotlin.konan.parseKonanAbiVersion
|
||||
|
||||
|
||||
data class KonanLibraryVersioning(
|
||||
val libraryVersion: String?,
|
||||
val compilerVersion: KonanVersion?,
|
||||
val abiVersion: KonanAbiVersion?
|
||||
)
|
||||
|
||||
fun Properties.writeKonanLibraryVersioning(versions: KonanLibraryVersioning) {
|
||||
versions.abiVersion ?. let { this.setProperty(KLIB_PROPERTY_ABI_VERSION, it.toString()) }
|
||||
versions.libraryVersion ?. let { this.setProperty(KLIB_PROPERTY_LIBRARY_VERSION, it) }
|
||||
versions.compilerVersion ?. let { this.setProperty(KLIB_PROPERTY_COMPILER_VERSION, "${versions.compilerVersion.toString(true, true)}") }
|
||||
}
|
||||
|
||||
fun Properties.readKonanLibraryVersioning(): KonanLibraryVersioning {
|
||||
val abiVersion = this.getProperty(KLIB_PROPERTY_ABI_VERSION)?.parseKonanAbiVersion()
|
||||
val libraryVersion = this.getProperty(KLIB_PROPERTY_LIBRARY_VERSION)
|
||||
val compilerVersion = this.getProperty(KLIB_PROPERTY_COMPILER_VERSION)?.parseKonanVersion()
|
||||
|
||||
return KonanLibraryVersioning(abiVersion = abiVersion, libraryVersion = libraryVersion, compilerVersion = compilerVersion)
|
||||
}
|
||||
@@ -1,6 +0,0 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
interface MetadataReader {
|
||||
fun loadSerializedModule(libraryLayout: KonanLibraryLayout): ByteArray
|
||||
fun loadSerializedPackageFragment(libraryLayout: KonanLibraryLayout, fqName: String, partName: String): ByteArray
|
||||
}
|
||||
@@ -1,13 +1,17 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
|
||||
import org.jetbrains.kotlin.konan.library.impl.createKonanLibrary
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.*
|
||||
import kotlin.system.exitProcess
|
||||
import org.jetbrains.kotlin.library.KLIB_FILE_EXTENSION_WITH_DOT
|
||||
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
||||
import org.jetbrains.kotlin.library.UnresolvedLibrary
|
||||
import org.jetbrains.kotlin.library.uniqueName
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the constants below:
|
||||
const val KONAN_STDLIB_NAME = "stdlib"
|
||||
@@ -24,7 +28,7 @@ interface SearchPathResolver : WithLogger {
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this interface!
|
||||
interface SearchPathResolverWithTarget: SearchPathResolver {
|
||||
val target: KonanTarget
|
||||
val knownAbiVersions: List<KonanAbiVersion>?
|
||||
val knownAbiVersions: List<KotlinAbiVersion>?
|
||||
val knownCompilerVersions: List<KonanVersion>?
|
||||
}
|
||||
|
||||
@@ -47,7 +51,7 @@ fun defaultResolver(
|
||||
repositories,
|
||||
directLibs,
|
||||
target,
|
||||
listOf(KonanAbiVersion.CURRENT),
|
||||
listOf(KotlinAbiVersion.CURRENT),
|
||||
compatibleCompilerVersions,
|
||||
distribution.klib,
|
||||
distribution.localKonanDir.absolutePath,
|
||||
@@ -179,7 +183,7 @@ internal class KonanLibraryProperResolver(
|
||||
repositories: List<String>,
|
||||
directLibs: List<String>,
|
||||
override val target: KonanTarget,
|
||||
override val knownAbiVersions: List<KonanAbiVersion>?,
|
||||
override val knownAbiVersions: List<KotlinAbiVersion>?,
|
||||
override val knownCompilerVersions: List<KonanVersion>?,
|
||||
distributionKlib: String?,
|
||||
localKonanDir: String?,
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
data class UnresolvedLibrary(
|
||||
val path: String,
|
||||
val libraryVersion: String?) {
|
||||
|
||||
fun substitutePath(newPath: String): UnresolvedLibrary {
|
||||
return UnresolvedLibrary(newPath, libraryVersion)
|
||||
}
|
||||
}
|
||||
-94
@@ -1,94 +0,0 @@
|
||||
/**
|
||||
* Copyright 2010-2019 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.library.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import java.io.RandomAccessFile
|
||||
import java.nio.channels.FileChannel
|
||||
|
||||
data class DeclarationId(val id: Long, val isLocal: Boolean)
|
||||
|
||||
class CombinedIrFileReader(file: File) {
|
||||
private val buffer = file.map(FileChannel.MapMode.READ_ONLY)
|
||||
private val declarationToOffsetSize = mutableMapOf<DeclarationId, Pair<Int, Int>>()
|
||||
|
||||
init {
|
||||
val declarationsCount = buffer.int
|
||||
for (i in 0 until declarationsCount) {
|
||||
val id = buffer.long
|
||||
val isLocal = buffer.int != 0
|
||||
val offset = buffer.int
|
||||
val size = buffer.int
|
||||
declarationToOffsetSize[DeclarationId(id, isLocal)] = offset to size
|
||||
}
|
||||
}
|
||||
|
||||
fun declarationBytes(id: DeclarationId): ByteArray {
|
||||
val offsetSize = declarationToOffsetSize[id] ?: throw Error("No declaration with $id here")
|
||||
val result = ByteArray(offsetSize.second)
|
||||
buffer.position(offsetSize.first)
|
||||
buffer.get(result, 0, offsetSize.second)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
private const val SINGLE_INDEX_RECORD_SIZE = 20 // sizeof(Long) + 3 * sizeof(Int).
|
||||
private const val INDEX_HEADER_SIZE = 4 // sizeof(Int).
|
||||
|
||||
class CombinedIrFileWriter(val declarationCount: Int) {
|
||||
private var currentDeclaration = 0
|
||||
private var currentPosition = 0
|
||||
private val file = org.jetbrains.kotlin.konan.file.createTempFile("ir").deleteOnExit()
|
||||
private val randomAccessFile = RandomAccessFile(file.path, "rw")
|
||||
|
||||
init {
|
||||
randomAccessFile.writeInt(declarationCount)
|
||||
assert(randomAccessFile.filePointer.toInt() == INDEX_HEADER_SIZE)
|
||||
for (i in 0 until declarationCount) {
|
||||
randomAccessFile.writeLong(-1) // id
|
||||
randomAccessFile.writeInt(-1) // isLocal
|
||||
randomAccessFile.writeInt(-1) // offset
|
||||
randomAccessFile.writeInt(-1) // size
|
||||
}
|
||||
currentPosition = randomAccessFile.filePointer.toInt()
|
||||
assert(currentPosition == INDEX_HEADER_SIZE + SINGLE_INDEX_RECORD_SIZE * declarationCount)
|
||||
}
|
||||
|
||||
fun skipDeclaration() {
|
||||
currentDeclaration++
|
||||
}
|
||||
|
||||
fun addDeclaration(id: DeclarationId, bytes: ByteArray) {
|
||||
randomAccessFile.seek((currentDeclaration * SINGLE_INDEX_RECORD_SIZE + INDEX_HEADER_SIZE).toLong())
|
||||
randomAccessFile.writeLong(id.id)
|
||||
randomAccessFile.writeInt(if (id.isLocal) 1 else 0)
|
||||
randomAccessFile.writeInt(currentPosition)
|
||||
randomAccessFile.writeInt(bytes.size)
|
||||
randomAccessFile.seek(currentPosition.toLong())
|
||||
randomAccessFile.write(bytes)
|
||||
assert(randomAccessFile.filePointer < Int.MAX_VALUE.toLong())
|
||||
currentPosition = randomAccessFile.filePointer.toInt()
|
||||
currentDeclaration++
|
||||
}
|
||||
|
||||
fun finishWriting(): File {
|
||||
assert(currentDeclaration == declarationCount)
|
||||
randomAccessFile.close()
|
||||
return file
|
||||
}
|
||||
}
|
||||
|
||||
-14
@@ -1,14 +0,0 @@
|
||||
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, partName: String): ByteArray =
|
||||
libraryLayout.packageFragmentFile(fqName, partName).readBytes()
|
||||
|
||||
}
|
||||
+65
-67
@@ -24,82 +24,80 @@ 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
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.impl.*
|
||||
|
||||
class KonanLibraryImpl(
|
||||
override val libraryFile: File,
|
||||
internal val target: KonanTarget?,
|
||||
override val isDefault: Boolean,
|
||||
private val metadataReader: MetadataReader
|
||||
) : KonanLibrary {
|
||||
open class TargetedLibraryImpl(
|
||||
private val access: TargetedLibraryAccess<TargetedKotlinLibraryLayout>,
|
||||
private val base: BaseKotlinLibrary
|
||||
) : TargetedLibrary, BaseKotlinLibrary by base {
|
||||
|
||||
// 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 target: KonanTarget? get() = access.target
|
||||
|
||||
private val layout = createKonanLibraryLayout(libraryFile, target)
|
||||
|
||||
override val libraryName: String by lazy { layout.inPlace { it.libraryName } }
|
||||
override val targetList by lazy {
|
||||
access.inPlace { it: TargetedKotlinLibraryLayout ->
|
||||
it.targetsDir.listFiles.map {
|
||||
it.name
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override val manifestProperties: Properties by lazy {
|
||||
val properties = layout.inPlace { it.manifestFile.loadProperties() }
|
||||
if (target != null) substitute(properties, defaultTargetSubstitutions(target))
|
||||
val properties = access.inPlace {
|
||||
it.manifestFile.loadProperties()
|
||||
}
|
||||
target?.let { substitute(properties, defaultTargetSubstitutions(it)) }
|
||||
properties
|
||||
}
|
||||
|
||||
override val versions: KonanLibraryVersioning
|
||||
get() = manifestProperties.readKonanLibraryVersioning()
|
||||
override val includedPaths: List<String>
|
||||
get() = access.realFiles {
|
||||
it.includedDir.listFilesOrEmpty.map { it.absolutePath }
|
||||
}
|
||||
}
|
||||
|
||||
open class BitcodeLibraryImpl(
|
||||
private val access: BitcodeLibraryAccess<BitcodeKotlinLibraryLayout>,
|
||||
targeted: TargetedLibrary
|
||||
) : BitcodeLibrary, TargetedLibrary by targeted {
|
||||
override val bitcodePaths: List<String>
|
||||
get() = access.realFiles { it: BitcodeKotlinLibraryLayout ->
|
||||
(it.kotlinDir.listFilesOrEmpty + it.nativeDir.listFilesOrEmpty).map { it.absolutePath }
|
||||
}
|
||||
}
|
||||
|
||||
class KonanLibraryImpl(
|
||||
targeted: TargetedLibraryImpl,
|
||||
metadata: MetadataLibraryImpl,
|
||||
ir: IrLibraryImpl,
|
||||
bitcode: BitcodeLibraryImpl
|
||||
) : KonanLibrary,
|
||||
BaseKotlinLibrary by targeted,
|
||||
MetadataLibrary by metadata,
|
||||
IrLibrary by ir,
|
||||
BitcodeLibrary by bitcode {
|
||||
|
||||
override val linkerOpts: List<String>
|
||||
get() = manifestProperties.propertyList(KLIB_PROPERTY_LINKED_OPTS, escapeInQuotes = true)
|
||||
|
||||
override val bitcodePaths: List<String>
|
||||
get() = layout.realFiles { (it.kotlinDir.listFilesOrEmpty + it.nativeDir.listFilesOrEmpty).map { it.absolutePath } }
|
||||
|
||||
override val includedPaths: List<String>
|
||||
get() = layout.realFiles { it.includedDir.listFilesOrEmpty.map { it.absolutePath } }
|
||||
|
||||
override val targetList by lazy { layout.inPlace { it.targetsDir.listFiles.map { it.name } } }
|
||||
|
||||
override val dataFlowGraph by lazy { layout.inPlace { it.dataFlowGraphFile.let { if (it.exists) it.readBytes() else null } } }
|
||||
|
||||
override val moduleHeaderData: ByteArray by lazy { layout.inPlace { metadataReader.loadSerializedModule(it) } }
|
||||
|
||||
override fun packageMetadata(packageFqName: String, partName: String) =
|
||||
layout.inPlace { metadataReader.loadSerializedPackageFragment(it, packageFqName, partName) }
|
||||
|
||||
override fun packageMetadataParts(fqName: String): Set<String> =
|
||||
layout.inPlace { inPlaceLayout ->
|
||||
val fileList =
|
||||
inPlaceLayout.packageFragmentsDir(fqName)
|
||||
.listFiles
|
||||
.mapNotNull {
|
||||
it.name
|
||||
.substringBeforeLast(KLIB_METADATA_FILE_EXTENSION_WITH_DOT, missingDelimiterValue = "")
|
||||
.takeIf { it.isNotEmpty() }
|
||||
}
|
||||
|
||||
fileList.toSortedSet().also {
|
||||
require(it.size == fileList.size) { "Duplicated names: ${fileList.groupingBy { it }.eachCount().filter { (_, count) -> count > 1 }}" }
|
||||
}
|
||||
}
|
||||
|
||||
override val irHeader: ByteArray? by lazy { layout.inPlace { library -> library.irHeader.let {
|
||||
if (it.exists) loadIrHeader() else null }
|
||||
}}
|
||||
|
||||
override fun irDeclaration(index: Long, isLocal: Boolean) = loadIrDeclaraton(index, isLocal)
|
||||
|
||||
override fun toString() = "$libraryName[default=$isDefault]"
|
||||
|
||||
private val combinedDeclarations: CombinedIrFileReader by lazy {
|
||||
CombinedIrFileReader(layout.realFiles {
|
||||
it.irFile
|
||||
})
|
||||
}
|
||||
private fun loadIrHeader(): ByteArray =
|
||||
layout.inPlace { it.irHeader.readBytes() }
|
||||
|
||||
private fun loadIrDeclaraton(index: Long, isLocal: Boolean) =
|
||||
combinedDeclarations.declarationBytes(DeclarationId(index, isLocal))
|
||||
}
|
||||
|
||||
|
||||
fun createKonanLibrary(
|
||||
libraryFile: File,
|
||||
target: KonanTarget? = null,
|
||||
isDefault: Boolean = false
|
||||
): KonanLibrary {
|
||||
val baseAccess = BaseLibraryAccess<KotlinLibraryLayout>(libraryFile)
|
||||
val targetedAccess = TargetedLibraryAccess<TargetedKotlinLibraryLayout>(libraryFile, target)
|
||||
val metadataAccess = MetadataLibraryAccess<MetadataKotlinLibraryLayout>(libraryFile)
|
||||
val irAccess = IrLibraryAccess<IrKotlinLibraryLayout>(libraryFile)
|
||||
val bitcodeAccess = BitcodeLibraryAccess<BitcodeKotlinLibraryLayout>(libraryFile, target)
|
||||
|
||||
val base = BaseKotlinLibraryImpl(baseAccess, isDefault)
|
||||
val targeted = TargetedLibraryImpl(targetedAccess, base)
|
||||
val metadata = MetadataLibraryImpl(metadataAccess)
|
||||
val ir = IrLibraryImpl(irAccess)
|
||||
val bitcode = BitcodeLibraryImpl(bitcodeAccess, targeted)
|
||||
|
||||
return KonanLibraryImpl(targeted, metadata, ir, bitcode)
|
||||
}
|
||||
+47
-79
@@ -1,93 +1,61 @@
|
||||
package org.jetbrains.kotlin.konan.library.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.*
|
||||
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.file.File
|
||||
import org.jetbrains.kotlin.konan.library.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.impl.*
|
||||
import java.nio.file.FileSystem
|
||||
|
||||
interface KonanLibraryLayoutImpl: KonanLibraryLayout {
|
||||
fun <T> inPlace(action: (KonanLibraryLayout) -> T): T
|
||||
fun <T> realFiles (action: (KonanLibraryLayout) -> T): T
|
||||
}
|
||||
open class TargetedLibraryLayoutImpl(klib: File, override val target: KonanTarget?) :
|
||||
KotlinLibraryLayoutImpl(klib), TargetedKotlinLibraryLayout {
|
||||
|
||||
private class ZippedKonanLibraryLayout(val klibFile: File, override val target: KonanTarget?): KonanLibraryLayoutImpl {
|
||||
|
||||
init { zippedKonanLibraryChecks(klibFile) }
|
||||
|
||||
override val libraryName = klibFile.path.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT)
|
||||
|
||||
override val libDir = File("/")
|
||||
|
||||
override fun <T> realFiles(action: (KonanLibraryLayout) -> T): T {
|
||||
return action(FileExtractor(this))!!
|
||||
override val extractingToTemp: TargetedKotlinLibraryLayout by lazy {
|
||||
ExtractingTargetedLibraryImpl(this)
|
||||
}
|
||||
|
||||
override fun <T> inPlace(action: (KonanLibraryLayout) -> T): T {
|
||||
return klibFile.withZipFileSystem { zipFileSystem ->
|
||||
action(DirectFromZip(this, zipFileSystem))
|
||||
}
|
||||
}
|
||||
override fun directlyFromZip(zipFileSystem: FileSystem): TargetedKotlinLibraryLayout =
|
||||
FromZipTargetedLibraryImpl(this, zipFileSystem)
|
||||
|
||||
}
|
||||
|
||||
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) {
|
||||
"KLIB path has unexpected extension: $klibFile"
|
||||
}
|
||||
}
|
||||
|
||||
private class UnzippedKonanLibraryLayout(override val libDir: File, override val target: KonanTarget?): KonanLibraryLayoutImpl {
|
||||
override val libraryName = libDir.path
|
||||
|
||||
override fun <T> inPlace(action: (KonanLibraryLayout) -> T): T = action(this)
|
||||
override fun <T> realFiles (action: (KonanLibraryLayout) -> T): T = inPlace(action)
|
||||
}
|
||||
|
||||
private class DirectFromZip(zippedLayout: ZippedKonanLibraryLayout, val zipFileSystem: FileSystem): KonanLibraryLayout {
|
||||
override val libraryName = zippedLayout.libraryName
|
||||
override val libDir = zipFileSystem.file(zippedLayout.libDir)
|
||||
}
|
||||
|
||||
/**
|
||||
* 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 [DirectFromZip].
|
||||
*/
|
||||
private class FileExtractor(val zippedLibraryLayout: ZippedKonanLibraryLayout): 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) }
|
||||
|
||||
override val irFile: File by lazy { extract(super.irFile) }
|
||||
|
||||
fun extract(file: File): File = zippedLibraryLayout.klibFile.withZipFileSystem { zipFileSystem ->
|
||||
val temporary = createTempFile(file.name)
|
||||
zipFileSystem.file(file).copyTo(temporary)
|
||||
temporary.deleteOnExit()
|
||||
temporary
|
||||
class BitcodeLibraryLayoutImpl(klib: File, target: KonanTarget?) : TargetedLibraryLayoutImpl(klib, target),
|
||||
BitcodeKotlinLibraryLayout {
|
||||
override val extractingToTemp: BitcodeKotlinLibraryLayout by lazy {
|
||||
ExtractingBitcodeLibraryImpl(this)
|
||||
}
|
||||
|
||||
fun extractDir(directory: File): File = zippedLibraryLayout.klibFile.withZipFileSystem { zipFileSystem ->
|
||||
val temporary = createTempDir(directory.name)
|
||||
zipFileSystem.file(directory).recursiveCopyTo(temporary)
|
||||
temporary.deleteOnExitRecursively()
|
||||
temporary
|
||||
}
|
||||
override fun directlyFromZip(zipFileSystem: FileSystem): BitcodeKotlinLibraryLayout =
|
||||
FromZipBitcodeLibraryImpl(this, zipFileSystem)
|
||||
|
||||
}
|
||||
|
||||
internal fun createKonanLibraryLayout(klib: File, target: KonanTarget? = null) =
|
||||
if (klib.isFile) ZippedKonanLibraryLayout(klib, target) else UnzippedKonanLibraryLayout(klib, target)
|
||||
open class TargetedLibraryAccess<L : KotlinLibraryLayout>(klib: File, val target: KonanTarget?) :
|
||||
BaseLibraryAccess<L>(klib) {
|
||||
override val layout = TargetedLibraryLayoutImpl(klib, target)
|
||||
}
|
||||
|
||||
open class BitcodeLibraryAccess<L : KotlinLibraryLayout>(klib: File, target: KonanTarget?) :
|
||||
TargetedLibraryAccess<L>(klib, target) {
|
||||
override val layout = BitcodeLibraryLayoutImpl(klib, target)
|
||||
}
|
||||
|
||||
private open class FromZipTargetedLibraryImpl(zipped: TargetedLibraryLayoutImpl, zipFileSystem: FileSystem) :
|
||||
FromZipBaseLibraryImpl(zipped, zipFileSystem), TargetedKotlinLibraryLayout
|
||||
|
||||
private class FromZipBitcodeLibraryImpl(zipped: BitcodeLibraryLayoutImpl, zipFileSystem: FileSystem) :
|
||||
FromZipTargetedLibraryImpl(zipped, zipFileSystem), BitcodeKotlinLibraryLayout
|
||||
|
||||
open class ExtractingTargetedLibraryImpl(zipped: TargetedLibraryLayoutImpl) :
|
||||
KotlinLibraryExtractor(zipped),
|
||||
TargetedKotlinLibraryLayout by zipped {
|
||||
|
||||
override val includedDir: File by lazy { extractDir(zipped.includedDir) }
|
||||
}
|
||||
|
||||
class ExtractingBitcodeLibraryImpl(zipped: BitcodeLibraryLayoutImpl) :
|
||||
ExtractingTargetedLibraryImpl(zipped), BitcodeKotlinLibraryLayout {
|
||||
|
||||
override val kotlinDir: File by lazy { extractDir(zipped.kotlinDir) }
|
||||
override val nativeDir: File by lazy { extractDir(zipped.nativeDir) }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user