Minor improvements in recursive klib dependency support

* Support -r option in the cinterop tool.
 * Move klib resolve into separate methods.
 * Don't treat directory as a library if it doesn't contain a manifest.
 * Rework recursive library search + duplicate removal.
 * Support recursive klib processing in the cinterop tool.
This commit is contained in:
Ilya Matveev
2017-10-02 18:38:56 +03:00
committed by ilmat192
parent a94448ba5f
commit e245a23c34
4 changed files with 105 additions and 53 deletions
@@ -18,8 +18,7 @@ package org.jetbrains.kotlin.backend.konan
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.konan.descriptors.createForwardDeclarationsModule
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
import org.jetbrains.kotlin.backend.konan.library.KonanLibrarySearchPathResolver
import org.jetbrains.kotlin.backend.konan.library.*
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl
import org.jetbrains.kotlin.backend.konan.util.profile
import org.jetbrains.kotlin.backend.konan.util.removeSuffixIfPresent
@@ -33,8 +32,6 @@ import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.descriptors.impl.ModuleDescriptorImpl
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.target.TargetManager.*
import org.jetbrains.kotlin.konan.target.CompilerOutputKind.*
import org.jetbrains.kotlin.konan.util.DependencyProcessor
import org.jetbrains.kotlin.storage.LockBasedStorageManager
import org.jetbrains.kotlin.storage.StorageManager
@@ -79,40 +76,24 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
get() = configuration.getList(KonanConfigKeys.LIBRARY_FILES)
private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES)
private val resolver = KonanLibrarySearchPathResolver(repositories, distribution.klib, distribution.localKonanDir)
private val resolver = defaultResolver(repositories, distribution)
val immediateLibraries: List<LibraryReaderImpl> by lazy {
val target = targetManager.target
val defaultLibraries = resolver.defaultLinks(
resolver.resolveImmediateLibraries(
libraryNames,
targetManager.target,
currentAbiVersion,
configuration.getBoolean(KonanConfigKeys.NOSTDLIB),
configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS)
) .map { LibraryReaderImpl(it, currentAbiVersion, target, isDefaultLink=true) }
val userProvidedLibraries = libraryNames
.map { resolver.resolve(it) }
.map{ LibraryReaderImpl(it, currentAbiVersion, target) }
var resolvedLibraries = defaultLibraries + userProvidedLibraries
warnOnLibraryDuplicates(resolvedLibraries.map{ it.libraryFile })
resolvedLibraries.distinctBy { it.libraryFile.absolutePath }
configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS),
false
).let {
warnOnLibraryDuplicates(it.map { it.libraryFile })
it.distinctBy { it.libraryFile.absolutePath }
}
}
val libraries: List<LibraryReaderImpl> by lazy {
val result = mutableListOf<LibraryReaderImpl>()
result.addAll(immediateLibraries)
do {
val dependencies = result
.map { it.dependencies } .flatten()
.map { resolver.resolve(it) }
.map { LibraryReaderImpl(it, currentAbiVersion, targetManager.target) }
.distinctBy { it.libraryFile.absolutePath }
val newDependencies = dependencies.deleteMatching(result, { it.libraryFile.absolutePath })
result.addAll(newDependencies)
} while (newDependencies.size > 0)
result
resolver.resolveLibrariesRecursive(immediateLibraries, targetManager.target, currentAbiVersion)
}
private val loadedDescriptors = loadLibMetadata()
@@ -170,10 +151,5 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
}
}
private fun <T, K> List<T>.deleteMatching(other: List<T>, transform: (T) -> K): List<T> {
val transformed = other.map { transform(it) }
return this.filterNot { transformed.contains( transform(it) ) }
}
fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String)
= this.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(priority, message)
@@ -16,9 +16,13 @@
package org.jetbrains.kotlin.backend.konan.library
import org.jetbrains.kotlin.backend.konan.Distribution
import org.jetbrains.kotlin.backend.konan.library.impl.LibraryReaderImpl
import org.jetbrains.kotlin.backend.konan.util.removeSuffixIfPresent
import org.jetbrains.kotlin.backend.konan.util.suffixIfNot
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.TargetManager
interface SearchPathResolver {
val searchRoots: List<File>
@@ -26,6 +30,63 @@ interface SearchPathResolver {
fun defaultLinks(nostdlib: Boolean, noDefaultLibs: Boolean): List<File>
}
fun defaultResolver(repositories: List<String>, targetManager: TargetManager): SearchPathResolver =
defaultResolver(repositories, Distribution(targetManager))
fun defaultResolver(repositories: List<String>, distribution: Distribution): SearchPathResolver =
KonanLibrarySearchPathResolver(repositories, distribution.klib, distribution.localKonanDir)
fun SearchPathResolver.resolveImmediateLibraries(libraryNames: List<String>,
target: KonanTarget,
abiVersion: Int = 1,
noStdLib: Boolean = false,
noDefaultLibs: Boolean = false,
removeDuplicates: Boolean = true): List<LibraryReaderImpl> {
val defaultLibraries = defaultLinks(noStdLib, noDefaultLibs).map {
LibraryReaderImpl(it, abiVersion, target, isDefaultLink = true)
}
val userProvidedLibraries = libraryNames
.map { resolve(it) }
.map{ LibraryReaderImpl(it, abiVersion, target) }
val resolvedLibraries = defaultLibraries + userProvidedLibraries
return resolvedLibraries.let {
if (removeDuplicates) it.distinctBy { it.libraryFile.absolutePath } else it
}
}
fun SearchPathResolver.resolveLibrariesRecursive(immediateLibraries: List<LibraryReaderImpl>,
target: KonanTarget,
abiVersion: Int): List<LibraryReaderImpl> {
val result = mutableMapOf<File, LibraryReaderImpl>()
result.putAll(immediateLibraries.map { it.libraryFile.absoluteFile to it })
var newDependencies: Map<File, LibraryReaderImpl> = result
do {
newDependencies = newDependencies.values.asSequence()
.flatMap { it.dependencies.asSequence() }
.map { resolve(it).absoluteFile }
.filter { it !in result }
.map { it to LibraryReaderImpl(it, abiVersion, target) }.toMap()
result.putAll(newDependencies)
} while (newDependencies.isNotEmpty())
return result.values.toList()
}
fun SearchPathResolver.resolveLibrariesRecursive(libraryNames: List<String>,
target: KonanTarget,
abiVersion: Int = 1,
noStdLib: Boolean = false,
noDefaultLibs: Boolean = false): List<LibraryReaderImpl> {
return resolveLibrariesRecursive(
resolveImmediateLibraries(libraryNames, target, abiVersion, noStdLib, noDefaultLibs, true),
target, abiVersion
)
}
class KonanLibrarySearchPathResolver(repositories: List<String>,
val distributionKlib: String?, val localKonanDir: String?, val skipCurrentDir: Boolean = false): SearchPathResolver {
@@ -48,21 +109,22 @@ class KonanLibrarySearchPathResolver(repositories: List<String>,
}
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"))
val withSuffix = File(candidate.path.suffixIfNot(".klib"))
if (withSuffix.exists) {
return withSuffix
return when {
check(withSuffix) -> withSuffix
check(noSuffix) -> noSuffix
else -> null
}
if (noSuffix.exists) {
return noSuffix
}
return null
}
override fun resolve(givenPath: String): File {
val given = File(givenPath)
if (given.isAbsolute) {
found(given)?.apply{return this}
found(given)?.apply{ return this }
} else {
searchRoots.forEach{
found(File(it, givenPath))?.apply{return this}
@@ -74,7 +136,7 @@ class KonanLibrarySearchPathResolver(repositories: List<String>,
private val File.klib
get() = File(this, "klib")
// The libraries from the default root are linked autimatically.
// The libraries from the default root are linked automatically.
val defaultRoot: File?
get() = if (distHead?.exists ?: false) distHead else null
@@ -24,7 +24,7 @@ import java.nio.file.*
import java.nio.file.attribute.BasicFileAttributes
import java.nio.file.StandardOpenOption
class File constructor(internal val javaPath: Path) {
data class File constructor(internal val javaPath: Path) {
constructor(parent: Path, child: String): this(parent.resolve(child))
constructor(parent: File, child: String): this(parent.javaPath.resolve(child))
constructor(path: String): this(Paths.get(path))
@@ -1,8 +1,11 @@
package org.jetbrains.kotlin.cli.utilities
import org.jetbrains.kotlin.backend.konan.library.defaultResolver
import org.jetbrains.kotlin.backend.konan.library.impl.KonanLibrary
import org.jetbrains.kotlin.backend.konan.library.resolveLibrariesRecursive
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.target.TargetManager
import org.jetbrains.kotlin.utils.addIfNotNull
import org.jetbrains.kotlin.cli.bc.main as konancMain
import org.jetbrains.kotlin.native.interop.gen.jvm.interop
@@ -12,6 +15,7 @@ fun invokeCinterop(args: Array<String>) {
var outputFileName = "nativelib"
var target = "host"
val libraries = mutableListOf<String>()
val repos = mutableListOf<String>()
for (i in args.indices) {
val arg = args[i]
val nextArg = args.getOrNull(i + 1)
@@ -21,6 +25,8 @@ fun invokeCinterop(args: Array<String>) {
target = nextArg ?: target
if (arg == "-library")
libraries.addIfNotNull(nextArg)
if (arg == "-r" || arg == "-repo")
repos.addIfNotNull(nextArg)
}
val buildDir = File("$outputFileName-build")
@@ -29,14 +35,22 @@ fun invokeCinterop(args: Array<String>) {
val cstubsName ="cstubs"
val manifest = File(buildDir, "manifest.properties")
val importArgs = libraries.flatMap {
val library = KonanLibrary(File(it))
val targetManager = TargetManager(target)
val resolver = defaultResolver(repos, targetManager)
val allLibraries = resolver.resolveLibrariesRecursive(
libraries, targetManager.target, noStdLib = true, noDefaultLibs = false
)
val importArgs = allLibraries.flatMap {
val library = KonanLibrary(it.libraryFile)
val manifestProperties = library.manifestFile.loadProperties()
// TODO: handle missing properties?
val pkg = manifestProperties["pkg"] as String
val headerIds = (manifestProperties["includedHeaders"] as String).split(' ')
val arg = "$pkg:${headerIds.joinToString(",")}"
listOf("-import", arg)
manifestProperties["pkg"]?.let {
val pkg = it as String
val headerIds = (manifestProperties["includedHeaders"] as String).split(' ')
val arg = "$pkg:${headerIds.joinToString(",")}"
listOf("-import", arg)
} ?: emptyList()
}
val additionalArgs = listOf<String>(
@@ -58,7 +72,7 @@ fun invokeCinterop(args: Array<String>) {
"-o", outputFileName,
"-target", target,
"-manifest", manifest.path
) + cinteropArgsToCompiler + libraries.flatMap { listOf("-library", it) }
) + cinteropArgsToCompiler + libraries.flatMap { listOf("-library", it) } + repos.flatMap { listOf("-repo", it) }
konancMain(konancArgs)
}