Provided library versioning in klib. (#2038)
* Provided library versioning in klib. * A test for library mismatch messages.
This commit is contained in:
committed by
Dmitriy Dolovov
parent
d406b1b16d
commit
27ce3b194d
@@ -24,10 +24,11 @@ import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.util.profile
|
||||
import org.jetbrains.kotlin.konan.util.*
|
||||
import org.jetbrains.kotlin.metadata.deserialization.BinaryVersion
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.KotlinPaths
|
||||
@@ -142,7 +143,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
val outputKind = CompilerOutputKind.valueOf(
|
||||
(arguments.produce ?: "program").toUpperCase())
|
||||
put(PRODUCE, outputKind)
|
||||
put(ABI_VERSION, 1)
|
||||
arguments.libraryVersion ?. let { put(LIBRARY_VERSION, it) }
|
||||
|
||||
arguments.mainPackage ?.let{ put(ENTRY, it) }
|
||||
arguments.manifestFile ?.let{ put(MANIFEST_FILE, it) }
|
||||
|
||||
@@ -30,6 +30,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-library", shortName = "-l", valueDescription = "<path>", description = "Link with the library")
|
||||
var libraries: Array<String>? = null
|
||||
|
||||
@Argument(value = "-library-version", shortName = "-lv", valueDescription = "<version>", description = "Set library version")
|
||||
var libraryVersion: String? = null
|
||||
|
||||
@Argument(value = "-list-targets", deprecatedName = "-list_targets", description = "List available hardware targets")
|
||||
var listTargets: Boolean = false
|
||||
|
||||
|
||||
+10
-3
@@ -8,6 +8,9 @@ import llvm.LLVMLinkModules2
|
||||
import llvm.LLVMWriteBitcodeToFile
|
||||
import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary
|
||||
import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
|
||||
val CompilerOutputKind.isNativeBinary: Boolean get() = when (this) {
|
||||
@@ -62,17 +65,21 @@ internal fun produceOutput(context: Context, phaser: PhaseManager) {
|
||||
val libraryName = context.config.moduleId
|
||||
val neededLibraries
|
||||
= context.llvm.librariesForLibraryManifest
|
||||
val abiVersion = context.config.currentAbiVersion
|
||||
val abiVersion = KonanAbiVersion.CURRENT
|
||||
val compilerVersion = KonanVersion.CURRENT
|
||||
val libraryVersion = config.get(KonanConfigKeys.LIBRARY_VERSION)
|
||||
val versions = KonanLibraryVersioning(abiVersion = abiVersion, libraryVersion = libraryVersion, compilerVersion = compilerVersion)
|
||||
val target = context.config.target
|
||||
val nopack = config.getBoolean(KonanConfigKeys.NOPACK)
|
||||
val manifestProperties = context.config.manifestProperties
|
||||
|
||||
|
||||
val library = buildLibrary(
|
||||
context.config.nativeLibraries,
|
||||
context.config.includeBinaries,
|
||||
neededLibraries,
|
||||
context.serializedLinkData!!,
|
||||
abiVersion,
|
||||
context.serializedLinkData!!,
|
||||
versions,
|
||||
target,
|
||||
output,
|
||||
libraryName,
|
||||
|
||||
+10
-6
@@ -20,11 +20,11 @@ import org.jetbrains.kotlin.konan.library.defaultResolver
|
||||
import org.jetbrains.kotlin.konan.library.libraryResolver
|
||||
import org.jetbrains.kotlin.konan.properties.loadProperties
|
||||
import org.jetbrains.kotlin.konan.target.*
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.library.toUnresolvedLibraries
|
||||
|
||||
class KonanConfig(val project: Project, val configuration: CompilerConfiguration) {
|
||||
|
||||
val currentAbiVersion: Int = configuration.get(KonanConfigKeys.ABI_VERSION)!!
|
||||
|
||||
internal val distribution = Distribution(
|
||||
false,
|
||||
null,
|
||||
@@ -71,15 +71,18 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
private val libraryNames: List<String>
|
||||
get() = configuration.getList(KonanConfigKeys.LIBRARY_FILES)
|
||||
|
||||
private val unresolvedLibraries = libraryNames.toUnresolvedLibraries
|
||||
|
||||
private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES)
|
||||
private val resolver = defaultResolver(repositories, target, distribution).libraryResolver(currentAbiVersion)
|
||||
private fun resolverLogger(msg: String) = configuration.report(STRONG_WARNING, msg)
|
||||
|
||||
private val resolver = defaultResolver(repositories, target, distribution, ::resolverLogger).libraryResolver()
|
||||
|
||||
internal val resolvedLibraries by lazy {
|
||||
resolver.resolveWithDependencies(
|
||||
libraryNames,
|
||||
unresolvedLibraries,
|
||||
noStdLib = configuration.getBoolean(KonanConfigKeys.NOSTDLIB),
|
||||
noDefaultLibs = configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS) ) { msg ->
|
||||
configuration.report(STRONG_WARNING, msg) }
|
||||
noDefaultLibs = configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS) )
|
||||
}
|
||||
|
||||
fun librariesWithDependencies(moduleDescriptor: ModuleDescriptor?): List<KonanLibrary> {
|
||||
@@ -114,3 +117,4 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
|
||||
fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String)
|
||||
= this.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(priority, message)
|
||||
|
||||
|
||||
+4
-4
@@ -12,8 +12,6 @@ import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
class KonanConfigKeys {
|
||||
companion object {
|
||||
// Keep the list lexically sorted.
|
||||
val ABI_VERSION: CompilerConfigurationKey<Int>
|
||||
= CompilerConfigurationKey.create("current abi version")
|
||||
val CHECK_DEPENDENCIES: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create("check dependencies and download the missing ones")
|
||||
val DEBUG: CompilerConfigurationKey<Boolean>
|
||||
@@ -26,12 +24,16 @@ class KonanConfigKeys {
|
||||
= CompilerConfigurationKey.create("enable backend phases")
|
||||
val ENTRY: CompilerConfigurationKey<String?>
|
||||
= CompilerConfigurationKey.create("fully qualified main() name")
|
||||
val FRIEND_MODULES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create<List<String>>("friend module paths")
|
||||
val GENERATE_TEST_RUNNER: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create("generate test runner")
|
||||
val INCLUDED_BINARY_FILES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create("included binary file paths")
|
||||
val LIBRARY_FILES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create("library file paths")
|
||||
val LIBRARY_VERSION: CompilerConfigurationKey<String?>
|
||||
= CompilerConfigurationKey.create("library version")
|
||||
val LINKER_ARGS: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create("additional linker arguments")
|
||||
val LIST_PHASES: CompilerConfigurationKey<Boolean>
|
||||
@@ -94,8 +96,6 @@ class KonanConfigKeys {
|
||||
= CompilerConfigurationKey.create("verify ir")
|
||||
val VERBOSE_PHASES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create("verbose backend phases")
|
||||
val FRIEND_MODULES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create<List<String>>("friend module paths")
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -7,11 +7,11 @@ package org.jetbrains.kotlin.backend.konan.library
|
||||
|
||||
import llvm.LLVMModuleRef
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import java.util.*
|
||||
|
||||
const val KLIB_CURRENT_ABI_VERSION = 1
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
|
||||
interface KonanLibraryWriter {
|
||||
val versions: KonanLibraryVersioning
|
||||
fun addLinkData(linkData: LinkData)
|
||||
fun addNativeBitcode(library: String)
|
||||
fun addIncludedBinary(library: String)
|
||||
|
||||
+14
-8
@@ -11,10 +11,11 @@ import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
|
||||
import org.jetbrains.kotlin.backend.konan.library.LinkData
|
||||
import org.jetbrains.kotlin.konan.file.*
|
||||
import org.jetbrains.kotlin.konan.library.*
|
||||
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION
|
||||
import org.jetbrains.kotlin.konan.properties.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
abstract class FileBasedLibraryWriter (val file: File, val currentAbiVersion: Int): KonanLibraryWriter
|
||||
abstract class FileBasedLibraryWriter (val file: File): KonanLibraryWriter
|
||||
|
||||
/**
|
||||
* Requires non-null [target].
|
||||
@@ -22,13 +23,13 @@ abstract class FileBasedLibraryWriter (val file: File, val currentAbiVersion: In
|
||||
class LibraryWriterImpl(
|
||||
override val libDir: File,
|
||||
moduleName: String,
|
||||
currentAbiVersion: Int,
|
||||
override val versions: KonanLibraryVersioning,
|
||||
override val target: KonanTarget,
|
||||
val nopack: Boolean = false
|
||||
): FileBasedLibraryWriter(libDir, currentAbiVersion), KonanLibraryLayout {
|
||||
): FileBasedLibraryWriter(libDir), KonanLibraryLayout {
|
||||
|
||||
constructor(path: String, moduleName: String, currentAbiVersion: Int, target: KonanTarget, nopack: Boolean):
|
||||
this(File(path), moduleName, currentAbiVersion, target, nopack)
|
||||
constructor(path: String, moduleName: String, versions: KonanLibraryVersioning, target: KonanTarget, nopack: Boolean):
|
||||
this(File(path), moduleName, versions, target, nopack)
|
||||
|
||||
override val libraryName = libDir.path
|
||||
val klibFile
|
||||
@@ -53,7 +54,7 @@ class LibraryWriterImpl(
|
||||
resourcesDir.mkdirs()
|
||||
// TODO: <name>:<hash> will go somewhere around here.
|
||||
manifestProperties.setProperty(KLIB_PROPERTY_UNIQUE_NAME, moduleName)
|
||||
manifestProperties.setProperty(KLIB_PROPERTY_ABI_VERSION, currentAbiVersion.toString())
|
||||
manifestProperties.writeKonanLibraryVersioning(versions)
|
||||
}
|
||||
|
||||
var llvmModule: LLVMModuleRef? = null
|
||||
@@ -85,6 +86,11 @@ class LibraryWriterImpl(
|
||||
} else {
|
||||
val newValue = libraries.joinToString(" ") { it.uniqueName }
|
||||
manifestProperties.setProperty(KLIB_PROPERTY_DEPENDS, newValue)
|
||||
libraries.forEach { it ->
|
||||
if (it.versions.libraryVersion != null) {
|
||||
manifestProperties.setProperty("${KLIB_PROPERTY_DEPENDENCY_VERSION}_${it.uniqueName}", it.versions.libraryVersion)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -110,7 +116,7 @@ internal fun buildLibrary(
|
||||
included: List<String>,
|
||||
linkDependencies: List<KonanLibrary>,
|
||||
linkData: LinkData,
|
||||
abiVersion: Int,
|
||||
versions: KonanLibraryVersioning,
|
||||
target: KonanTarget,
|
||||
output: String,
|
||||
moduleName: String,
|
||||
@@ -119,7 +125,7 @@ internal fun buildLibrary(
|
||||
manifestProperties: Properties?,
|
||||
dataFlowGraph: ByteArray?): KonanLibraryWriter {
|
||||
|
||||
val library = LibraryWriterImpl(output, moduleName, abiVersion, target, nopack)
|
||||
val library = LibraryWriterImpl(File(output), moduleName, versions, target, nopack)
|
||||
|
||||
library.addKotlinBitcode(llvmModule)
|
||||
library.addLinkData(linkData)
|
||||
|
||||
@@ -2892,6 +2892,37 @@ task produce_dynamic(type: DynamicKonanTest) {
|
||||
"topLevel = 777 3\n"
|
||||
}
|
||||
|
||||
task library_mismatch(type: RunStandaloneKonanTest) {
|
||||
def dir = buildDir.absolutePath
|
||||
def lib = "$projectDir/link/versioning/empty.kt"
|
||||
|
||||
def currentTarget = project.target.name
|
||||
def someOtherTarget = (project.testTarget == 'wasm32' ? project.hostName : 'wasm32')
|
||||
|
||||
if (!useCustomDist) {
|
||||
dependsOn ':wasm32CrossDistRuntime' // we actually need any target other than the current one.
|
||||
}
|
||||
|
||||
doFirst {
|
||||
def konancScript = isWindows() ? "konanc.bat" : "konanc"
|
||||
def konanc = "$dist/bin/$konancScript"
|
||||
|
||||
"$konanc $lib -p library -o $dir/1.2/empty -target $currentTarget -lv 1.2".execute().waitFor()
|
||||
"$konanc $lib -p library -o $dir/3.4/empty -target $someOtherTarget".execute().waitFor()
|
||||
"$konanc $lib -p library -o $dir/5.6/empty -target $currentTarget -lv 5.6".execute().waitFor()
|
||||
"$konanc $lib -p library -o $dir/7.8/empty -target $currentTarget -lv 7.8".execute().waitFor()
|
||||
|
||||
}
|
||||
source = "link/versioning/hello.kt"
|
||||
flags = ['-l', 'empty@5.6', '-r', "$dir/1.2", '-r', "$dir/3.4", '-r', "$dir/5.6"]
|
||||
compilerMessages = true
|
||||
def messages =
|
||||
"warning: skipping $dir/1.2/empty.klib. The library versions don't match. Expected '5.6', found '1.2'\n" +
|
||||
"warning: skipping $dir/3.4/empty.klib. The target doesn't match. Expected '$currentTarget', found [$someOtherTarget]\n" +
|
||||
"Hello, versioned world!\n"
|
||||
goldValue = isWindows() ? messages.replaceAll('\\/', '\\\\') : messages
|
||||
}
|
||||
|
||||
if (isMac() && project.testTarget != 'wasm32') {
|
||||
def target = ext.platformManager.targetByName(project.testTarget ?: 'host').name
|
||||
|
||||
|
||||
@@ -0,0 +1,2 @@
|
||||
/* This file has intentionally been left blank */
|
||||
|
||||
@@ -0,0 +1,3 @@
|
||||
fun main(args: Array<String>) {
|
||||
println("Hello, versioned world!")
|
||||
}
|
||||
@@ -47,6 +47,7 @@ abstract class KonanTest extends JavaExec {
|
||||
boolean enabled = true
|
||||
boolean expectedFail = false
|
||||
boolean run = true
|
||||
boolean compilerMessages = false
|
||||
|
||||
void setDisabled(boolean value) {
|
||||
this.enabled = !value
|
||||
@@ -268,6 +269,8 @@ abstract class KonanTest extends JavaExec {
|
||||
}
|
||||
println "execution: $exe"
|
||||
|
||||
def compilerMessagesText = compilerMessages ? project.file("${program}.compilation.log").getText('UTF-8') : ""
|
||||
|
||||
def out = new ByteArrayOutputStream()
|
||||
//TODO Add test timeout
|
||||
ExecResult execResult = project.execute {
|
||||
@@ -284,7 +287,7 @@ abstract class KonanTest extends JavaExec {
|
||||
|
||||
ignoreExitValue = true
|
||||
}
|
||||
def result = out.toString("UTF-8")
|
||||
def result = compilerMessagesText + out.toString("UTF-8")
|
||||
|
||||
println(result)
|
||||
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolver
|
||||
import org.jetbrains.kotlin.konan.library.resolver.impl.KonanLibraryResolverImpl
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
|
||||
fun SearchPathResolverWithTarget.libraryResolver(): KonanLibraryResolver =
|
||||
KonanLibraryResolverImpl(this)
|
||||
+3
-7
@@ -2,23 +2,20 @@ package org.jetbrains.kotlin.konan.library.resolver
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.SearchPathResolverWithTarget
|
||||
|
||||
typealias DuplicatedLibraryLogger = (String) -> Unit
|
||||
import org.jetbrains.kotlin.konan.library.UnresolvedLibrary
|
||||
|
||||
interface KonanLibraryResolver {
|
||||
|
||||
val searchPathResolver: SearchPathResolverWithTarget
|
||||
val abiVersion: Int
|
||||
|
||||
/**
|
||||
* Given the list of Kotlin/Native library names, ABI version and other parameters
|
||||
* resolves libraries and evaluates dependencies between them.
|
||||
*/
|
||||
fun resolveWithDependencies(
|
||||
libraryNames: List<String>,
|
||||
unresolvedLibraries: List<UnresolvedLibrary>,
|
||||
noStdLib: Boolean = false,
|
||||
noDefaultLibs: Boolean = false,
|
||||
logger: DuplicatedLibraryLogger? = null
|
||||
noDefaultLibs: Boolean = false
|
||||
): KonanLibraryResolveResult
|
||||
}
|
||||
|
||||
@@ -31,7 +28,6 @@ interface KonanLibraryResolveResult {
|
||||
fun forEach(action: (KonanLibrary, PackageAccessedHandler) -> Unit)
|
||||
}
|
||||
|
||||
|
||||
typealias LibraryOrder = (Iterable<KonanResolvedLibrary>) -> List<KonanResolvedLibrary>
|
||||
|
||||
val TopologicalLibraryOrder: LibraryOrder = { input ->
|
||||
|
||||
+1
-2
@@ -1,11 +1,10 @@
|
||||
package org.jetbrains.kotlin.konan.library.resolver
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
interface PackageAccessedHandler {
|
||||
|
||||
fun markPackageAccessed(fqName: FqName)
|
||||
fun markPackageAccessed(fqName: String)
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
+25
-31
@@ -1,24 +1,20 @@
|
||||
package org.jetbrains.kotlin.konan.library.resolver.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.SearchPathResolverWithTarget
|
||||
import org.jetbrains.kotlin.konan.library.createKonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.*
|
||||
import org.jetbrains.kotlin.konan.library.resolver.*
|
||||
import org.jetbrains.kotlin.konan.library.unresolvedDependencies
|
||||
import org.jetbrains.kotlin.konan.util.WithLogger
|
||||
|
||||
internal class KonanLibraryResolverImpl(
|
||||
override val searchPathResolver: SearchPathResolverWithTarget,
|
||||
override val abiVersion: Int
|
||||
): KonanLibraryResolver {
|
||||
override val searchPathResolver: SearchPathResolverWithTarget
|
||||
): KonanLibraryResolver, WithLogger by searchPathResolver {
|
||||
|
||||
override fun resolveWithDependencies(
|
||||
libraryNames: List<String>,
|
||||
unresolvedLibraries: List<UnresolvedLibrary>,
|
||||
noStdLib: Boolean,
|
||||
noDefaultLibs: Boolean,
|
||||
logger: DuplicatedLibraryLogger?
|
||||
) = findLibraries(libraryNames, noStdLib, noDefaultLibs)
|
||||
.leaveDistinct(logger)
|
||||
noDefaultLibs: Boolean
|
||||
) = findLibraries(unresolvedLibraries, noStdLib, noDefaultLibs)
|
||||
.leaveDistinct()
|
||||
.resolveDependencies()
|
||||
|
||||
/**
|
||||
@@ -28,19 +24,16 @@ internal class KonanLibraryResolverImpl(
|
||||
* from the original library set (root set).
|
||||
*/
|
||||
private fun findLibraries(
|
||||
libraryNames: List<String>,
|
||||
unresolvedLibraries: List<UnresolvedLibrary>,
|
||||
noStdLib: Boolean,
|
||||
noDefaultLibs: Boolean
|
||||
): List<KonanLibrary> {
|
||||
|
||||
val userProvidedLibraries = libraryNames.asSequence()
|
||||
val userProvidedLibraries = unresolvedLibraries.asSequence()
|
||||
.map { searchPathResolver.resolve(it) }
|
||||
.map { createKonanLibrary(it, abiVersion, searchPathResolver.target) }
|
||||
.toList()
|
||||
|
||||
val defaultLibraries = searchPathResolver.defaultLinks(noStdLib, noDefaultLibs).map {
|
||||
createKonanLibrary(it, abiVersion, searchPathResolver.target, isDefault = true)
|
||||
}
|
||||
val defaultLibraries = searchPathResolver.defaultLinks(noStdLib, noDefaultLibs)
|
||||
|
||||
// Make sure the user provided ones appear first, so that
|
||||
// they have precedence over defaults when duplicates are eliminated.
|
||||
@@ -50,14 +43,13 @@ internal class KonanLibraryResolverImpl(
|
||||
/**
|
||||
* Leaves only distinct libraries (by absolute path), warns on duplicated paths.
|
||||
*/
|
||||
private fun List<KonanLibrary>.leaveDistinct(logger: DuplicatedLibraryLogger?) =
|
||||
private fun List<KonanLibrary>.leaveDistinct() =
|
||||
this.groupBy { it.libraryFile.absolutePath }.let { groupedByAbsolutePath ->
|
||||
warnOnLibraryDuplicates(groupedByAbsolutePath.filter { it.value.size > 1 }.keys, logger)
|
||||
warnOnLibraryDuplicates(groupedByAbsolutePath.filter { it.value.size > 1 }.keys)
|
||||
groupedByAbsolutePath.map { it.value.first() }
|
||||
}
|
||||
|
||||
private fun warnOnLibraryDuplicates(duplicatedPaths: Iterable<String>, logger: DuplicatedLibraryLogger? ) {
|
||||
if (logger == null) return
|
||||
private fun warnOnLibraryDuplicates(duplicatedPaths: Iterable<String>) {
|
||||
duplicatedPaths.forEach { logger("library included more than once: $it") }
|
||||
}
|
||||
|
||||
@@ -84,18 +76,20 @@ internal class KonanLibraryResolverImpl(
|
||||
do {
|
||||
newDependencies = newDependencies.map { library: KonanResolvedLibraryImpl ->
|
||||
library.library.unresolvedDependencies.asSequence()
|
||||
.map { searchPathResolver.resolve(it).absoluteFile }
|
||||
.mapNotNull {
|
||||
if (it in cache) {
|
||||
library.addDependency(cache[it]!!)
|
||||
|
||||
.map { KonanResolvedLibraryImpl(searchPathResolver.resolve(it)) }
|
||||
.map { resolved ->
|
||||
val absoluteFile = resolved.library.libraryFile.absoluteFile
|
||||
if (absoluteFile in cache) {
|
||||
library.addDependency(cache[absoluteFile]!!)
|
||||
null
|
||||
} else {
|
||||
val newLibrary = KonanResolvedLibraryImpl(createKonanLibrary(it, abiVersion, searchPathResolver.target))
|
||||
cache[it] = newLibrary
|
||||
library.addDependency(newLibrary)
|
||||
newLibrary
|
||||
cache.put(absoluteFile, resolved)
|
||||
library.addDependency(resolved)
|
||||
resolved
|
||||
}
|
||||
}
|
||||
|
||||
}.filterNotNull()
|
||||
.toList()
|
||||
}.flatten()
|
||||
} while (newDependencies.isNotEmpty())
|
||||
|
||||
+2
-3
@@ -2,7 +2,6 @@ package org.jetbrains.kotlin.konan.library.resolver.impl
|
||||
|
||||
import org.jetbrains.kotlin.konan.library.KonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.resolver.KonanResolvedLibrary
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.serialization.konan.parseModuleHeader
|
||||
|
||||
internal class KonanResolvedLibraryImpl(
|
||||
@@ -23,9 +22,9 @@ internal class KonanResolvedLibraryImpl(
|
||||
override val isDefault: Boolean
|
||||
get() = library.isDefault
|
||||
|
||||
override fun markPackageAccessed(fqName: FqName) {
|
||||
override fun markPackageAccessed(fqName: String) {
|
||||
if (!isNeededForLink // fast path
|
||||
&& !_emptyPackages.contains(fqName.asString())) {
|
||||
&& !_emptyPackages.contains(fqName)) {
|
||||
isNeededForLink = true
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -35,7 +35,7 @@ class KonanPackageFragment(
|
||||
}
|
||||
|
||||
val proto: KonanProtoBuf.LinkDataPackageFragment
|
||||
get() = protoForNames.also { packageAccessedHandler?.markPackageAccessed(fqName) }
|
||||
get() = protoForNames.also { packageAccessedHandler?.markPackageAccessed(fqName.toString()) }
|
||||
|
||||
private val nameResolver by lazy {
|
||||
NameResolverImpl(protoForNames.stringTable, protoForNames.nameTable)
|
||||
|
||||
+2
-2
@@ -41,9 +41,9 @@ internal object KonanDeserializedPackageFragmentsFactoryImpl: KonanDeserializedP
|
||||
|
||||
if (!library.isInterop) return emptyList()
|
||||
|
||||
val mainPackageFqName = library.packageFqName
|
||||
val mainPackageFqName = library.packageFqName ?.let { FqName(it) }
|
||||
?: error("Inconsistent manifest: interop library ${library.libraryName} should have `package` specified")
|
||||
val exportForwardDeclarations = library.exportForwardDeclarations
|
||||
val exportForwardDeclarations = library.exportForwardDeclarations.map { FqName(it) }
|
||||
|
||||
val aliasedPackageFragments = deserializedPackageFragments.filter { it.fqName == mainPackageFqName }
|
||||
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.cli.klib
|
||||
|
||||
// TODO: Extract `library` package as a shared jar?
|
||||
import org.jetbrains.kotlin.backend.konan.library.KLIB_CURRENT_ABI_VERSION
|
||||
import org.jetbrains.kotlin.config.ApiVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersion
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl
|
||||
@@ -15,11 +14,12 @@ import org.jetbrains.kotlin.descriptors.konan.isKonanStdlib
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.KLIB_FILE_EXTENSION_WITH_DOT
|
||||
import org.jetbrains.kotlin.konan.library.createKonanLibrary
|
||||
import org.jetbrains.kotlin.konan.library.noTargetResolver
|
||||
import org.jetbrains.kotlin.konan.library.unpackZippedKonanLibraryTo
|
||||
import org.jetbrains.kotlin.konan.library.resolverByName
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.PlatformManager
|
||||
import org.jetbrains.kotlin.konan.util.DependencyProcessor
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.library.unpackZippedKonanLibraryTo
|
||||
import org.jetbrains.kotlin.konan.utils.KonanFactories.DefaultDeserializedDescriptorFactory
|
||||
import org.jetbrains.kotlin.metadata.konan.KonanProtoBuf
|
||||
import org.jetbrains.kotlin.serialization.konan.parseModuleHeader
|
||||
@@ -96,31 +96,30 @@ class Library(val name: String, val requestedRepository: String?, val target: St
|
||||
val repository = requestedRepository?.File() ?: defaultRepository
|
||||
fun info() {
|
||||
val library = libraryInRepoOrCurrentDir(repository, name)
|
||||
val reader = createKonanLibrary(library, currentAbiVersion)
|
||||
val headerAbiVersion = reader.abiVersion
|
||||
val moduleName = ModuleDeserializer(reader.moduleHeaderData).moduleName
|
||||
val headerAbiVersion = library.versions.abiVersion
|
||||
val moduleName = ModuleDeserializer(library.moduleHeaderData).moduleName
|
||||
|
||||
println("")
|
||||
println("Resolved to: ${reader.libraryName.File().absolutePath}")
|
||||
println("Resolved to: ${library.libraryName.File().absolutePath}")
|
||||
println("Module name: $moduleName")
|
||||
println("ABI version: $headerAbiVersion")
|
||||
val targets = reader.targetList.joinToString(", ")
|
||||
val targets = library.targetList.joinToString(", ")
|
||||
print("Available targets: $targets\n")
|
||||
}
|
||||
|
||||
fun install() {
|
||||
Library(File(name).name.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT), requestedRepository, target).remove(true)
|
||||
|
||||
val klibFile = libraryInCurrentDir(name)
|
||||
val newLibDir = File(repository, klibFile.name.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT))
|
||||
val library = libraryInCurrentDir(name)
|
||||
val newLibDir = File(repository, library.libraryFile.name.removeSuffix(KLIB_FILE_EXTENSION_WITH_DOT))
|
||||
|
||||
klibFile.unpackZippedKonanLibraryTo(newLibDir)
|
||||
library.libraryFile.unpackZippedKonanLibraryTo(newLibDir)
|
||||
}
|
||||
|
||||
fun remove(blind: Boolean = false) {
|
||||
if (!repository.exists) error("Repository does not exist: $repository")
|
||||
|
||||
val libDir = try {
|
||||
val library = try {
|
||||
val library = libraryInRepo(repository, name)
|
||||
if (blind) warn("Removing The previously installed $name from $repository.")
|
||||
library
|
||||
@@ -130,26 +129,26 @@ class Library(val name: String, val requestedRepository: String?, val target: St
|
||||
null
|
||||
|
||||
}
|
||||
libDir?.deleteRecursively()
|
||||
library?.libraryFile?.deleteRecursively()
|
||||
}
|
||||
|
||||
fun contents(output: Appendable = out) {
|
||||
|
||||
val storageManager = LockBasedStorageManager()
|
||||
val library = createKonanLibrary(libraryInRepoOrCurrentDir(repository, name), currentAbiVersion)
|
||||
val library = libraryInRepoOrCurrentDir(repository, name)
|
||||
val versionSpec = LanguageVersionSettingsImpl(currentLanguageVersion, currentApiVersion)
|
||||
val module = DefaultDeserializedDescriptorFactory.createDescriptorAndNewBuiltIns(library, versionSpec, storageManager)
|
||||
|
||||
val defaultModules = mutableListOf<ModuleDescriptorImpl>()
|
||||
if (!module.isKonanStdlib()) {
|
||||
val resolver = noTargetResolver(
|
||||
val resolver = resolverByName(
|
||||
emptyList(),
|
||||
distributionKlib = Distribution().klib,
|
||||
skipCurrentDir = true)
|
||||
resolver.defaultLinks(false, true)
|
||||
.mapTo(defaultModules) {
|
||||
DefaultDeserializedDescriptorFactory.createDescriptor(
|
||||
createKonanLibrary(it, currentAbiVersion), versionSpec, storageManager, module.builtIns)
|
||||
it, versionSpec, storageManager, module.builtIns)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -161,17 +160,16 @@ class Library(val name: String, val requestedRepository: String?, val target: St
|
||||
}
|
||||
}
|
||||
|
||||
const val currentAbiVersion = KLIB_CURRENT_ABI_VERSION
|
||||
val currentLanguageVersion = LanguageVersion.LATEST_STABLE
|
||||
val currentApiVersion = ApiVersion.LATEST_STABLE
|
||||
|
||||
fun libraryInRepo(repository: File, name: String) =
|
||||
noTargetResolver(listOf(repository.absolutePath), skipCurrentDir = true).resolve(name)
|
||||
resolverByName(listOf(repository.absolutePath), skipCurrentDir = true).resolve(name)
|
||||
|
||||
fun libraryInCurrentDir(name: String) = noTargetResolver(emptyList()).resolve(name)
|
||||
fun libraryInCurrentDir(name: String) = resolverByName(emptyList()).resolve(name)
|
||||
|
||||
fun libraryInRepoOrCurrentDir(repository: File, name: String) =
|
||||
noTargetResolver(listOf(repository.absolutePath)).resolve(name)
|
||||
resolverByName(listOf(repository.absolutePath)).resolve(name)
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
val command = Command(args)
|
||||
|
||||
@@ -40,6 +40,7 @@ task generateCompilerVersion(type: VersionGenerator){}
|
||||
sourceSets {
|
||||
main.kotlin {
|
||||
srcDir 'src/main/kotlin'
|
||||
srcDir 'src/library/kotlin'
|
||||
srcDir generateCompilerVersion.versionSourceDirectory
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,6 +93,17 @@ open class VersionGenerator: DefaultTask() {
|
||||
|
|
||||
| override fun toString() = versionString
|
||||
|}
|
||||
|fun String.parseKonanVersion(): KonanVersion {
|
||||
| val (major, minor, maintenance, meta, build) =
|
||||
| Regex(""${'"'}([0-9]+)\.([0-9]+)(?:\.([0-9]+))?(?:-(\p{Alpha}\p{Alnum}*))?(?:-([0-9]+))?""${'"'})
|
||||
| .matchEntire(this)!!.destructured
|
||||
| return KonanVersionImpl(
|
||||
| MetaVersion.valueOf(meta.toUpperCase()),
|
||||
| major.toInt(),
|
||||
| minor.toInt(),
|
||||
| maintenance.toIntOrNull() ?: 0,
|
||||
| build.toIntOrNull() ?: -1)
|
||||
|}
|
||||
""".trimMargin()
|
||||
}
|
||||
versionFile.printWriter().use {
|
||||
|
||||
+10
-5
@@ -3,9 +3,11 @@ package org.jetbrains.kotlin.konan.library
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jetbrains.kotlin.konan.properties.propertyList
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
const val KLIB_PROPERTY_ABI_VERSION = "abi_version"
|
||||
const val KLIB_PROPERTY_COMPILER_VERSION = "compiler_version"
|
||||
const val KLIB_PROPERTY_DEPENDENCY_VERSION = "dependency_version"
|
||||
const val KLIB_PROPERTY_LIBRARY_VERSION = "library_version"
|
||||
const val KLIB_PROPERTY_UNIQUE_NAME = "unique_name"
|
||||
const val KLIB_PROPERTY_LINKED_OPTS = "linkerOpts"
|
||||
const val KLIB_PROPERTY_DEPENDS = "depends"
|
||||
@@ -27,7 +29,6 @@ interface KonanLibrary {
|
||||
|
||||
// Properties:
|
||||
val manifestProperties: Properties
|
||||
val abiVersion: String
|
||||
val linkerOpts: List<String>
|
||||
|
||||
// Paths:
|
||||
@@ -35,6 +36,7 @@ interface KonanLibrary {
|
||||
val includedPaths: List<String>
|
||||
|
||||
val targetList: List<String>
|
||||
val versions: KonanLibraryVersioning
|
||||
|
||||
val dataFlowGraph: ByteArray?
|
||||
val moduleHeaderData: ByteArray
|
||||
@@ -44,21 +46,24 @@ interface KonanLibrary {
|
||||
val KonanLibrary.uniqueName
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_UNIQUE_NAME)!!
|
||||
|
||||
val KonanLibrary.unresolvedDependencies: List<String>
|
||||
val KonanLibrary.unresolvedDependencies: List<UnresolvedLibrary>
|
||||
get() = manifestProperties.propertyList(KLIB_PROPERTY_DEPENDS)
|
||||
.map {
|
||||
UnresolvedLibrary(it, manifestProperties.getProperty("dependency_version_$it"))
|
||||
}
|
||||
|
||||
val KonanLibrary.isInterop
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_INTEROP) == "true"
|
||||
|
||||
val KonanLibrary.packageFqName
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_PACKAGE)?.let { FqName(it) }
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_PACKAGE)
|
||||
|
||||
val KonanLibrary.exportForwardDeclarations
|
||||
get() = manifestProperties.getProperty(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS)
|
||||
.split(' ').asSequence()
|
||||
.map { it.trim() }
|
||||
.filter { it.isNotEmpty() }
|
||||
.map { FqName(it) }
|
||||
.map { it }
|
||||
.toList()
|
||||
|
||||
val KonanLibrary.includedHeaders
|
||||
+13
-8
@@ -3,14 +3,14 @@ package org.jetbrains.kotlin.konan.library
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.file.file
|
||||
import org.jetbrains.kotlin.konan.file.withMutableZipFileSystem
|
||||
import org.jetbrains.kotlin.konan.file.withZipFileSystem
|
||||
import org.jetbrains.kotlin.konan.library.impl.DefaultMetadataReaderImpl
|
||||
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
|
||||
import org.jetbrains.kotlin.konan.library.impl.zippedKonanLibraryChecks
|
||||
import org.jetbrains.kotlin.konan.library.resolver.KonanLibraryResolver
|
||||
import org.jetbrains.kotlin.konan.library.resolver.impl.KonanLibraryResolverImpl
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
val KLIB_FILE_EXTENSION = "klib"
|
||||
val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION"
|
||||
|
||||
fun File.unpackZippedKonanLibraryTo(newDir: File) {
|
||||
|
||||
// First, run validity checks for the given KLIB file.
|
||||
@@ -29,13 +29,18 @@ fun File.unpackZippedKonanLibraryTo(newDir: File) {
|
||||
check(newDir.exists) { "Could not unpack $this as $newDir." }
|
||||
}
|
||||
|
||||
val List<String>.toUnresolvedLibraries
|
||||
get() = this.map {
|
||||
|
||||
val version = it.substringAfterLast('@', "")
|
||||
.let { if (it.isEmpty()) null else it}
|
||||
val name = it.substringBeforeLast('@')
|
||||
UnresolvedLibrary(name, version)
|
||||
}
|
||||
|
||||
fun createKonanLibrary(
|
||||
libraryFile: File,
|
||||
currentAbiVersion: Int,
|
||||
target: KonanTarget? = null,
|
||||
isDefault: Boolean = false,
|
||||
metadataReader: MetadataReader = DefaultMetadataReaderImpl
|
||||
): KonanLibrary = KonanLibraryImpl(libraryFile, currentAbiVersion, target, isDefault, metadataReader)
|
||||
|
||||
fun SearchPathResolverWithTarget.libraryResolver(abiVersion: Int): KonanLibraryResolver =
|
||||
KonanLibraryResolverImpl(this, abiVersion)
|
||||
): KonanLibrary = KonanLibraryImpl(libraryFile, target, isDefault, metadataReader)
|
||||
+28
@@ -0,0 +1,28 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.parseKonanVersion
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.properties.Properties
|
||||
import org.jetbrains.kotlin.konan.parseKonanAbiVersion
|
||||
|
||||
|
||||
data class KonanLibraryVersioning(
|
||||
val libraryVersion: String?,
|
||||
val compilerVersion: KonanVersion,
|
||||
val abiVersion: KonanAbiVersion
|
||||
)
|
||||
|
||||
fun Properties.writeKonanLibraryVersioning(versions: KonanLibraryVersioning) {
|
||||
this.setProperty(KLIB_PROPERTY_ABI_VERSION, versions.abiVersion.toString())
|
||||
versions.libraryVersion ?. let { this.setProperty(KLIB_PROPERTY_LIBRARY_VERSION, it) }
|
||||
this.setProperty(KLIB_PROPERTY_COMPILER_VERSION, "${versions.compilerVersion}")
|
||||
}
|
||||
|
||||
fun Properties.readKonanLibraryVersioning(): KonanLibraryVersioning {
|
||||
val abiVersion = this.getProperty(KLIB_PROPERTY_ABI_VERSION)!!.parseKonanAbiVersion()
|
||||
val libraryVersion = this.getProperty(KLIB_PROPERTY_LIBRARY_VERSION)
|
||||
val compilerVersion = this.getProperty(KLIB_PROPERTY_COMPILER_VERSION)!!.parseKonanVersion()
|
||||
|
||||
return KonanLibraryVersioning(abiVersion = abiVersion, libraryVersion = libraryVersion, compilerVersion = compilerVersion)
|
||||
}
|
||||
@@ -0,0 +1,200 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.KonanVersion
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.*
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the constants below:
|
||||
const val KONAN_STDLIB_NAME = "stdlib"
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this interface!
|
||||
interface SearchPathResolver : WithLogger {
|
||||
val searchRoots: List<File>
|
||||
fun resolutionSequence(givenPath: String): Sequence<File>
|
||||
fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean = false): KonanLibraryImpl
|
||||
fun resolve(givenPath: String): KonanLibraryImpl
|
||||
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<KonanLibraryImpl>
|
||||
}
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this interface!
|
||||
interface SearchPathResolverWithTarget: SearchPathResolver {
|
||||
val target: KonanTarget
|
||||
val knownAbiVersions: List<KonanAbiVersion>?
|
||||
val knownCompilerVersions: List<KonanVersion>?
|
||||
}
|
||||
|
||||
fun defaultResolver(
|
||||
repositories: List<String>,
|
||||
target: KonanTarget
|
||||
): SearchPathResolverWithTarget = defaultResolver(repositories, target, Distribution())
|
||||
|
||||
fun defaultResolver(
|
||||
repositories: List<String>,
|
||||
target: KonanTarget,
|
||||
distribution: Distribution,
|
||||
logger: Logger = ::dummyLogger,
|
||||
skipCurrentDir: Boolean = false
|
||||
): SearchPathResolverWithTarget = KonanLibraryProperResolver(
|
||||
repositories,
|
||||
target,
|
||||
listOf(KonanAbiVersion.CURRENT),
|
||||
listOf(KonanVersion.CURRENT),
|
||||
distribution.klib,
|
||||
distribution.localKonanDir.absolutePath,
|
||||
skipCurrentDir,
|
||||
logger)
|
||||
|
||||
fun resolverByName(
|
||||
repositories: List<String>,
|
||||
distributionKlib: String? = null,
|
||||
localKonanDir: String? = null,
|
||||
skipCurrentDir: Boolean = false
|
||||
): SearchPathResolver = KonanLibrarySearchPathResolver(repositories, distributionKlib, localKonanDir, skipCurrentDir)
|
||||
|
||||
internal open class KonanLibrarySearchPathResolver(
|
||||
repositories: List<String>,
|
||||
val distributionKlib: String?,
|
||||
val localKonanDir: String?,
|
||||
val skipCurrentDir: Boolean,
|
||||
override val logger:Logger = ::dummyLogger
|
||||
) : SearchPathResolver {
|
||||
|
||||
val localHead: File?
|
||||
get() = localKonanDir?.File()?.klib
|
||||
|
||||
val distHead: File?
|
||||
get() = distributionKlib?.File()?.child("common")
|
||||
|
||||
open val distPlatformHead: File? = null
|
||||
|
||||
val currentDirHead: File?
|
||||
get() = if (!skipCurrentDir) File.userDir else null
|
||||
|
||||
private val repoRoots: List<File> by lazy { repositories.map { File(it) } }
|
||||
|
||||
// This is the place where we specify the order of library search.
|
||||
override val searchRoots: List<File> by lazy {
|
||||
(listOf(currentDirHead) + repoRoots + listOf(localHead, distHead, distPlatformHead)).filterNotNull()
|
||||
}
|
||||
|
||||
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_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
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolutionSequence(givenPath: String): Sequence<File> {
|
||||
val given = File(givenPath)
|
||||
val sequence = if (given.isAbsolute) {
|
||||
sequenceOf(found(given))
|
||||
} else {
|
||||
searchRoots.asSequence().map {
|
||||
found(File(it, givenPath))
|
||||
}
|
||||
}
|
||||
return sequence.filterNotNull()
|
||||
}
|
||||
|
||||
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): KonanLibraryImpl {
|
||||
val givenPath = unresolved.path
|
||||
return resolutionSequence(givenPath).firstOrNull() ?. let {
|
||||
createKonanLibrary(it, null, isDefaultLink) as KonanLibraryImpl
|
||||
} ?: error("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
|
||||
}
|
||||
|
||||
override fun resolve(givenPath: String) = resolve(UnresolvedLibrary(givenPath, null), false)
|
||||
|
||||
|
||||
private val File.klib
|
||||
get() = File(this, "klib")
|
||||
|
||||
// The libraries from the default root are linked automatically.
|
||||
val defaultRoots: List<File>
|
||||
get() = listOfNotNull(distHead, distPlatformHead).filter { it.exists }
|
||||
|
||||
override fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<KonanLibraryImpl> {
|
||||
|
||||
val result = mutableListOf<KonanLibraryImpl>()
|
||||
|
||||
if (!noStdLib) {
|
||||
result.add(resolve(UnresolvedLibrary(KONAN_STDLIB_NAME, null), true))
|
||||
}
|
||||
|
||||
if (!noDefaultLibs) {
|
||||
val defaultLibs = defaultRoots.flatMap { it.listFiles }
|
||||
.filterNot { it.name.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT) == KONAN_STDLIB_NAME }
|
||||
.map { UnresolvedLibrary(it.absolutePath, null) }
|
||||
.map {resolve(it, isDefaultLink = true) }
|
||||
result.addAll(defaultLibs)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal class KonanLibraryProperResolver(
|
||||
repositories: List<String>,
|
||||
override val target: KonanTarget,
|
||||
override val knownAbiVersions: List<KonanAbiVersion>?,
|
||||
override val knownCompilerVersions: List<KonanVersion>?,
|
||||
distributionKlib: String?,
|
||||
localKonanDir: String?,
|
||||
skipCurrentDir: Boolean,
|
||||
override val logger: Logger = ::dummyLogger
|
||||
): KonanLibrarySearchPathResolver(repositories, distributionKlib, localKonanDir, skipCurrentDir, logger), SearchPathResolverWithTarget {
|
||||
|
||||
override val distPlatformHead: File?
|
||||
get() = distributionKlib?.File()?.child("platform")?.child(target.visibleName)
|
||||
|
||||
override fun resolve(unresolved: UnresolvedLibrary, isDefaultLink: Boolean): KonanLibraryImpl {
|
||||
val givenPath = unresolved.path
|
||||
val fileSequence = resolutionSequence(givenPath)
|
||||
val matching = fileSequence.map { createKonanLibrary(it, target, isDefaultLink) as KonanLibraryImpl }
|
||||
.map { it.takeIf { libraryMatch(it, unresolved) } }
|
||||
.filterNotNull()
|
||||
|
||||
return matching.firstOrNull() ?: error("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun SearchPathResolverWithTarget.libraryMatch(candidate: KonanLibraryImpl, unresolved: UnresolvedLibrary): Boolean {
|
||||
val resolverTarget = this.target
|
||||
val candidatePath = candidate.libraryFile.absolutePath
|
||||
|
||||
if (resolverTarget != null && !candidate.targetList.contains(resolverTarget.visibleName)) {
|
||||
logger("skipping $candidatePath. The target doesn't match. Expected '$resolverTarget', found ${candidate.targetList}")
|
||||
return false
|
||||
}
|
||||
|
||||
if (knownCompilerVersions != null &&
|
||||
!knownCompilerVersions!!.contains(candidate.versions.compilerVersion)) {
|
||||
logger("skipping $candidatePath. The compiler versions don't match. Expected '${knownCompilerVersions}', found '${candidate.versions.compilerVersion}'")
|
||||
return false
|
||||
}
|
||||
|
||||
if (knownAbiVersions != null &&
|
||||
!knownAbiVersions!!.contains(candidate.versions.abiVersion)) {
|
||||
logger("skipping $candidatePath. The abi versions don't match. Expected '${knownAbiVersions}', found '${candidate.versions.abiVersion}'")
|
||||
return false
|
||||
}
|
||||
|
||||
if (candidate.versions.libraryVersion != unresolved.libraryVersion &&
|
||||
candidate.versions.libraryVersion != null &&
|
||||
unresolved.libraryVersion != null) {
|
||||
logger("skipping $candidatePath. The library versions don't match. Expected '${unresolved.libraryVersion}', found '${candidate.versions.libraryVersion}'")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
data class UnresolvedLibrary(
|
||||
val path: String,
|
||||
val libraryVersion: String?) {
|
||||
|
||||
fun substitutePath(newPath: String): UnresolvedLibrary {
|
||||
return UnresolvedLibrary(newPath, libraryVersion)
|
||||
}
|
||||
}
|
||||
+4
-10
@@ -9,9 +9,9 @@ import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions
|
||||
import org.jetbrains.kotlin.konan.util.substitute
|
||||
|
||||
internal class KonanLibraryImpl(
|
||||
|
||||
class KonanLibraryImpl(
|
||||
override val libraryFile: File,
|
||||
private val currentAbiVersion: Int,
|
||||
internal val target: KonanTarget?,
|
||||
override val isDefault: Boolean,
|
||||
private val metadataReader: MetadataReader
|
||||
@@ -32,14 +32,8 @@ internal class KonanLibraryImpl(
|
||||
properties
|
||||
}
|
||||
|
||||
override val abiVersion: String
|
||||
get() {
|
||||
val manifestAbiVersion = manifestProperties.getProperty(KLIB_PROPERTY_ABI_VERSION)
|
||||
check(currentAbiVersion.toString() == manifestAbiVersion) {
|
||||
"ABI version mismatch. Compiler expects: $currentAbiVersion, the library is $manifestAbiVersion"
|
||||
}
|
||||
return manifestAbiVersion
|
||||
}
|
||||
override val versions: KonanLibraryVersioning
|
||||
get() = manifestProperties.readKonanLibraryVersioning()
|
||||
|
||||
override val linkerOpts: List<String>
|
||||
get() = manifestProperties.propertyList(KLIB_PROPERTY_LINKED_OPTS, target!!.visibleName)
|
||||
@@ -0,0 +1,12 @@
|
||||
package org.jetbrains.kotlin.konan
|
||||
|
||||
fun String.parseKonanAbiVersion(): KonanAbiVersion {
|
||||
return KonanAbiVersion(this.toInt())
|
||||
}
|
||||
|
||||
data class KonanAbiVersion(val version: Int) {
|
||||
companion object {
|
||||
val CURRENT = KonanAbiVersion(1)
|
||||
}
|
||||
override fun toString() = "$version"
|
||||
}
|
||||
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.konan.file
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the whole file!
|
||||
|
||||
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
|
||||
import java.io.BufferedReader
|
||||
import java.io.InputStream
|
||||
import java.io.InputStreamReader
|
||||
@@ -38,7 +39,7 @@ data class File constructor(internal val javaPath: Path) {
|
||||
val absoluteFile: File
|
||||
get() = File(absolutePath)
|
||||
val name: String
|
||||
get() = javaPath.fileName.toString()
|
||||
get() = javaPath.fileName.toString().removeSuffixIfPresent("/") // https://bugs.java.com/bugdatabase/view_bug.do?bug_id=8153248
|
||||
val extension: String
|
||||
get() = name.substringAfterLast('.', "")
|
||||
val parent: String
|
||||
|
||||
@@ -1,138 +0,0 @@
|
||||
package org.jetbrains.kotlin.konan.library
|
||||
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.removeSuffixIfPresent
|
||||
import org.jetbrains.kotlin.konan.util.suffixIfNot
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove the constants below:
|
||||
const val KLIB_FILE_EXTENSION = "klib"
|
||||
const val KLIB_FILE_EXTENSION_WITH_DOT = ".$KLIB_FILE_EXTENSION"
|
||||
|
||||
const val KONAN_STDLIB_NAME = "stdlib"
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this interface!
|
||||
interface SearchPathResolver {
|
||||
val searchRoots: List<File>
|
||||
fun resolve(givenPath: String): File
|
||||
fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<File>
|
||||
}
|
||||
|
||||
// FIXME(ddol): KLIB-REFACTORING-CLEANUP: remove this interface!
|
||||
interface SearchPathResolverWithTarget: SearchPathResolver {
|
||||
val target: KonanTarget
|
||||
}
|
||||
|
||||
fun defaultResolver(
|
||||
repositories: List<String>,
|
||||
target: KonanTarget
|
||||
): SearchPathResolverWithTarget = defaultResolver(repositories, target, Distribution())
|
||||
|
||||
fun defaultResolver(
|
||||
repositories: List<String>,
|
||||
target: KonanTarget,
|
||||
distribution: Distribution,
|
||||
skipCurrentDir: Boolean = false
|
||||
): SearchPathResolverWithTarget = KonanLibrarySearchPathResolverWithTarget(
|
||||
repositories,
|
||||
target,
|
||||
distribution.klib,
|
||||
distribution.localKonanDir.absolutePath,
|
||||
skipCurrentDir)
|
||||
|
||||
fun noTargetResolver(
|
||||
repositories: List<String>,
|
||||
distributionKlib: String? = null,
|
||||
localKonanDir: String? = null,
|
||||
skipCurrentDir: Boolean = false
|
||||
): SearchPathResolver = KonanLibrarySearchPathResolver(repositories, distributionKlib, localKonanDir, skipCurrentDir)
|
||||
|
||||
|
||||
internal open class KonanLibrarySearchPathResolver(
|
||||
repositories: List<String>,
|
||||
val distributionKlib: String?,
|
||||
val localKonanDir: String?,
|
||||
val skipCurrentDir: Boolean
|
||||
) : SearchPathResolver {
|
||||
|
||||
val localHead: File?
|
||||
get() = localKonanDir?.File()?.klib
|
||||
|
||||
val distHead: File?
|
||||
get() = distributionKlib?.File()?.child("common")
|
||||
|
||||
open val distPlatformHead: File? = null
|
||||
|
||||
val currentDirHead: File?
|
||||
get() = if (!skipCurrentDir) File.userDir else null
|
||||
|
||||
private val repoRoots: List<File> by lazy { repositories.map { File(it) } }
|
||||
|
||||
// This is the place where we specify the order of library search.
|
||||
override val searchRoots: List<File> by lazy {
|
||||
(listOf(currentDirHead) + repoRoots + listOf(localHead, distHead, distPlatformHead)).filterNotNull()
|
||||
}
|
||||
|
||||
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_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
|
||||
}
|
||||
}
|
||||
|
||||
override fun resolve(givenPath: String): File {
|
||||
val given = File(givenPath)
|
||||
if (given.isAbsolute) {
|
||||
found(given)?.apply { return this }
|
||||
} else {
|
||||
searchRoots.forEach {
|
||||
found(File(it, givenPath))?.apply { return this }
|
||||
}
|
||||
}
|
||||
error("Could not find \"$givenPath\" in ${searchRoots.map { it.absolutePath }}.")
|
||||
}
|
||||
|
||||
private val File.klib
|
||||
get() = File(this, "klib")
|
||||
|
||||
// The libraries from the default root are linked automatically.
|
||||
val defaultRoots: List<File>
|
||||
get() = listOfNotNull(distHead, distPlatformHead).filter { it.exists }
|
||||
|
||||
override fun defaultLinks(noStdLib: Boolean, noDefaultLibs: Boolean): List<File> {
|
||||
|
||||
val result = mutableListOf<File>()
|
||||
|
||||
if (!noStdLib) {
|
||||
result.add(resolve(KONAN_STDLIB_NAME))
|
||||
}
|
||||
|
||||
if (!noDefaultLibs) {
|
||||
val defaultLibs = defaultRoots.flatMap { it.listFiles }
|
||||
.filterNot { it.name.removeSuffixIfPresent(KLIB_FILE_EXTENSION_WITH_DOT) == KONAN_STDLIB_NAME }
|
||||
.map { File(it.absolutePath) }
|
||||
result.addAll(defaultLibs)
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal class KonanLibrarySearchPathResolverWithTarget(
|
||||
repositories: List<String>,
|
||||
override val target: KonanTarget,
|
||||
distributionKlib: String?,
|
||||
localKonanDir: String?,
|
||||
skipCurrentDir: Boolean
|
||||
): KonanLibrarySearchPathResolver(repositories, distributionKlib, localKonanDir, skipCurrentDir), SearchPathResolverWithTarget {
|
||||
|
||||
override val distPlatformHead: File?
|
||||
get() = distributionKlib?.File()?.child("platform")?.child(target.visibleName)
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
typealias Logger = (String) -> Unit
|
||||
|
||||
interface WithLogger {
|
||||
val logger: Logger
|
||||
}
|
||||
|
||||
fun dummyLogger(message: String) {}
|
||||
|
||||
+1
-1
@@ -154,6 +154,6 @@ open class KonanLibrariesSpec(val task: KonanArtifactWithLibrariesTask, val proj
|
||||
files.flatMapTo(this) { it.files }
|
||||
addAll(artifactFiles)
|
||||
addAll(task.platformConfiguration.files)
|
||||
namedKlibs.mapTo(this) { project.file(resolver.resolve(it).absolutePath) }
|
||||
namedKlibs.mapTo(this) { project.file(resolver.resolve(it).libraryFile.absolutePath) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,10 @@
|
||||
*/
|
||||
package org.jetbrains.kotlin.cli.utilities
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.library.KLIB_CURRENT_ABI_VERSION
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.library.defaultResolver
|
||||
import org.jetbrains.kotlin.konan.library.includedHeaders
|
||||
import org.jetbrains.kotlin.konan.library.libraryResolver
|
||||
import org.jetbrains.kotlin.konan.library.packageFqName
|
||||
import org.jetbrains.kotlin.konan.target.PlatformManager
|
||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
||||
import org.jetbrains.kotlin.konan.library.*
|
||||
import org.jetbrains.kotlin.native.interop.gen.jvm.interop
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
@@ -57,14 +54,14 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String> {
|
||||
val manifest = File(buildDir, "manifest.properties")
|
||||
|
||||
val target = PlatformManager().targetManager(targetRequest).target
|
||||
val resolver = defaultResolver(repos, target).libraryResolver(KLIB_CURRENT_ABI_VERSION)
|
||||
val resolver = defaultResolver(repos, target).libraryResolver()
|
||||
val allLibraries = resolver.resolveWithDependencies(
|
||||
libraries, noStdLib = true, noDefaultLibs = noDefaultLibs
|
||||
libraries.toUnresolvedLibraries, noStdLib = true, noDefaultLibs = noDefaultLibs
|
||||
).getFullList()
|
||||
|
||||
val importArgs = allLibraries.flatMap { library ->
|
||||
// TODO: handle missing properties?
|
||||
library.packageFqName?.asString()?.let { packageFqName ->
|
||||
library.packageFqName?.let { packageFqName ->
|
||||
val headerIds = library.includedHeaders
|
||||
val arg = "$packageFqName:${headerIds.joinToString(";")}"
|
||||
listOf("-import", arg)
|
||||
|
||||
Reference in New Issue
Block a user