From e7b8f3ecdef674f462e02017cd06ffcbab93c2c2 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Fri, 27 Oct 2023 11:56:28 +0200 Subject: [PATCH] [Native] Deprecate KLIB repositories in Kotlin/Native compiler 1. Log warnings on usage of KLIB repositories. 2. Don't block using repositories for now. ^KT-61098 --- .../arguments/K2NativeCompilerArguments.kt | 10 +- .../org/jetbrains/kotlin/konan/file/File.kt | 2 + .../kotlin/library/SearchPathResolver.kt | 127 ++++++++++++++---- .../native/interop/gen/jvm/CommandLine.kt | 10 +- 4 files changed, 123 insertions(+), 26 deletions(-) diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt index a76f8734951..3aed3eb3684 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/K2NativeCompilerArguments.kt @@ -121,7 +121,15 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { ) var produce: String? = null - @Argument(value = "-repo", shortName = "-r", valueDescription = "", description = "Library search path") + // TODO: remove after 2.0, KT-61098 + @Argument( + value = "-repo", + shortName = "-r", + valueDescription = "", + description = "Library search path.\n" + + "Note: This option is deprecated and will be removed in one of the future releases.\n" + + "Please use library paths instead of library names in all compiler options such as '-library'" + ) var repositories: Array? = null @Argument(value = "-target", valueDescription = "", description = "Set hardware target") diff --git a/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt b/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt index c88ce3b9833..e67c28c7f14 100644 --- a/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt +++ b/compiler/util-io/src/org/jetbrains/kotlin/konan/file/File.kt @@ -38,6 +38,8 @@ data class File constructor(internal val javaPath: Path) { get() = javaPath.fileName.toString().removeSuffixIfPresent(separator) // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8153248 val extension: String get() = name.substringAfterLast('.', "") + val nameSegments: List + get() = javaPath.map { it.fileName.toString() } val parent: String get() = javaPath.parent.toString() val parentFile: File diff --git a/compiler/util-klib/src/org/jetbrains/kotlin/library/SearchPathResolver.kt b/compiler/util-klib/src/org/jetbrains/kotlin/library/SearchPathResolver.kt index 314da356f05..005b850d46e 100644 --- a/compiler/util-klib/src/org/jetbrains/kotlin/library/SearchPathResolver.kt +++ b/compiler/util-klib/src/org/jetbrains/kotlin/library/SearchPathResolver.kt @@ -1,12 +1,13 @@ package org.jetbrains.kotlin.library import org.jetbrains.kotlin.konan.file.File +import org.jetbrains.kotlin.library.SearchPathResolver.LookupResult +import org.jetbrains.kotlin.library.SearchPathResolver.SearchRoot import org.jetbrains.kotlin.library.impl.createKotlinLibraryComponents import org.jetbrains.kotlin.library.impl.isPre_1_4_Library import org.jetbrains.kotlin.util.Logger import org.jetbrains.kotlin.util.WithLogger import org.jetbrains.kotlin.util.removeSuffixIfPresent -import org.jetbrains.kotlin.util.suffixIfNot import java.nio.file.InvalidPathException import java.nio.file.Paths @@ -18,7 +19,78 @@ const val KOTLIN_JS_STDLIB_NAME: String = "kotlin" const val KOTLIN_WASM_STDLIB_NAME: String = "kotlin" interface SearchPathResolver : WithLogger { - val searchRoots: List + /** + * The search root for KLIBs. + * + * @property searchRootPath The search root path. + * @property allowLookupByRelativePath Whether the lookup by relative paths is allowed. + * true - yes, allow to look up by relative path and by library name. + * false - no, allow to look up strictly by library name. + * @property isDeprecated Whether this search root is going to be removed in the future + * (and a warning should be displayed when a library was resolved against this root). + */ + class SearchRoot(val searchRootPath: File, val allowLookupByRelativePath: Boolean = false, val isDeprecated: Boolean = false) { + fun lookUp(libraryPath: File): LookupResult { + if (libraryPath.isAbsolute) + return LookupResult.Found(lookUpByAbsolutePath(libraryPath) ?: return LookupResult.NotFound) + + if (!allowLookupByRelativePath && libraryPath.nameSegments.size > 1) + return LookupResult.NotFound + + val resolvedLibrary = lookUpByAbsolutePath(File(searchRootPath, libraryPath)) ?: return LookupResult.NotFound + return if (isDeprecated) + LookupResult.FoundWithWarning( + library = resolvedLibrary, + warningText = "Library '${libraryPath.path}' was found in a custom library repository '${searchRootPath.path}'. " + + "Note, that custom library repositories are deprecated and will be removed in one of the future Kotlin releases. " + + "Please, avoid using '-repo' ('-r') compiler option and specify full paths to libraries in compiler CLI arguments." + ) + else + LookupResult.Found(resolvedLibrary) + } + + companion object { + fun lookUpByAbsolutePath(absoluteLibraryPath: File): File? = + when { + absoluteLibraryPath.isFile -> { + // It's a really existing file. + when (absoluteLibraryPath.extension.toLowerCase()) { + KLIB_FILE_EXTENSION -> absoluteLibraryPath + "jar" -> { + // A special workaround for old JS stdlib, that was packed in a JAR file. + absoluteLibraryPath + } + else -> { + // A file with an unexpected extension. + null + } + } + } + absoluteLibraryPath.isDirectory -> { + // It's a really existing directory. + absoluteLibraryPath + } + else -> null + } + } + } + + sealed interface LookupResult { + object NotFound : LookupResult + data class Found(val library: File) : LookupResult + data class FoundWithWarning(val library: File, val warningText: String) : LookupResult + } + + /** + * The KLIB search roots: + * 1. user working dir + * 2. custom repositories (deprecated) + * 3. the current K/N distribution + * + * IMPORTANT: The order of search roots actually defines the order of the lookup. + */ + val searchRoots: List + fun resolutionSequence(givenPath: String): Sequence fun resolve(unresolved: LenientUnresolvedLibrary, isDefaultLink: Boolean = false): L? fun resolve(unresolved: RequiredUnresolvedLibrary, isDefaultLink: Boolean = false): L @@ -59,26 +131,28 @@ abstract class KotlinLibrarySearchPathResolver( abstract fun libraryComponentBuilder(file: File, isDefault: Boolean): List private val directLibraries: List by lazy { - directLibs.mapNotNull { found(File(it)) }.flatMap { libraryComponentBuilder(it, false) } + directLibs.mapNotNull { SearchRoot.lookUpByAbsolutePath(File(it)) }.flatMap { libraryComponentBuilder(it, false) } } - // This is the place where we specify the order of library search. - override val searchRoots: List by lazy { - (listOf(currentDirHead) + repoRoots + listOf(localHead, distHead, distPlatformHead)).filterNotNull() - } + override val searchRoots: List by lazy { + val searchRoots = mutableListOf() - private val files: Set by lazy { searchRoots.flatMap { it.listFilesOrEmpty }.map { it.absolutePath }.toSet() } + // Current working dir: + searchRoots += currentDirHead?.let { SearchRoot(searchRootPath = it, allowLookupByRelativePath = true) } - private fun found(candidate: File): File? { - fun check(file: File): Boolean = files.contains(file.absolutePath) || file.exists + // Custom repositories (deprecated, to be removed): + // TODO: remove after 2.0, KT-61098 + repositories.mapTo(searchRoots) { SearchRoot(searchRootPath = File(it), allowLookupByRelativePath = true, isDeprecated = true) } - 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 - } + // Something likely never unused (deprecated, to be removed): + // TODO: remove after 2.0, KT-61098 + searchRoots += localHead?.let { SearchRoot(searchRootPath = it, allowLookupByRelativePath = true, isDeprecated = true) } + + // Current Kotlin/Native distribution: + searchRoots += distHead?.let { SearchRoot(searchRootPath = it) } + searchRoots += distPlatformHead?.let { SearchRoot(searchRootPath = it) } + + searchRoots.filterNotNull() } /** @@ -112,19 +186,26 @@ abstract class KotlinLibrarySearchPathResolver( } override fun resolutionSequence(givenPath: String): Sequence { - val given = validFileOrNull(givenPath) - val sequence = when { + val given: File? = validFileOrNull(givenPath) + val sequence: Sequence = when { given == null -> { // The given path can't denote a real file, so just look for such // unique_name among libraries passed to the compiler directly. directLibsSequence(givenPath) } given.isAbsolute -> - sequenceOf(found(given)) + sequenceOf(SearchRoot.lookUpByAbsolutePath(given)) else -> { // Search among libraries in repositories by library filename. - val repoLibs = searchRoots.asSequence().map { - found(File(it, given)) + val repoLibs = searchRoots.asSequence().map { searchRoot -> + when (val lookupResult = searchRoot.lookUp(given)) { + is LookupResult.Found -> lookupResult.library + is LookupResult.FoundWithWarning -> { + logger.warning(lookupResult.warningText) + lookupResult.library + } + LookupResult.NotFound -> null + } } // The given path still may denote a unique name of a direct library. directLibsSequence(givenPath) + repoLibs @@ -172,7 +253,7 @@ abstract class KotlinLibrarySearchPathResolver( override fun resolve(unresolved: RequiredUnresolvedLibrary, isDefaultLink: Boolean): L { return resolveOrNull(unresolved, isDefaultLink) - ?: logger.fatal("Could not find \"${unresolved.path}\" in ${searchRoots.map { it.absolutePath }}") + ?: logger.fatal("Could not find \"${unresolved.path}\" in ${searchRoots.map { it.searchRootPath.absolutePath }}") } override fun libraryMatch(candidate: L, unresolved: UnresolvedLibrary): Boolean = true diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/CommandLine.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/CommandLine.kt index ff66a3f8778..9ffd028c1d7 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/CommandLine.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/CommandLine.kt @@ -49,8 +49,14 @@ open class CommonInteropArguments(val argParser: ArgParser) { .multiple() val libraryVersion by argParser.option(ArgType.String, shortName = "lv", description = "resulting interop library version") .default("unspecified") - val repo by argParser.option(ArgType.String, shortName = "r", description = "repository to resolve dependencies") - .multiple() + + // TODO: remove after 2.0, KT-61098 + val repo by argParser.option( + ArgType.String, + shortName = "r", + description = "repository to resolve dependencies", + deprecatedWarning = "This option is deprecated and will be removed in one of the future releases. Please use library paths instead of library names in all options such as '-library'" + ).multiple() val nodefaultlibs by argParser.option(ArgType.Boolean, NODEFAULTLIBS, description = "don't link the libraries from dist/klib automatically").default(false) val nodefaultlibsDeprecated by argParser.option(ArgType.Boolean, NODEFAULTLIBS_DEPRECATED,