JS search path resolver with attributes.
Warn on inclusion of klibs with the same name in manifest
This commit is contained in:
committed by
alexander-gorshenev
parent
bc4be53569
commit
55805ddeb8
+63
@@ -0,0 +1,63 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.ir.backend.js
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.KonanVersion
|
||||||
|
import org.jetbrains.kotlin.library.KotlinAbiVersion
|
||||||
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
|
import org.jetbrains.kotlin.library.KotlinLibraryProperResolverWithAttributes
|
||||||
|
import org.jetbrains.kotlin.library.UnresolvedLibrary
|
||||||
|
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
|
||||||
|
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||||
|
import org.jetbrains.kotlin.library.resolver.impl.libraryResolver
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
class JsLibraryResolver(
|
||||||
|
repositories: List<String>,
|
||||||
|
directLibs: List<String>,
|
||||||
|
knownAbiVersions: List<KotlinAbiVersion>?,
|
||||||
|
knownCompilerVersions: List<KonanVersion>?,
|
||||||
|
distributionKlib: String?,
|
||||||
|
localKotlinDir: String?,
|
||||||
|
skipCurrentDir: Boolean,
|
||||||
|
logger: Logger
|
||||||
|
) : KotlinLibraryProperResolverWithAttributes<KotlinLibrary>(
|
||||||
|
repositories,
|
||||||
|
directLibs,
|
||||||
|
knownAbiVersions,
|
||||||
|
knownCompilerVersions,
|
||||||
|
distributionKlib,
|
||||||
|
localKotlinDir,
|
||||||
|
skipCurrentDir,
|
||||||
|
logger,
|
||||||
|
::createKotlinLibrary
|
||||||
|
)
|
||||||
|
|
||||||
|
// TODO: This is a temporary set of library resolver policies for js compiler.
|
||||||
|
fun jsResolveLibraries(libraries: List<String>, logger: Logger): KotlinLibraryResolveResult {
|
||||||
|
val unresolvedLibraries = libraries.map { UnresolvedLibrary(it, null) }
|
||||||
|
val libraryAbsolutePaths = libraries.map { File(it).absolutePath }
|
||||||
|
// Configure the resolver to only work with absolute paths for now.
|
||||||
|
val libraryResolver = JsLibraryResolver(
|
||||||
|
repositories = emptyList(),
|
||||||
|
directLibs = libraryAbsolutePaths,
|
||||||
|
knownAbiVersions = listOf(KotlinAbiVersion.CURRENT),
|
||||||
|
knownCompilerVersions = emptyList<KonanVersion>(),
|
||||||
|
distributionKlib = null,
|
||||||
|
localKotlinDir = null,
|
||||||
|
skipCurrentDir = false,
|
||||||
|
logger = logger
|
||||||
|
).libraryResolver()
|
||||||
|
val resolvedLibraries =
|
||||||
|
libraryResolver.resolveWithDependencies(
|
||||||
|
unresolvedLibraries = unresolvedLibraries,
|
||||||
|
noStdLib = true,
|
||||||
|
noDefaultLibs = true,
|
||||||
|
noEndorsedLibs = true
|
||||||
|
)
|
||||||
|
return resolvedLibraries
|
||||||
|
}
|
||||||
@@ -80,29 +80,6 @@ private val CompilerConfiguration.metadataVersion
|
|||||||
|
|
||||||
class KotlinFileSerializedData(val metadata: ByteArray, val irData: SerializedIrFile)
|
class KotlinFileSerializedData(val metadata: ByteArray, val irData: SerializedIrFile)
|
||||||
|
|
||||||
// TODO: This is a temporary set of library resolver policies for js compiler.
|
|
||||||
fun jsResolveLibraries(libraries: List<String>, logger: Logger): KotlinLibraryResolveResult {
|
|
||||||
val unresolvedLibraries = libraries.map { UnresolvedLibrary(it ,null) }
|
|
||||||
val libraryAbsolutePaths = libraries.map{ File(it).absolutePath }
|
|
||||||
// Configure the resolver to only work with absolute paths for now.
|
|
||||||
val libraryResolver = KotlinLibrarySearchPathResolver<KotlinLibrary>(
|
|
||||||
repositories = emptyList(),
|
|
||||||
directLibs = libraryAbsolutePaths,
|
|
||||||
distributionKlib = null,
|
|
||||||
localKotlinDir = null,
|
|
||||||
skipCurrentDir = false,
|
|
||||||
logger = logger
|
|
||||||
).libraryResolver()
|
|
||||||
val resolvedLibraries =
|
|
||||||
libraryResolver.resolveWithDependencies(
|
|
||||||
unresolvedLibraries = unresolvedLibraries,
|
|
||||||
noStdLib = true,
|
|
||||||
noDefaultLibs = true,
|
|
||||||
noEndorsedLibs = true
|
|
||||||
)
|
|
||||||
return resolvedLibraries
|
|
||||||
}
|
|
||||||
|
|
||||||
fun generateKLib(
|
fun generateKLib(
|
||||||
project: Project,
|
project: Project,
|
||||||
files: List<KtFile>,
|
files: List<KtFile>,
|
||||||
|
|||||||
+15
@@ -39,6 +39,7 @@ class KotlinLibraryResolverImpl<L: KotlinLibrary>(
|
|||||||
noEndorsedLibs: Boolean
|
noEndorsedLibs: Boolean
|
||||||
) = findLibraries(unresolvedLibraries, noStdLib, noDefaultLibs, noEndorsedLibs)
|
) = findLibraries(unresolvedLibraries, noStdLib, noDefaultLibs, noEndorsedLibs)
|
||||||
.leaveDistinct()
|
.leaveDistinct()
|
||||||
|
.omitDuplicateNames()
|
||||||
.resolveDependencies()
|
.resolveDependencies()
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -74,10 +75,24 @@ class KotlinLibraryResolverImpl<L: KotlinLibrary>(
|
|||||||
groupedByAbsolutePath.map { it.value.first() }
|
groupedByAbsolutePath.map { it.value.first() }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Having two libraries with the same uniqName we only keep the first one.
|
||||||
|
* TODO: The old JS plugin passes libraries with the same uniqName twice,
|
||||||
|
* so make it a warning for now.
|
||||||
|
*/
|
||||||
|
private fun List<KotlinLibrary>.omitDuplicateNames() =
|
||||||
|
this.groupBy { it.uniqueName }.let { groupedByUniqName ->
|
||||||
|
warnOnLibraryDuplicateNames(groupedByUniqName.filter { it.value.size > 1 }.keys)
|
||||||
|
groupedByUniqName.map { it.value.first() }
|
||||||
|
}
|
||||||
|
|
||||||
private fun warnOnLibraryDuplicates(duplicatedPaths: Iterable<String>) {
|
private fun warnOnLibraryDuplicates(duplicatedPaths: Iterable<String>) {
|
||||||
duplicatedPaths.forEach { logger.warning("library included more than once: $it") }
|
duplicatedPaths.forEach { logger.warning("library included more than once: $it") }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun warnOnLibraryDuplicateNames(duplicatedPaths: Iterable<String>) {
|
||||||
|
duplicatedPaths.forEach { logger.warning("duplicate library name: $it") }
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Given the list of root libraries does the following:
|
* Given the list of root libraries does the following:
|
||||||
|
|||||||
@@ -7,35 +7,47 @@ import org.jetbrains.kotlin.util.*
|
|||||||
|
|
||||||
const val KOTLIN_STDLIB_NAME = "stdlib"
|
const val KOTLIN_STDLIB_NAME = "stdlib"
|
||||||
|
|
||||||
interface SearchPathResolver<out L: KotlinLibrary> : WithLogger {
|
interface SearchPathResolver<L: KotlinLibrary> : WithLogger {
|
||||||
val searchRoots: List<File>
|
val searchRoots: List<File>
|
||||||
fun resolutionSequence(givenPath: String): Sequence<File>
|
fun resolutionSequence(givenPath: String): Sequence<File>
|
||||||
fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean = false): L
|
fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean = false): L
|
||||||
fun resolve(givenPath: String): L
|
fun resolve(givenPath: String): L
|
||||||
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean, noEndorsedLibs: Boolean): List<L>
|
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean, noEndorsedLibs: Boolean): List<L>
|
||||||
|
fun libraryMatch(candidate: L, unresolved: UnresolvedLibrary): Boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
interface SearchPathResolverWithAttributes<out L: KotlinLibrary>: SearchPathResolver<L> {
|
interface SearchPathResolverWithAttributes<L: KotlinLibrary>: SearchPathResolver<L> {
|
||||||
val knownAbiVersions: List<KotlinAbiVersion>?
|
val knownAbiVersions: List<KotlinAbiVersion>?
|
||||||
val knownCompilerVersions: List<KonanVersion>?
|
val knownCompilerVersions: List<KonanVersion>?
|
||||||
}
|
}
|
||||||
|
|
||||||
fun resolverByName(
|
fun resolverByName(
|
||||||
repositories: List<String>,
|
repositories: List<String>,
|
||||||
directLibs: List<String> = emptyList(),
|
directLibs: List<String> = emptyList(),
|
||||||
distributionKlib: String? = null,
|
distributionKlib: String? = null,
|
||||||
localKotlinDir: String? = null,
|
localKotlinDir: String? = null,
|
||||||
skipCurrentDir: Boolean = false,
|
skipCurrentDir: Boolean = false,
|
||||||
logger: Logger = DummyLogger
|
logger: Logger
|
||||||
): SearchPathResolver<KotlinLibrary> = KotlinLibrarySearchPathResolver(repositories, directLibs, distributionKlib, localKotlinDir, skipCurrentDir, logger)
|
): SearchPathResolver<KotlinLibrary> =
|
||||||
|
KotlinLibrarySearchPathResolver(
|
||||||
|
repositories,
|
||||||
|
directLibs,
|
||||||
|
distributionKlib,
|
||||||
|
localKotlinDir,
|
||||||
|
skipCurrentDir,
|
||||||
|
logger,
|
||||||
|
::createKotlinLibrary
|
||||||
|
)
|
||||||
|
|
||||||
open class KotlinLibrarySearchPathResolver<out L: KotlinLibrary>(
|
// This is a simple library resolver that only cares for file names.
|
||||||
|
open class KotlinLibrarySearchPathResolver<L: KotlinLibrary>(
|
||||||
repositories: List<String>,
|
repositories: List<String>,
|
||||||
directLibs: List<String>,
|
directLibs: List<String>,
|
||||||
val distributionKlib: String?,
|
val distributionKlib: String?,
|
||||||
val localKotlinDir: String?,
|
val localKotlinDir: String?,
|
||||||
val skipCurrentDir: Boolean,
|
val skipCurrentDir: Boolean,
|
||||||
override val logger: Logger = DummyLogger
|
override val logger: Logger,
|
||||||
|
open val libraryBuilder: (File, Boolean) -> L
|
||||||
) : SearchPathResolver<L> {
|
) : SearchPathResolver<L> {
|
||||||
|
|
||||||
val localHead: File?
|
val localHead: File?
|
||||||
@@ -52,7 +64,7 @@ open class KotlinLibrarySearchPathResolver<out L: KotlinLibrary>(
|
|||||||
private val repoRoots: List<File> by lazy { repositories.map { File(it) } }
|
private val repoRoots: List<File> by lazy { repositories.map { File(it) } }
|
||||||
|
|
||||||
private val directLibraries: List<KotlinLibrary> by lazy {
|
private val directLibraries: List<KotlinLibrary> by lazy {
|
||||||
directLibs.mapNotNull { found(File(it)) }.map { createKotlinLibrary(it) }
|
directLibs.mapNotNull { found(File(it)) }.map { libraryBuilder(it, false) }
|
||||||
}
|
}
|
||||||
|
|
||||||
// This is the place where we specify the order of library search.
|
// This is the place where we specify the order of library search.
|
||||||
@@ -102,15 +114,19 @@ open class KotlinLibrarySearchPathResolver<out L: KotlinLibrary>(
|
|||||||
|
|
||||||
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): L {
|
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): L {
|
||||||
val givenPath = unresolved.path
|
val givenPath = unresolved.path
|
||||||
return resolutionSequence(givenPath).firstOrNull() ?. let {
|
val fileSequence = resolutionSequence(givenPath)
|
||||||
createKotlinLibrary(it, isDefaultLink) as L
|
val matching = fileSequence.map { libraryBuilder(it, isDefaultLink) }
|
||||||
} ?: run {
|
.map { it.takeIf { libraryMatch(it, unresolved) } }
|
||||||
|
.filterNotNull()
|
||||||
|
|
||||||
|
return matching.firstOrNull() ?: run {
|
||||||
logger.fatal("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
|
logger.fatal("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun resolve(givenPath: String) = resolve(UnresolvedLibrary(givenPath, null), false)
|
override fun libraryMatch(candidate: L, unresolved: UnresolvedLibrary) = true
|
||||||
|
|
||||||
|
override fun resolve(givenPath: String) = resolve(UnresolvedLibrary(givenPath, null), false)
|
||||||
|
|
||||||
private val File.klib
|
private val File.klib
|
||||||
get() = File(this, "klib")
|
get() = File(this, "klib")
|
||||||
@@ -158,3 +174,59 @@ fun KonanVersion.compatible(other: KonanVersion) =
|
|||||||
this.major == other.major
|
this.major == other.major
|
||||||
&& this.minor == other.minor
|
&& this.minor == other.minor
|
||||||
&& this.maintenance == other.maintenance
|
&& this.maintenance == other.maintenance
|
||||||
|
|
||||||
|
|
||||||
|
// This is a library resolver aware of attributes shared between platforms,
|
||||||
|
// such as abi version.
|
||||||
|
// JS and Native resolvers are inherited from this one.
|
||||||
|
open class KotlinLibraryProperResolverWithAttributes<L: KotlinLibrary>(
|
||||||
|
repositories: List<String>,
|
||||||
|
directLibs: List<String>,
|
||||||
|
override val knownAbiVersions: List<KotlinAbiVersion>?,
|
||||||
|
override val knownCompilerVersions: List<KonanVersion>?,
|
||||||
|
distributionKlib: String?,
|
||||||
|
localKotlinDir: String?,
|
||||||
|
skipCurrentDir: Boolean,
|
||||||
|
override val logger: Logger,
|
||||||
|
override val libraryBuilder: (File, Boolean) -> L
|
||||||
|
) : KotlinLibrarySearchPathResolver<L>(repositories, directLibs, distributionKlib, localKotlinDir, skipCurrentDir, logger, libraryBuilder),
|
||||||
|
SearchPathResolverWithAttributes<L>
|
||||||
|
{
|
||||||
|
override fun libraryMatch(candidate: L, unresolved: UnresolvedLibrary): Boolean {
|
||||||
|
val candidatePath = candidate.libraryFile.absolutePath
|
||||||
|
|
||||||
|
val candidateCompilerVersion = candidate.versions.compilerVersion
|
||||||
|
val candidateAbiVersion = candidate.versions.abiVersion
|
||||||
|
val candidateLibraryVersion = candidate.versions.libraryVersion
|
||||||
|
|
||||||
|
val abiVersionMatch = candidateAbiVersion != null &&
|
||||||
|
knownAbiVersions != null &&
|
||||||
|
knownAbiVersions!!.contains(candidateAbiVersion)
|
||||||
|
|
||||||
|
val compilerVersionMatch = candidateCompilerVersion != null &&
|
||||||
|
knownCompilerVersions != null &&
|
||||||
|
knownCompilerVersions!!.any { it.compatible(candidateCompilerVersion) }
|
||||||
|
|
||||||
|
if (!abiVersionMatch && !compilerVersionMatch) {
|
||||||
|
logger.warning("skipping $candidatePath. The abi versions don't match. Expected '${knownAbiVersions}', found '${candidateAbiVersion}'")
|
||||||
|
|
||||||
|
if (knownCompilerVersions != null) {
|
||||||
|
val expected = knownCompilerVersions?.map { it.toString(false, false) }
|
||||||
|
val found = candidateCompilerVersion?.toString(true, true)
|
||||||
|
logger.warning("The compiler versions don't match either. Expected '${expected}', found '${found}'")
|
||||||
|
}
|
||||||
|
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidateLibraryVersion != unresolved.libraryVersion &&
|
||||||
|
candidateLibraryVersion != null &&
|
||||||
|
unresolved.libraryVersion != null
|
||||||
|
) {
|
||||||
|
logger.warning("skipping $candidatePath. The library versions don't match. Expected '${unresolved.libraryVersion}', found '${candidateLibraryVersion}'")
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user