[Interop] Move dependency resolution into processCLib

Because metadata mode doesn't call compiler we need to
resolve dependencies (including stdlib) by hand. This logic was partially
implemented in `InteropCompiler.kt`. So we move it into `processCLib`.
This commit is contained in:
Sergey Bogolepov
2019-11-21 13:39:38 +07:00
committed by Sergey Bogolepov
parent 2e22d5a389
commit e714f1e067
3 changed files with 64 additions and 62 deletions
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.konan.library.impl.KonanLibraryWriterImpl
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.library.KotlinLibraryVersioning import org.jetbrains.kotlin.library.KotlinLibraryVersioning
import org.jetbrains.kotlin.library.KotlinAbiVersion import org.jetbrains.kotlin.library.KotlinAbiVersion
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.SerializedMetadata import org.jetbrains.kotlin.library.SerializedMetadata
import org.jetbrains.kotlin.util.removeSuffixIfPresent import org.jetbrains.kotlin.util.removeSuffixIfPresent
import java.util.* import java.util.*
@@ -24,7 +25,8 @@ data class LibraryCreationArguments(
val moduleName: String, val moduleName: String,
val nativeBitcodePath: String, val nativeBitcodePath: String,
val target: KonanTarget, val target: KonanTarget,
val manifest: Properties val manifest: Properties,
val dependencies: List<KotlinLibrary>
) )
fun createInteropLibrary(arguments: LibraryCreationArguments) { fun createInteropLibrary(arguments: LibraryCreationArguments) {
@@ -47,6 +49,7 @@ fun createInteropLibrary(arguments: LibraryCreationArguments) {
addMetadata(SerializedMetadata(metadata.header, metadata.fragments, metadata.fragmentNames)) addMetadata(SerializedMetadata(metadata.header, metadata.fragments, metadata.fragmentNames))
addNativeBitcode(arguments.nativeBitcodePath) addNativeBitcode(arguments.nativeBitcodePath)
addManifestAddend(arguments.manifest) addManifestAddend(arguments.manifest)
addLinkDependencies(arguments.dependencies)
commit() commit()
} }
} }
@@ -24,8 +24,12 @@ import org.jetbrains.kotlin.native.interop.gen.wasm.processIdlLib
import org.jetbrains.kotlin.native.interop.indexer.* import org.jetbrains.kotlin.native.interop.indexer.*
import org.jetbrains.kotlin.native.interop.tool.* import org.jetbrains.kotlin.native.interop.tool.*
import kotlinx.cli.ArgParser import kotlinx.cli.ArgParser
import org.jetbrains.kotlin.konan.library.KLIB_INTEROP_IR_PROVIDER_IDENTIFIER import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.library.KotlinLibrary
import org.jetbrains.kotlin.library.resolver.impl.libraryResolver
import org.jetbrains.kotlin.library.toUnresolvedLibraries
import java.io.File import java.io.File
import java.lang.IllegalArgumentException import java.lang.IllegalArgumentException
import java.nio.file.* import java.nio.file.*
@@ -98,15 +102,14 @@ private fun selectNativeLanguage(config: DefFile.DefFileConfig): Language {
error("Unexpected language '$language'. Possible values are: ${languages.keys.joinToString { "'$it'" }}") error("Unexpected language '$language'. Possible values are: ${languages.keys.joinToString { "'$it'" }}")
} }
private fun parseImports(imports: Array<String>): ImportsImpl { private fun parseImports(dependencies: List<KotlinLibrary>): ImportsImpl =
val headerIdToPackage = imports.map { arg -> dependencies.filterIsInstance<KonanLibrary>().mapNotNull { library ->
val (pkg, joinedIds) = arg.split(':') // TODO: handle missing properties?
val ids = joinedIds.split(';') library.packageFqName?.let { packageFqName ->
ids.map { HeaderId(it) to pkg } val headerIds = library.includedHeaders
}.reversed().flatten().toMap() headerIds.map { HeaderId(it) to packageFqName }
}
return ImportsImpl(headerIdToPackage) }.reversed().flatten().toMap().let(::ImportsImpl)
}
fun getCompilerFlagsForVfsOverlay(headerFilterPrefix: Array<String>, def: DefFile): List<String> { fun getCompilerFlagsForVfsOverlay(headerFilterPrefix: Array<String>, def: DefFile): List<String> {
val relativeToRoot = mutableMapOf<Path, Path>() // TODO: handle clashes val relativeToRoot = mutableMapOf<Path, Path>() // TODO: handle clashes
@@ -161,7 +164,6 @@ private fun findFilesByGlobs(roots: List<Path>, globs: List<String>): Map<Path,
return relativeToRoot return relativeToRoot
} }
private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> = mapOf()): Array<String>? { private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> = mapOf()): Array<String>? {
val cinteropArguments = CInteropArguments() val cinteropArguments = CInteropArguments()
cinteropArguments.argParser.parse(args) cinteropArguments.argParser.parse(args)
@@ -209,11 +211,19 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
val outKtPkg = fqParts.joinToString(".") val outKtPkg = fqParts.joinToString(".")
val libName = (additionalArgs["cstubsname"] as? String)?: fqParts.joinToString("") + "stubs" val mode = parseGenerationMode(cinteropArguments.mode)
?: error ("Unexpected interop generation mode: ${cinteropArguments.mode}")
val allLibraryDependencies = when (flavor) {
KotlinPlatform.NATIVE -> resolveDependencies(cinteropArguments, tool.target)
else -> listOf()
}
val libName = additionalArgs["cstubsName"] as? String ?: fqParts.joinToString("") + "stubs"
val tempFiles = TempFiles(libName, cinteropArguments.tempDir) val tempFiles = TempFiles(libName, cinteropArguments.tempDir)
val imports = parseImports((additionalArgs["import"] as? List<String>)?.toTypedArray() ?: arrayOf()) val imports = parseImports(allLibraryDependencies)
val library = buildNativeLibrary(tool, def, cinteropArguments, imports) val library = buildNativeLibrary(tool, def, cinteropArguments, imports)
@@ -251,9 +261,6 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
{} {}
} }
val mode = parseGenerationMode(cinteropArguments.mode)
?: error ("Unexpected interop generation mode: ${cinteropArguments.mode}")
val stubIrContext = StubIrContext(logger, configuration, nativeIndex, imports, flavor, libName) val stubIrContext = StubIrContext(logger, configuration, nativeIndex, imports, flavor, libName)
val stubIrOutput = run { val stubIrOutput = run {
val outKtFileCreator = { val outKtFileCreator = {
@@ -320,7 +327,8 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
target = tool.target, target = tool.target,
moduleName = moduleName, moduleName = moduleName,
outputPath = cinteropArguments.output, outputPath = cinteropArguments.output,
manifest = def.manifestAddendProperties manifest = def.manifestAddendProperties,
dependencies = allLibraryDependencies
) )
createInteropLibrary(args) createInteropLibrary(args)
return null return null
@@ -328,6 +336,27 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
} }
} }
private fun resolveDependencies(
cinteropArguments: CInteropArguments, target: KonanTarget
): List<KotlinLibrary> {
val libraries = cinteropArguments.library
val repos = cinteropArguments.repo
val noDefaultLibs = cinteropArguments.nodefaultlibs || cinteropArguments.nodefaultlibsDeprecated
val noEndorsedLibs = cinteropArguments.noendorsedlibs
val resolver = defaultResolver(
repos,
libraries.filter { it.contains(org.jetbrains.kotlin.konan.file.File.separator) },
target,
Distribution()
).libraryResolver()
return resolver.resolveWithDependencies(
libraries.toUnresolvedLibraries,
noStdLib = false,
noDefaultLibs = noDefaultLibs,
noEndorsedLibs = noEndorsedLibs
).getFullList()
}
internal fun prepareTool(target: String?, flavor: KotlinPlatform): ToolConfig { internal fun prepareTool(target: String?, flavor: KotlinPlatform): ToolConfig {
val tool = ToolConfig(target, flavor) val tool = ToolConfig(target, flavor)
tool.downloadDependencies() tool.downloadDependencies()
@@ -5,14 +5,7 @@
package org.jetbrains.kotlin.cli.utilities package org.jetbrains.kotlin.cli.utilities
import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.library.KonanLibrary
import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.library.includedHeaders
import org.jetbrains.kotlin.konan.library.packageFqName
import org.jetbrains.kotlin.konan.target.Distribution
import org.jetbrains.kotlin.konan.target.PlatformManager import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.library.resolver.impl.libraryResolver
import org.jetbrains.kotlin.library.toUnresolvedLibraries
import org.jetbrains.kotlin.native.interop.gen.jvm.interop import org.jetbrains.kotlin.native.interop.gen.jvm.interop
import org.jetbrains.kotlin.native.interop.tool.* import org.jetbrains.kotlin.native.interop.tool.*
@@ -41,8 +34,6 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String>? {
"-natives", nativesDir.path, "-natives", nativesDir.path,
"-flavor", flavor "-flavor", flavor
) )
val additionalProperties = mutableMapOf<String, Any>(
"manifest" to manifest.path)
val cstubsName ="cstubs" val cstubsName ="cstubs"
val libraries = arguments.library val libraries = arguments.library
val repos = arguments.repo val repos = arguments.repo
@@ -50,31 +41,12 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String>? {
else (arguments as JSInteropArguments).target else (arguments as JSInteropArguments).target
val target = PlatformManager().targetManager(targetRequest).target val target = PlatformManager().targetManager(targetRequest).target
if (flavor == "native") { val cinteropArgsToCompiler = interop(flavor, args + additionalArgs,
val resolver = defaultResolver( listOfNotNull(
repos, "manifest" to manifest.path,
libraries.filter { it.contains(File.separator) }, ("cstubsName" to cstubsName).takeIf { flavor == "native" }
target, ).toMap()
Distribution() ) ?: return null // There is no need in compiler invocation if we're generating only metadata.
).libraryResolver()
val allLibraries = resolver.resolveWithDependencies(
libraries.toUnresolvedLibraries, noStdLib = true, noDefaultLibs = noDefaultLibs,
noEndorsedLibs = noEndorsedLibs
).getFullList() as List<KonanLibrary>
val imports = allLibraries.map { library ->
// TODO: handle missing properties?
library.packageFqName?.let { packageFqName ->
val headerIds = library.includedHeaders
"$packageFqName:${headerIds.joinToString(";")}"
}
}.filterNotNull()
additionalProperties.putAll(mapOf("cstubsname" to cstubsName, "import" to imports))
}
val cinteropArgsToCompiler = interop(flavor, args + additionalArgs, additionalProperties)
?: return null // There is no need in compiler invocation if we're generating only metadata.
val nativeStubs = val nativeStubs =
if (flavor == "wasm") if (flavor == "wasm")
@@ -82,7 +54,7 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String>? {
else else
arrayOf("-native-library", File(nativesDir, "$cstubsName.bc").path) arrayOf("-native-library", File(nativesDir, "$cstubsName.bc").path)
val konancArgs = arrayOf( return arrayOf(
generatedDir.path, generatedDir.path,
"-produce", "library", "-produce", "library",
"-o", outputFileName, "-o", outputFileName,
@@ -96,8 +68,6 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String>? {
(if (noDefaultLibs) arrayOf("-$NODEFAULTLIBS") else emptyArray()) + (if (noDefaultLibs) arrayOf("-$NODEFAULTLIBS") else emptyArray()) +
(if (noEndorsedLibs) arrayOf("-$NOENDORSEDLIBS") else emptyArray()) + (if (noEndorsedLibs) arrayOf("-$NOENDORSEDLIBS") else emptyArray()) +
(if (purgeUserLibs) arrayOf("-$PURGE_USER_LIBS") else emptyArray()) (if (purgeUserLibs) arrayOf("-$PURGE_USER_LIBS") else emptyArray())
return konancArgs
} }