Commonizing klib metadata between native and js
This commit is contained in:
committed by
alexander-gorshenev
parent
f38123e78c
commit
c227c13799
@@ -11,6 +11,9 @@ const val KLIB_PROPERTY_LIBRARY_VERSION = "library_version"
|
||||
const val KLIB_PROPERTY_UNIQUE_NAME = "unique_name"
|
||||
const val KLIB_PROPERTY_DEPENDS = "depends"
|
||||
const val KLIB_PROPERTY_PACKAGE = "package"
|
||||
const val KLIB_PROPERTY_INTEROP = "interop"
|
||||
const val KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS = "exportForwardDeclarations"
|
||||
|
||||
/**
|
||||
* Abstractions for getting access to the information stored inside of Kotlin/Native library.
|
||||
*/
|
||||
@@ -51,3 +54,17 @@ val BaseKotlinLibrary.unresolvedDependencies: List<UnresolvedLibrary>
|
||||
}
|
||||
|
||||
interface KotlinLibrary : BaseKotlinLibrary, MetadataLibrary, IrLibrary
|
||||
|
||||
// TODO: should we move the below ones to Native?
|
||||
val KotlinLibrary.isInterop
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_INTEROP) == "true"
|
||||
|
||||
val KotlinLibrary.packageFqName: String?
|
||||
get() = manifestProperties.getProperty(org.jetbrains.kotlin.library.KLIB_PROPERTY_PACKAGE)
|
||||
|
||||
val KotlinLibrary.exportForwardDeclarations
|
||||
get() = manifestProperties.propertyList(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS, escapeInQuotes = true)
|
||||
.asSequence()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.toList()
|
||||
@@ -36,4 +36,4 @@ val List<String>.toUnresolvedLibraries
|
||||
.let { if (it.isEmpty()) null else it }
|
||||
val name = it.substringBeforeLast('@')
|
||||
UnresolvedLibrary(name, version)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,160 @@
|
||||
package org.jetbrains.kotlin.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
|
||||
import org.jetbrains.kotlin.util.*
|
||||
|
||||
const val KOTLIN_STDLIB_NAME = "stdlib"
|
||||
|
||||
interface SearchPathResolver<out L: KotlinLibrary> : WithLogger {
|
||||
val searchRoots: List<File>
|
||||
fun resolutionSequence(givenPath: String): Sequence<File>
|
||||
fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean = false): L
|
||||
fun resolve(givenPath: String): L
|
||||
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean, noEndorsedLibs: Boolean): List<L>
|
||||
}
|
||||
|
||||
interface SearchPathResolverWithAttributes<out L: KotlinLibrary>: SearchPathResolver<L> {
|
||||
val knownAbiVersions: List<KotlinAbiVersion>?
|
||||
val knownCompilerVersions: List<KonanVersion>?
|
||||
}
|
||||
|
||||
fun resolverByName(
|
||||
repositories: List<String>,
|
||||
directLibs: List<String> = emptyList(),
|
||||
distributionKlib: String? = null,
|
||||
localKotlinDir: String? = null,
|
||||
skipCurrentDir: Boolean = false,
|
||||
logger: Logger = DummyLogger
|
||||
): SearchPathResolver<KotlinLibrary> = KotlinLibrarySearchPathResolver(repositories, directLibs, distributionKlib, localKotlinDir, skipCurrentDir, logger)
|
||||
|
||||
open class KotlinLibrarySearchPathResolver<out L: KotlinLibrary>(
|
||||
repositories: List<String>,
|
||||
directLibs: List<String>,
|
||||
val distributionKlib: String?,
|
||||
val localKotlinDir: String?,
|
||||
val skipCurrentDir: Boolean,
|
||||
override val logger: Logger = DummyLogger
|
||||
) : SearchPathResolver<L> {
|
||||
|
||||
val localHead: File?
|
||||
get() = localKotlinDir?.File()?.klib
|
||||
|
||||
val distHead: File?
|
||||
get() = distributionKlib?.File()?.child("common")
|
||||
|
||||
open val distPlatformHead: File? = null
|
||||
|
||||
val currentDirHead: File?
|
||||
get() = if (!skipCurrentDir) File.userDir else null
|
||||
|
||||
private val repoRoots: List<File> by lazy { repositories.map { File(it) } }
|
||||
|
||||
private val directLibraries: List<KotlinLibrary> by lazy {
|
||||
directLibs.mapNotNull { found(File(it)) }.map { createKotlinLibrary(it) }
|
||||
}
|
||||
|
||||
// This is the place where we specify the order of library search.
|
||||
override val searchRoots: List<File> by lazy {
|
||||
(listOf(currentDirHead) + repoRoots + listOf(localHead, distHead, distPlatformHead)).filterNotNull()
|
||||
}
|
||||
|
||||
private fun found(candidate: File): File? {
|
||||
fun check(file: File): Boolean =
|
||||
file.exists && (file.isFile || File(file, "manifest").exists)
|
||||
|
||||
val noSuffix = File(candidate.path.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT))
|
||||
val withSuffix = File(candidate.path.suffixIfNot(KLIB_FILE_EXTENSION_WITH_DOT))
|
||||
return when {
|
||||
check(withSuffix) -> withSuffix
|
||||
check(noSuffix) -> noSuffix
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolutionSequence(givenPath: String): Sequence<File> {
|
||||
val given = File(givenPath)
|
||||
val sequence = if (given.isAbsolute) {
|
||||
sequenceOf(found(given))
|
||||
} else {
|
||||
// Search among user-provided libraries by unique name.
|
||||
// It's a workaround for maven publication. When a library is published without Gradle metadata,
|
||||
// it has a complex file name (e.g. foo-macos_x64-1.0.klib). But a dependency on this lib in manifests
|
||||
// of other libs uses its unique name written in the manifest (i.e just 'foo'). So we cannot resolve this
|
||||
// library by its filename. But we have this library's file (we've downloaded it using maven dependency
|
||||
// resolution) so we can pass it to the compiler directly. This code takes this into account and looks for
|
||||
// a library dependencies also in libs passed to the compiler as files (passed to the resolver as the
|
||||
// 'directLibraries' property).
|
||||
val directLibs = directLibraries.asSequence().filter {
|
||||
it.uniqueName == givenPath
|
||||
}.map {
|
||||
it.libraryFile
|
||||
}
|
||||
// Search among libraries in repositoreis by library filename.
|
||||
val repoLibs = searchRoots.asSequence().map {
|
||||
found(File(it, givenPath))
|
||||
}
|
||||
directLibs + repoLibs
|
||||
}
|
||||
return sequence.filterNotNull()
|
||||
}
|
||||
|
||||
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): L {
|
||||
val givenPath = unresolved.path
|
||||
return resolutionSequence(givenPath).firstOrNull() ?. let {
|
||||
createKotlinLibrary(it, isDefaultLink) as L
|
||||
} ?: run {
|
||||
logger.fatal("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolve(givenPath: String) = resolve(UnresolvedLibrary(givenPath, null), false)
|
||||
|
||||
|
||||
private val File.klib
|
||||
get() = File(this, "klib")
|
||||
|
||||
// The libraries from the default root are linked automatically.
|
||||
val defaultRoots: List<File>
|
||||
get() = listOfNotNull(distHead, distPlatformHead).filter { it.exists }
|
||||
|
||||
private fun getDefaultLibrariesFromDir(directory: File) =
|
||||
if (directory.exists) {
|
||||
directory.listFiles
|
||||
.asSequence()
|
||||
.filterNot { it.name.startsWith('.') }
|
||||
.filterNot { it.name.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT) == KOTLIN_STDLIB_NAME }
|
||||
.map { UnresolvedLibrary(it.absolutePath, null) }
|
||||
.map { resolve(it, isDefaultLink = true) }
|
||||
} else emptySequence()
|
||||
|
||||
override fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean, noEndorsedLibs: Boolean): List<L> {
|
||||
|
||||
val result = mutableListOf<L>()
|
||||
|
||||
if (!noStdLib) {
|
||||
result.add(resolve(UnresolvedLibrary(KOTLIN_STDLIB_NAME, null), true))
|
||||
}
|
||||
|
||||
// Endorsed libraries in distHead.
|
||||
if (!noEndorsedLibs) {
|
||||
distHead?.let {
|
||||
result.addAll(getDefaultLibrariesFromDir(it))
|
||||
}
|
||||
}
|
||||
// Platform libraries resolve.
|
||||
if (!noDefaultLibs) {
|
||||
distPlatformHead?.let {
|
||||
result.addAll(getDefaultLibrariesFromDir(it))
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
fun KonanVersion.compatible(other: KonanVersion) =
|
||||
this.major == other.major
|
||||
&& this.minor == other.minor
|
||||
&& this.maintenance == other.maintenance
|
||||
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jetbrains.kotlin.konan.properties.loadProperties
|
||||
|
||||
open class BaseKotlinLibraryImpl(
|
||||
private val access: BaseLibraryAccess<KotlinLibraryLayout>,
|
||||
val access: BaseLibraryAccess<KotlinLibraryLayout>,
|
||||
override val isDefault: Boolean
|
||||
) : BaseKotlinLibrary {
|
||||
override val libraryFile get() = access.klib
|
||||
@@ -40,7 +40,7 @@ open class BaseKotlinLibraryImpl(
|
||||
}
|
||||
|
||||
open class MetadataLibraryImpl(
|
||||
private val access: MetadataLibraryAccess<MetadataKotlinLibraryLayout>
|
||||
val access: MetadataLibraryAccess<MetadataKotlinLibraryLayout>
|
||||
) : MetadataLibrary {
|
||||
|
||||
override val moduleHeaderData: ByteArray by lazy {
|
||||
@@ -72,7 +72,7 @@ open class MetadataLibraryImpl(
|
||||
}
|
||||
|
||||
abstract class IrLibraryImpl(
|
||||
protected val access: IrLibraryAccess<IrKotlinLibraryLayout>
|
||||
val access: IrLibraryAccess<IrKotlinLibraryLayout>
|
||||
) : IrLibrary {
|
||||
override val dataFlowGraph by lazy {
|
||||
access.inPlace { it: IrKotlinLibraryLayout ->
|
||||
@@ -211,9 +211,9 @@ class IrPerFileLibraryImpl(_access: IrLibraryAccess<IrKotlinLibraryLayout>) : Ir
|
||||
}
|
||||
|
||||
open class KotlinLibraryImpl(
|
||||
base: BaseKotlinLibraryImpl,
|
||||
metadata: MetadataLibraryImpl,
|
||||
ir: IrLibraryImpl
|
||||
val base: BaseKotlinLibraryImpl,
|
||||
val metadata: MetadataLibraryImpl,
|
||||
val ir: IrLibraryImpl
|
||||
) : KotlinLibrary,
|
||||
BaseKotlinLibrary by base,
|
||||
MetadataLibrary by metadata,
|
||||
|
||||
@@ -4,7 +4,7 @@ import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.file.file
|
||||
import org.jetbrains.kotlin.konan.file.withZipFileSystem
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
|
||||
import org.jetbrains.kotlin.util.removeSuffixIfPresent
|
||||
import java.nio.file.FileSystem
|
||||
|
||||
open class KotlinLibraryLayoutImpl(val klib: File) : KotlinLibraryLayout {
|
||||
|
||||
Reference in New Issue
Block a user