Introduce 2 KLIB resolve strategies: "compiler" & "tooling"

Issue #KT-36213
This commit is contained in:
Dmitriy Dolovov
2020-01-30 12:51:39 +07:00
parent 1053428ee4
commit 1196044df7
3 changed files with 92 additions and 10 deletions
@@ -238,14 +238,18 @@ class SingleKlibComponentResolver(
override fun libraryComponentBuilder(file: File, isDefault: Boolean) = createKotlinLibraryComponents(file, isDefault) override fun libraryComponentBuilder(file: File, isDefault: Boolean) = createKotlinLibraryComponents(file, isDefault)
} }
fun resolveSingleFileKlib( /**
libraryFile: File, * Resolves KLIB libraries by:
logger: Logger = object : Logger { * - expanding the given library path to the real path that may or may not contain ".klib" extension
override fun log(message: String) {} * - searching among user-supplied libraries by "unique_name" that matches the given library name
override fun error(message: String) = kotlin.error("e: $message") * - filtering out pre-1.4 libraries (with the old style layout)
override fun warning(message: String) {} * - filtering out library components that have different ABI version than the ABI version of the current compiler
override fun fatal(message: String) = kotlin.error("e: $message") *
} * If no match found, fails with [Logger#fatal].
): KotlinLibrary { *
return SingleKlibComponentResolver(libraryFile.absolutePath, listOf(KotlinAbiVersion.CURRENT), logger).resolve(libraryFile.absolutePath) * Typical usage scenario: compiler.
*/
object CompilerSingleFileKlibResolveStrategy : SingleFileKlibResolveStrategy {
override fun resolve(libraryFile: File, logger: Logger) =
SingleKlibComponentResolver(libraryFile.absolutePath, listOf(KotlinAbiVersion.CURRENT), logger).resolve(libraryFile.absolutePath)
} }
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2020 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.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.util.Logger
interface SingleFileKlibResolveStrategy {
fun resolve(libraryFile: File, logger: Logger): KotlinLibrary
}
fun resolveSingleFileKlib(
libraryFile: File,
logger: Logger = object : Logger {
override fun log(message: String) {}
override fun error(message: String) = kotlin.error("e: $message")
override fun warning(message: String) {}
override fun fatal(message: String) = kotlin.error("e: $message")
},
strategy: SingleFileKlibResolveStrategy = CompilerSingleFileKlibResolveStrategy
): KotlinLibrary = strategy.resolve(libraryFile, logger)
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2020 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.library
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
import org.jetbrains.kotlin.util.Logger
/**
* Resolves KLIB library by making sure that the library has 1.4+ layout with exactly one component.
* If it is not, then [resolve] does not fail and returns a fake [KotlinLibrary] instance with nonexistent component that can be
* treated by the callee but can't be read.
*
* The given library path is assumed to be absolute and pointing to the real KLIB.
* It's the responsibility of the callee to check this condition in the appropriate way.
*
* [ToolingSingleFileKlibResolveStrategy] does not perform any ABI or metadata version compatibility checks.
* It's the responsibility of the callee to check library versions in the appropriate way.
*
* Typical usage scenario: IDE.
*/
object ToolingSingleFileKlibResolveStrategy : SingleFileKlibResolveStrategy {
override fun resolve(libraryFile: File, logger: Logger): KotlinLibrary {
if (checkComponent(libraryFile)) {
// old style library
return fakeLibrary(libraryFile)
}
val componentFiles = libraryFile.listFiles.filter(::checkComponent)
componentFiles.singleOrNull()?.let { componentFile ->
// single component library
return createKotlinLibrary(libraryFile, componentFile.name)
}
// otherwise mimic as old style library and warn
if (componentFiles.isNotEmpty()) {
// TODO: choose the best fit among all available candidates
logger.warning("Library $libraryFile can not be read. Multiple components found: ${componentFiles.map {
it.path.substringAfter(libraryFile.path)
}}")
}
return fakeLibrary(libraryFile)
}
private const val NONEXISTENT_COMPONENT_NAME = "__nonexistent_component_name__"
private fun checkComponent(componentFile: File) = componentFile.child(KLIB_MANIFEST_FILE_NAME).isFile
private fun fakeLibrary(libraryFile: File) = createKotlinLibrary(libraryFile, NONEXISTENT_COMPONENT_NAME)
}