Use "tooling" KLIB resolve strategy in IDE and commonizer
Issue #KT-36213
This commit is contained in:
+25
-14
@@ -25,9 +25,8 @@ import org.jetbrains.kotlin.idea.caches.project.LibraryInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.SdkInfo
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
|
||||
import org.jetbrains.kotlin.idea.framework.CommonLibraryKind
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.idea.util.IJLoggerAdapter
|
||||
import org.jetbrains.kotlin.library.*
|
||||
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
|
||||
import org.jetbrains.kotlin.platform.CommonPlatforms
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
|
||||
@@ -35,6 +34,7 @@ import org.jetbrains.kotlin.resolve.TargetEnvironment
|
||||
import org.jetbrains.kotlin.serialization.deserialization.MetadataPackageFragment
|
||||
import java.io.IOException
|
||||
import java.util.*
|
||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||
|
||||
class CommonPlatformKindResolution : IdePlatformKindResolution {
|
||||
override fun isLibraryFileForPlatform(virtualFile: VirtualFile): Boolean {
|
||||
@@ -95,7 +95,11 @@ class CommonKlibLibraryInfo(project: Project, library: Library, val libraryRoot:
|
||||
}
|
||||
}
|
||||
|
||||
val commonLibrary = createKotlinLibrary(File(libraryRoot))
|
||||
val commonLibrary = resolveSingleFileKlib(
|
||||
libraryFile = KFile(libraryRoot),
|
||||
logger = LOG,
|
||||
strategy = ToolingSingleFileKlibResolveStrategy
|
||||
)
|
||||
|
||||
val metadataInfo by lazy {
|
||||
val metadataVersion = commonLibrary.safeMetadataVersion
|
||||
@@ -114,6 +118,8 @@ class CommonKlibLibraryInfo(project: Project, library: Library, val libraryRoot:
|
||||
override fun toString() = "Common" + super.toString()
|
||||
|
||||
companion object {
|
||||
private val LOG = IJLoggerAdapter.getInstance(CommonKlibLibraryInfo::class.java)
|
||||
|
||||
internal val KotlinLibrary.safeMetadataVersion get() = this.readSafe(null) { metadataVersion }
|
||||
|
||||
private fun <T> KotlinLibrary.readSafe(defaultValue: T, action: KotlinLibrary.() -> T) = try {
|
||||
@@ -124,23 +130,28 @@ class CommonKlibLibraryInfo(project: Project, library: Library, val libraryRoot:
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
val VirtualFile.isMetadataKlib: Boolean
|
||||
get() {
|
||||
val extension = extension
|
||||
if (!extension.isNullOrEmpty() && extension != KLIB_FILE_EXTENSION) return false
|
||||
|
||||
val manifestFile = findChild(KLIB_MANIFEST_FILE_NAME)?.takeIf { !it.isDirectory } ?: return false
|
||||
fun checkComponent(componentFile: VirtualFile): Boolean {
|
||||
val manifestFile = componentFile.findChild(KLIB_MANIFEST_FILE_NAME)?.takeIf { !it.isDirectory } ?: return false
|
||||
|
||||
// native libraries
|
||||
val irFile = findChild(KLIB_IR_FOLDER_NAME)
|
||||
if (irFile != null && irFile.children.isNotEmpty()) return false
|
||||
// native libraries
|
||||
val irFile = componentFile.findChild(KLIB_IR_FOLDER_NAME)
|
||||
if (irFile != null && irFile.children.isNotEmpty()) return false
|
||||
|
||||
val manifestProperties = try {
|
||||
manifestFile.inputStream.use { Properties().apply { load(it) } }
|
||||
} catch (_: IOException) {
|
||||
return false
|
||||
val manifestProperties = try {
|
||||
manifestFile.inputStream.use { Properties().apply { load(it) } }
|
||||
} catch (_: IOException) {
|
||||
return false
|
||||
}
|
||||
|
||||
return manifestProperties.containsKey(KLIB_PROPERTY_UNIQUE_NAME)
|
||||
}
|
||||
|
||||
return manifestProperties.containsKey(KLIB_PROPERTY_UNIQUE_NAME)
|
||||
}
|
||||
// run check for library root too
|
||||
// this is necessary to recognize old style KLIBs that do not have components, and report them to user appropriately
|
||||
return checkComponent(this) || children?.any(::checkComponent) == true
|
||||
}
|
||||
|
||||
@@ -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.idea.util
|
||||
|
||||
import org.jetbrains.kotlin.util.Logger as KLogger
|
||||
import com.intellij.openapi.diagnostic.Logger as IJLogger
|
||||
|
||||
class IJLoggerAdapter private constructor(private val logger: IJLogger) : KLogger {
|
||||
override fun log(message: String) = logger.info(message)
|
||||
override fun warning(message: String) = logger.warn(message)
|
||||
|
||||
override fun error(message: String) = fatal(message)
|
||||
override fun fatal(message: String): Nothing {
|
||||
logger.error(message)
|
||||
error(message) // normally, this line of code should not be reached
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getInstance(clazz: Class<*>): KLogger = IJLoggerAdapter(IJLogger.getInstance(clazz))
|
||||
}
|
||||
}
|
||||
@@ -86,18 +86,24 @@ internal val VirtualFile.isKonanLibraryRoot: Boolean
|
||||
val extension = extension
|
||||
if (!extension.isNullOrEmpty() && extension != KLIB_FILE_EXTENSION) return false
|
||||
|
||||
val manifestFile = findChild(KLIB_MANIFEST_FILE_NAME)?.takeIf { !it.isDirectory } ?: return false
|
||||
fun checkComponent(componentFile: VirtualFile): Boolean {
|
||||
val manifestFile = componentFile.findChild(KLIB_MANIFEST_FILE_NAME)?.takeIf { !it.isDirectory } ?: return false
|
||||
|
||||
// this is a hacky way to determine whether this is a Kotlin/Native .klib or common .klib (common .klibs don't have ir)
|
||||
// TODO(dsavvinov): introduce more robust way to detect library platform
|
||||
val irFolder = findChild(KLIB_IR_FOLDER_NAME)
|
||||
if (irFolder == null || irFolder.children.isEmpty()) return false
|
||||
// this is a hacky way to determine whether this is a Kotlin/Native .klib or common .klib (common .klibs don't have ir)
|
||||
// TODO(dsavvinov): introduce more robust way to detect library platform
|
||||
val irFolder = componentFile.findChild(KLIB_IR_FOLDER_NAME)
|
||||
if (irFolder == null || irFolder.children.isEmpty()) return false
|
||||
|
||||
val manifestProperties = try {
|
||||
manifestFile.inputStream.use { Properties().apply { load(it) } }
|
||||
} catch (_: IOException) {
|
||||
return false
|
||||
val manifestProperties = try {
|
||||
manifestFile.inputStream.use { Properties().apply { load(it) } }
|
||||
} catch (_: IOException) {
|
||||
return false
|
||||
}
|
||||
|
||||
return manifestProperties.containsKey(KLIB_PROPERTY_UNIQUE_NAME)
|
||||
}
|
||||
|
||||
return manifestProperties.containsKey(KLIB_PROPERTY_UNIQUE_NAME)
|
||||
// run check for library root too
|
||||
// this is necessary to recognize old style KLIBs that do not have components, and report tem to user appropriately
|
||||
return checkComponent(this) || children?.any(::checkComponent) == true
|
||||
}
|
||||
|
||||
+11
-3
@@ -38,11 +38,12 @@ import org.jetbrains.kotlin.idea.caches.project.SdkInfo
|
||||
import org.jetbrains.kotlin.idea.caches.project.lazyClosure
|
||||
import org.jetbrains.kotlin.idea.caches.resolve.BuiltInsCacheKey
|
||||
import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.idea.util.IJLoggerAdapter
|
||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||
import org.jetbrains.kotlin.konan.util.KlibMetadataFactories
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.impl.createKotlinLibrary
|
||||
import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy
|
||||
import org.jetbrains.kotlin.library.isInterop
|
||||
import org.jetbrains.kotlin.library.resolveSingleFileKlib
|
||||
import org.jetbrains.kotlin.platform.TargetPlatform
|
||||
@@ -192,9 +193,14 @@ class NativeLibraryInfo(project: Project, library: Library, val libraryRoot: Str
|
||||
}
|
||||
}
|
||||
|
||||
private val nativeLibrary = resolveSingleFileKlib(File(libraryRoot))
|
||||
private val nativeLibrary = resolveSingleFileKlib(
|
||||
libraryFile = KFile(libraryRoot),
|
||||
logger = LOG,
|
||||
strategy = ToolingSingleFileKlibResolveStrategy
|
||||
)
|
||||
|
||||
val isStdlib get() = libraryRoot.endsWith(KONAN_STDLIB_NAME)
|
||||
|
||||
val metadataInfo by lazy {
|
||||
val metadataVersion = nativeLibrary.safeMetadataVersion
|
||||
when {
|
||||
@@ -221,6 +227,8 @@ class NativeLibraryInfo(project: Project, library: Library, val libraryRoot: Str
|
||||
override fun toString() = "Native" + super.toString()
|
||||
|
||||
companion object {
|
||||
private val LOG = IJLoggerAdapter.getInstance(NativeLibraryInfo::class.java)
|
||||
|
||||
val NATIVE_LIBRARY_CAPABILITY = ModuleDescriptor.Capability<KotlinLibrary>("KotlinNativeLibrary")
|
||||
|
||||
internal val KotlinLibrary.safeMetadataVersion get() = this.readSafe(null) { metadataVersion }
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.descriptors.commonizer.cli
|
||||
|
||||
import org.jetbrains.kotlin.util.Logger
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
internal fun parseArgs(
|
||||
@@ -22,9 +23,13 @@ internal fun parseArgs(
|
||||
return commandLine
|
||||
}
|
||||
|
||||
internal fun printErrorAndExit(errorMessage: String): Nothing {
|
||||
println("Error: $errorMessage")
|
||||
println()
|
||||
internal object CliLoggerAdapter : Logger {
|
||||
override fun log(message: String) = println(message)
|
||||
override fun warning(message: String) = println("Warning: $message")
|
||||
|
||||
exitProcess(1)
|
||||
override fun error(message: String) = fatal(message)
|
||||
override fun fatal(message: String): Nothing {
|
||||
println("Error: $message\n")
|
||||
exitProcess(1)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -35,8 +35,7 @@ fun main(args: Array<String>) {
|
||||
copyStdlib = true,
|
||||
copyEndorsedLibs = true,
|
||||
withStats = withStats,
|
||||
handleError = ::printErrorAndExit,
|
||||
log = ::println
|
||||
logger = CliLoggerAdapter
|
||||
).run()
|
||||
}
|
||||
|
||||
|
||||
+23
-19
@@ -21,12 +21,14 @@ import org.jetbrains.kotlin.konan.library.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||
import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy
|
||||
import org.jetbrains.kotlin.library.impl.BaseWriterImpl
|
||||
import org.jetbrains.kotlin.library.impl.KoltinLibraryWriterImpl
|
||||
import org.jetbrains.kotlin.library.resolveSingleFileKlib
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.serialization.konan.impl.KlibResolvedModuleDescriptorsFactoryImpl
|
||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||
import org.jetbrains.kotlin.util.Logger
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
||||
|
||||
@@ -37,8 +39,7 @@ class NativeDistributionCommonizer(
|
||||
private val copyStdlib: Boolean,
|
||||
private val copyEndorsedLibs: Boolean,
|
||||
private val withStats: Boolean,
|
||||
private val handleError: (String) -> Nothing,
|
||||
private val log: (String) -> Unit
|
||||
private val logger: Logger
|
||||
) {
|
||||
fun run() {
|
||||
checkPreconditions()
|
||||
@@ -46,36 +47,35 @@ class NativeDistributionCommonizer(
|
||||
with(ResettableClockMark()) {
|
||||
// 1. load modules
|
||||
val modulesByTargets = loadModules()
|
||||
log("Loaded lazy (uninitialized) libraries in ${elapsedSinceLast()}")
|
||||
logger.log("Loaded lazy (uninitialized) libraries in ${elapsedSinceLast()}")
|
||||
|
||||
// 2. run commonization
|
||||
val result = commonize(modulesByTargets)
|
||||
log("Commonization performed in ${elapsedSinceLast()}")
|
||||
logger.log("Commonization performed in ${elapsedSinceLast()}")
|
||||
|
||||
// 3. write new libraries
|
||||
saveModules(modulesByTargets, result)
|
||||
log("Written libraries in ${elapsedSinceLast()}")
|
||||
logger.log("Written libraries in ${elapsedSinceLast()}")
|
||||
|
||||
log("TOTAL: ${elapsedSinceStart()}")
|
||||
logger.log("TOTAL: ${elapsedSinceStart()}")
|
||||
}
|
||||
|
||||
log("Done.")
|
||||
log("")
|
||||
logger.log("Done.\n")
|
||||
}
|
||||
|
||||
private fun checkPreconditions() {
|
||||
if (!repository.isDirectory)
|
||||
handleError("repository does not exist: $repository")
|
||||
logger.fatal("repository does not exist: $repository")
|
||||
|
||||
when (targets.size) {
|
||||
0 -> handleError("no targets specified")
|
||||
1 -> handleError("too few targets specified: $targets")
|
||||
0 -> logger.fatal("no targets specified")
|
||||
1 -> logger.fatal("too few targets specified: $targets")
|
||||
}
|
||||
|
||||
when {
|
||||
!destination.exists() -> destination.mkdirs()
|
||||
!destination.isDirectory -> handleError("output already exists: $destination")
|
||||
destination.walkTopDown().any { it != destination } -> handleError("output is not empty: $destination")
|
||||
!destination.isDirectory -> logger.fatal("output already exists: $destination")
|
||||
destination.walkTopDown().any { it != destination } -> logger.fatal("output is not empty: $destination")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ class NativeDistributionCommonizer(
|
||||
?.listFiles()
|
||||
?.takeIf { it.isNotEmpty() }
|
||||
?.map { loadLibrary(it) }
|
||||
?: handleError("no platform libraries found for target $target in $platformLibsPath")
|
||||
?: logger.fatal("no platform libraries found for target $target in $platformLibsPath")
|
||||
|
||||
InputTarget(target.name, target) to platformLibs
|
||||
}.toMap()
|
||||
@@ -142,16 +142,20 @@ class NativeDistributionCommonizer(
|
||||
|
||||
private fun loadLibrary(location: File): KotlinLibrary {
|
||||
if (!location.isDirectory)
|
||||
handleError("library not found: $location")
|
||||
logger.fatal("library not found: $location")
|
||||
|
||||
val library = resolveSingleFileKlib(KFile(location.path))
|
||||
val library = resolveSingleFileKlib(
|
||||
libraryFile = KFile(location.path),
|
||||
logger = logger,
|
||||
strategy = ToolingSingleFileKlibResolveStrategy
|
||||
)
|
||||
|
||||
if (library.versions.metadataVersion == null)
|
||||
handleError("library does not have metadata version specified in manifest: $location")
|
||||
logger.fatal("library does not have metadata version specified in manifest: $location")
|
||||
|
||||
val metadataVersion = library.metadataVersion
|
||||
if (metadataVersion?.isCompatible() != true)
|
||||
handleError(
|
||||
logger.fatal(
|
||||
"""
|
||||
library has incompatible metadata version ${metadataVersion ?: "\"unknown\""}: $location,
|
||||
please make sure that all libraries passed to commonizer compatible metadata version ${KlibMetadataVersion.INSTANCE}
|
||||
@@ -172,7 +176,7 @@ class NativeDistributionCommonizer(
|
||||
|
||||
val result = runCommonization(parameters)
|
||||
return when (result) {
|
||||
is NothingToCommonize -> handleError("too few targets specified: ${modulesByTargets.keys}")
|
||||
is NothingToCommonize -> logger.fatal("too few targets specified: ${modulesByTargets.keys}")
|
||||
is CommonizationPerformed -> result
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user