[Commonizer] Implement :native:kotlin-klib-commonizer:api with support for library commonization
- Implement new Gradle module ':native:kotlin-klib-commonizer' - Implement new NativeKlibCommonize task - Implement CommonizerTarget.identityString
This commit is contained in:
committed by
Space
parent
6d019d9544
commit
4500b6ce74
@@ -768,6 +768,7 @@ tasks {
|
|||||||
register("toolsTest") {
|
register("toolsTest") {
|
||||||
dependsOn(":tools:kotlinp:test")
|
dependsOn(":tools:kotlinp:test")
|
||||||
dependsOn(":native:kotlin-klib-commonizer:test")
|
dependsOn(":native:kotlin-klib-commonizer:test")
|
||||||
|
dependsOn(":native:kotlin-klib-commonizer-api:test")
|
||||||
}
|
}
|
||||||
|
|
||||||
register("examplesTest") {
|
register("examplesTest") {
|
||||||
|
|||||||
@@ -53,7 +53,8 @@ fun Task.dependsOnKotlinPluginInstall() {
|
|||||||
":kotlin-scripting-compiler-embeddable:install",
|
":kotlin-scripting-compiler-embeddable:install",
|
||||||
":kotlin-scripting-compiler-impl-embeddable:install",
|
":kotlin-scripting-compiler-impl-embeddable:install",
|
||||||
":kotlin-test-js-runner:install",
|
":kotlin-test-js-runner:install",
|
||||||
":native:kotlin-klib-commonizer-embeddable:install"
|
":native:kotlin-klib-commonizer-embeddable:install",
|
||||||
|
":native:kotlin-klib-commonizer-api:install"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -42,6 +42,7 @@ dependencies {
|
|||||||
|
|
||||||
implementation(kotlinStdlib())
|
implementation(kotlinStdlib())
|
||||||
implementation(project(":kotlin-util-klib"))
|
implementation(project(":kotlin-util-klib"))
|
||||||
|
implementation(project(":native:kotlin-klib-commonizer-api"))
|
||||||
compileOnly(project(":kotlin-reflect-api"))
|
compileOnly(project(":kotlin-reflect-api"))
|
||||||
compileOnly(project(":kotlin-android-extensions"))
|
compileOnly(project(":kotlin-android-extensions"))
|
||||||
compileOnly(project(":kotlin-build-common"))
|
compileOnly(project(":kotlin-build-common"))
|
||||||
|
|||||||
+21
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.compilerRunner
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.CliCommonizer
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates an instance of [CliCommonizer] that is backed by [KotlinNativeCommonizerToolRunner] to adhere to user defined settings
|
||||||
|
* when executing the commonizer (like jvm arguments, running in separate process, etc)
|
||||||
|
*/
|
||||||
|
internal fun GradleCliCommonizer(project: Project): CliCommonizer {
|
||||||
|
return CliCommonizer(CliCommonizer.Executor { arguments ->
|
||||||
|
KotlinNativeCommonizerToolRunner(project).run(arguments)
|
||||||
|
})
|
||||||
|
}
|
||||||
+1
-1
@@ -11,7 +11,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
internal class KotlinNativeKlibCommonizerToolRunner(project: Project) : KotlinToolRunner(project) {
|
internal class KotlinNativeCommonizerToolRunner(project: Project) : KotlinToolRunner(project) {
|
||||||
override val displayName get() = "Kotlin/Native KLIB commonizer"
|
override val displayName get() = "Kotlin/Native KLIB commonizer"
|
||||||
|
|
||||||
override val mainClass: String get() = "org.jetbrains.kotlin.descriptors.commonizer.cli.CommonizerCLI"
|
override val mainClass: String get() = "org.jetbrains.kotlin.descriptors.commonizer.cli.CommonizerCLI"
|
||||||
+2
-3
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.gradle.targets.native.internal
|
|||||||
import org.gradle.api.DefaultTask
|
import org.gradle.api.DefaultTask
|
||||||
import org.gradle.api.Project
|
import org.gradle.api.Project
|
||||||
import org.gradle.api.tasks.*
|
import org.gradle.api.tasks.*
|
||||||
import org.jetbrains.kotlin.compilerRunner.KotlinNativeKlibCommonizerToolRunner
|
import org.jetbrains.kotlin.compilerRunner.KotlinNativeCommonizerToolRunner
|
||||||
import org.jetbrains.kotlin.compilerRunner.konanHome
|
import org.jetbrains.kotlin.compilerRunner.konanHome
|
||||||
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
|
||||||
import org.jetbrains.kotlin.gradle.targets.native.internal.SuccessMarker.Companion.getSuccessMarker
|
import org.jetbrains.kotlin.gradle.targets.native.internal.SuccessMarker.Companion.getSuccessMarker
|
||||||
@@ -24,7 +24,6 @@ import java.nio.file.*
|
|||||||
import java.nio.file.attribute.*
|
import java.nio.file.attribute.*
|
||||||
import java.time.*
|
import java.time.*
|
||||||
import java.util.*
|
import java.util.*
|
||||||
import javax.inject.Inject
|
|
||||||
|
|
||||||
internal const val COMMONIZER_TASK_NAME = "runCommonizer"
|
internal const val COMMONIZER_TASK_NAME = "runCommonizer"
|
||||||
|
|
||||||
@@ -190,7 +189,7 @@ internal fun Project.createTempNativeDistributionCommonizerOutputDirectory(targe
|
|||||||
fun callCommonizerCLI(project: Project, commandLineArguments: List<String>) {
|
fun callCommonizerCLI(project: Project, commandLineArguments: List<String>) {
|
||||||
if (commandLineArguments.isEmpty()) return
|
if (commandLineArguments.isEmpty()) return
|
||||||
|
|
||||||
KotlinNativeKlibCommonizerToolRunner(project).run(commandLineArguments)
|
KotlinNativeCommonizerToolRunner(project).run(commandLineArguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun renameDirectory(source: File, destination: File) {
|
private fun renameDirectory(source: File, destination: File) {
|
||||||
|
|||||||
@@ -0,0 +1,44 @@
|
|||||||
|
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
|
||||||
|
|
||||||
|
plugins {
|
||||||
|
kotlin("jvm")
|
||||||
|
id("jps-compatible")
|
||||||
|
}
|
||||||
|
|
||||||
|
kotlin {
|
||||||
|
explicitApi()
|
||||||
|
}
|
||||||
|
|
||||||
|
description = "Kotlin KLIB Library Commonizer API"
|
||||||
|
publish()
|
||||||
|
|
||||||
|
dependencies {
|
||||||
|
implementation(kotlinStdlib())
|
||||||
|
implementation(project(":native:kotlin-native-utils"))
|
||||||
|
testImplementation(project(":kotlin-test::kotlin-test-junit"))
|
||||||
|
testImplementation(commonDep("junit:junit"))
|
||||||
|
testImplementation(projectTests(":compiler:tests-common"))
|
||||||
|
testRuntimeOnly(project(":native:kotlin-klib-commonizer"))
|
||||||
|
}
|
||||||
|
|
||||||
|
sourceSets {
|
||||||
|
"main" { projectDefault() }
|
||||||
|
"test" { projectDefault() }
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks.register("downloadNativeCompiler") {
|
||||||
|
doFirst {
|
||||||
|
NativeCompilerDownloader(project).downloadIfNeeded()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
projectTest(parallel = false) {
|
||||||
|
dependsOn(":dist")
|
||||||
|
dependsOn("downloadNativeCompiler")
|
||||||
|
workingDir = projectDir
|
||||||
|
environment("KONAN_HOME", NativeCompilerDownloader(project).compilerDirectory.absolutePath)
|
||||||
|
}
|
||||||
|
|
||||||
|
runtimeJar()
|
||||||
|
sourcesJar()
|
||||||
|
javadocJar()
|
||||||
+61
@@ -0,0 +1,61 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.net.URLClassLoader
|
||||||
|
import kotlin.jvm.Throws
|
||||||
|
|
||||||
|
public fun CliCommonizer(classpath: Iterable<File>): CliCommonizer {
|
||||||
|
return CliCommonizer(URLClassLoader(classpath.map { it.absoluteFile.toURI().toURL() }.toTypedArray()))
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun CliCommonizer(classLoader: ClassLoader): CliCommonizer {
|
||||||
|
return CliCommonizer(CommonizerClassLoaderExecutor(classLoader))
|
||||||
|
}
|
||||||
|
|
||||||
|
public class CliCommonizer(private val executor: Executor) : Commonizer {
|
||||||
|
|
||||||
|
public fun interface Executor {
|
||||||
|
public operator fun invoke(arguments: List<String>)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun commonizeLibraries(
|
||||||
|
konanHome: File,
|
||||||
|
inputLibraries: Set<File>,
|
||||||
|
dependencyLibraries: Set<File>,
|
||||||
|
outputCommonizerTarget: SharedCommonizerTarget,
|
||||||
|
outputDirectory: File
|
||||||
|
) {
|
||||||
|
val arguments = mutableListOf<String>().apply {
|
||||||
|
add("native-klib-commonize")
|
||||||
|
add("-distribution-path"); add(konanHome.absolutePath)
|
||||||
|
add("-input-libraries"); add(inputLibraries.joinToString(";") { it.absolutePath })
|
||||||
|
add("-dependency-libraries"); add(dependencyLibraries.joinToString(";") { it.absolutePath })
|
||||||
|
add("-output-commonizer-target"); add(outputCommonizerTarget.identityString)
|
||||||
|
add("-output-path"); add(outputDirectory.absolutePath)
|
||||||
|
}
|
||||||
|
executor(arguments)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CommonizerClassLoaderExecutor(private val commonizerClassLoader: ClassLoader) : CliCommonizer.Executor {
|
||||||
|
companion object {
|
||||||
|
private const val commonizerMainClass = "org.jetbrains.kotlin.descriptors.commonizer.cli.CommonizerCLI"
|
||||||
|
private const val commonizerMainFunction = "main"
|
||||||
|
}
|
||||||
|
|
||||||
|
@Throws(Throwable::class)
|
||||||
|
override fun invoke(arguments: List<String>) {
|
||||||
|
val commonizerMainClass = commonizerClassLoader.loadClass(commonizerMainClass)
|
||||||
|
val commonizerMainMethod = commonizerMainClass.methods.singleOrNull { it.name == commonizerMainFunction }
|
||||||
|
?: throw IllegalArgumentException(
|
||||||
|
"Missing or conflicting $commonizerMainFunction function in " +
|
||||||
|
"Class ${commonizerMainClass.name} from ClassLoader $commonizerClassLoader"
|
||||||
|
)
|
||||||
|
commonizerMainMethod.invoke(null, arguments.toTypedArray())
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
import java.io.Serializable
|
||||||
|
import kotlin.jvm.Throws
|
||||||
|
|
||||||
|
public interface Commonizer : Serializable {
|
||||||
|
@Throws(Throwable::class)
|
||||||
|
public fun commonizeLibraries(
|
||||||
|
konanHome: File,
|
||||||
|
inputLibraries: Set<File>,
|
||||||
|
dependencyLibraries: Set<File>,
|
||||||
|
outputCommonizerTarget: SharedCommonizerTarget,
|
||||||
|
outputDirectory: File
|
||||||
|
)
|
||||||
|
}
|
||||||
+100
@@ -0,0 +1,100 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
import java.io.Serializable
|
||||||
|
|
||||||
|
// N.B. TargetPlatform/SimplePlatform are non exhaustive enough to address both target platforms such as
|
||||||
|
// JVM, JS and concrete Kotlin/Native targets, e.g. macos_x64, ios_x64, linux_x64.
|
||||||
|
public sealed class CommonizerTarget : Serializable {
|
||||||
|
final override fun toString(): String = identityString
|
||||||
|
}
|
||||||
|
|
||||||
|
public data class LeafCommonizerTarget public constructor(val name: String) : CommonizerTarget() {
|
||||||
|
public constructor(konanTarget: KonanTarget) : this(konanTarget.name)
|
||||||
|
|
||||||
|
public val konanTargetOrNull: KonanTarget? = KonanTarget.predefinedTargets[name]
|
||||||
|
|
||||||
|
public val konanTarget: KonanTarget get() = konanTargetOrNull ?: error("Unknown KonanTarget: $name")
|
||||||
|
}
|
||||||
|
|
||||||
|
public data class SharedCommonizerTarget(val targets: Set<CommonizerTarget>) : CommonizerTarget() {
|
||||||
|
public constructor(vararg targets: CommonizerTarget) : this(targets.toSet())
|
||||||
|
public constructor(vararg targets: KonanTarget) : this(targets.toSet())
|
||||||
|
public constructor(targets: Iterable<KonanTarget>) : this(targets.map(::LeafCommonizerTarget).toSet())
|
||||||
|
|
||||||
|
init {
|
||||||
|
require(targets.isNotEmpty())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun CommonizerTarget(konanTargets: Iterable<KonanTarget>): CommonizerTarget {
|
||||||
|
val konanTargetsSet = konanTargets.toSet()
|
||||||
|
require(konanTargetsSet.isNotEmpty()) { "Empty set of of konanTargets" }
|
||||||
|
val leafTargets = konanTargetsSet.map(::LeafCommonizerTarget)
|
||||||
|
return leafTargets.singleOrNull() ?: SharedCommonizerTarget(leafTargets.toSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun CommonizerTarget(konanTarget: KonanTarget): LeafCommonizerTarget {
|
||||||
|
return LeafCommonizerTarget(konanTarget)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun CommonizerTarget(konanTarget: KonanTarget, vararg konanTargets: KonanTarget): SharedCommonizerTarget {
|
||||||
|
val targets = ArrayList<KonanTarget>(konanTargets.size + 1).apply {
|
||||||
|
add(konanTarget)
|
||||||
|
addAll(konanTargets)
|
||||||
|
}
|
||||||
|
return SharedCommonizerTarget(targets.map(::LeafCommonizerTarget).toSet())
|
||||||
|
}
|
||||||
|
|
||||||
|
public val CommonizerTarget.identityString: String
|
||||||
|
get() = when (this) {
|
||||||
|
is LeafCommonizerTarget -> name
|
||||||
|
is SharedCommonizerTarget -> identityString
|
||||||
|
}
|
||||||
|
|
||||||
|
private val SharedCommonizerTarget.identityString: String
|
||||||
|
get() {
|
||||||
|
val segments = targets.map(CommonizerTarget::identityString).sorted()
|
||||||
|
return segments.joinToString(
|
||||||
|
separator = ", ", prefix = "(", postfix = ")"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
public val CommonizerTarget.prettyName: String
|
||||||
|
get() = when (this) {
|
||||||
|
is LeafCommonizerTarget -> "[$name]"
|
||||||
|
is SharedCommonizerTarget -> prettyName(null)
|
||||||
|
}
|
||||||
|
|
||||||
|
public fun SharedCommonizerTarget.prettyName(highlightedChild: CommonizerTarget?): String {
|
||||||
|
return targets
|
||||||
|
.sortedWith(compareBy<CommonizerTarget> { it.level }.thenBy { it.identityString }).joinToString(", ", "[", "]") { child ->
|
||||||
|
when (child) {
|
||||||
|
is LeafCommonizerTarget -> child.name
|
||||||
|
is SharedCommonizerTarget -> child.prettyName(highlightedChild)
|
||||||
|
} + if (child == highlightedChild) "(*)" else ""
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val CommonizerTarget.konanTargets: Set<KonanTarget>
|
||||||
|
get() {
|
||||||
|
return when (this) {
|
||||||
|
is LeafCommonizerTarget -> setOf(konanTarget)
|
||||||
|
is SharedCommonizerTarget -> targets.flatMap { it.konanTargets }.toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public val CommonizerTarget.level: Int
|
||||||
|
get() {
|
||||||
|
return when (this) {
|
||||||
|
is LeafCommonizerTarget -> return 0
|
||||||
|
is SharedCommonizerTarget -> targets.maxOf { it.level } + 1
|
||||||
|
}
|
||||||
|
}
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
|
||||||
|
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
|
||||||
|
public fun interface CommonizerOutputLayout {
|
||||||
|
public fun getTargetDirectory(root: File, target: CommonizerTarget): File
|
||||||
|
}
|
||||||
|
|
||||||
|
public object NativeDistributionCommonizerOutputLayout : CommonizerOutputLayout {
|
||||||
|
override fun getTargetDirectory(root: File, target: CommonizerTarget): File {
|
||||||
|
return when (target) {
|
||||||
|
is LeafCommonizerTarget -> root.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.name)
|
||||||
|
is SharedCommonizerTarget -> root.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public object HierarchicalCommonizerOutputLayout : CommonizerOutputLayout {
|
||||||
|
override fun getTargetDirectory(root: File, target: CommonizerTarget): File {
|
||||||
|
return root.resolve(target.identityString)
|
||||||
|
}
|
||||||
|
}
|
||||||
+196
@@ -0,0 +1,196 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.IdentityStringSyntaxNode.LeafTargetSyntaxNode
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.IdentityStringSyntaxNode.SharedTargetSyntaxNode
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.IdentityStringToken.*
|
||||||
|
|
||||||
|
public fun parseCommonizerTarget(identityString: String): CommonizerTarget {
|
||||||
|
try {
|
||||||
|
val tokens = tokenizeIdentityString(identityString)
|
||||||
|
val syntaxTree = parser(tokens) ?: error("Failed building syntax tree. $identityString")
|
||||||
|
check(syntaxTree.remaining.isEmpty()) { "Failed building syntax tree. Unexpected remaining tokens ${syntaxTree.remaining}" }
|
||||||
|
return buildCommonizerTarget(syntaxTree.value)
|
||||||
|
} catch (e: Throwable) {
|
||||||
|
throw IllegalArgumentException("Failed parsing CommonizerTarget from \"$identityString\"", e)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//region Tokens
|
||||||
|
|
||||||
|
private fun tokenizeIdentityString(identityString: String): List<IdentityStringToken> {
|
||||||
|
var remainingString = identityString
|
||||||
|
val tokenizer = sharedTargetStartTokenizer + sharedTargetEndTokenizer + separatorTokenizer + wordTokenizer
|
||||||
|
return mutableListOf<IdentityStringToken>().apply {
|
||||||
|
while (remainingString.isNotEmpty()) {
|
||||||
|
val generatedToken = tokenizer.nextToken(remainingString)
|
||||||
|
?: error("Unexpected token at $remainingString")
|
||||||
|
|
||||||
|
remainingString = generatedToken.remaining
|
||||||
|
add(generatedToken.token)
|
||||||
|
}
|
||||||
|
}.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class IdentityStringToken {
|
||||||
|
data class Word(val value: String) : IdentityStringToken()
|
||||||
|
object Separator : IdentityStringToken()
|
||||||
|
object SharedTargetStart : IdentityStringToken()
|
||||||
|
object SharedTargetEnd : IdentityStringToken()
|
||||||
|
|
||||||
|
final override fun toString(): String {
|
||||||
|
return when (this) {
|
||||||
|
is Word -> value
|
||||||
|
is Separator -> ", "
|
||||||
|
is SharedTargetStart -> "["
|
||||||
|
is SharedTargetEnd -> "]"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class GeneratedToken(val token: IdentityStringToken, val remaining: String)
|
||||||
|
|
||||||
|
private interface IdentityStringTokenizer {
|
||||||
|
fun nextToken(value: String): GeneratedToken?
|
||||||
|
}
|
||||||
|
|
||||||
|
private operator fun IdentityStringTokenizer.plus(other: IdentityStringTokenizer): IdentityStringTokenizer {
|
||||||
|
return CompositeIdentityStringTokenizer(this, other)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class CompositeIdentityStringTokenizer(
|
||||||
|
val first: IdentityStringTokenizer,
|
||||||
|
val second: IdentityStringTokenizer
|
||||||
|
) : IdentityStringTokenizer {
|
||||||
|
override fun nextToken(value: String): GeneratedToken? {
|
||||||
|
return first.nextToken(value) ?: second.nextToken(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class RegexIdentityStringTokenizer(
|
||||||
|
val regex: Regex,
|
||||||
|
val token: (String) -> IdentityStringToken
|
||||||
|
) : IdentityStringTokenizer {
|
||||||
|
override fun nextToken(value: String): GeneratedToken? {
|
||||||
|
val firstMatchResult = regex.findAll(value, 0).firstOrNull() ?: return null
|
||||||
|
val range = firstMatchResult.range
|
||||||
|
if (range.first != 0) return null
|
||||||
|
return GeneratedToken(token(firstMatchResult.value), value.drop(firstMatchResult.value.length))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private val sharedTargetStartTokenizer =
|
||||||
|
RegexIdentityStringTokenizer(Regex.fromLiteral("(")) { SharedTargetStart }
|
||||||
|
|
||||||
|
private val sharedTargetEndTokenizer =
|
||||||
|
RegexIdentityStringTokenizer(Regex.fromLiteral(")")) { SharedTargetEnd }
|
||||||
|
|
||||||
|
private val separatorTokenizer =
|
||||||
|
RegexIdentityStringTokenizer(Regex("""\s*,\s*""")) { Separator }
|
||||||
|
|
||||||
|
private val wordTokenizer =
|
||||||
|
RegexIdentityStringTokenizer(Regex("\\w+"), IdentityStringToken::Word)
|
||||||
|
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
//region Syntax Tree
|
||||||
|
|
||||||
|
private val parser = anyOf(SharedTargetParser, LeafTargetParser)
|
||||||
|
|
||||||
|
private data class ParserOutput<out T : Any>(val value: T, val remaining: List<IdentityStringToken>)
|
||||||
|
|
||||||
|
private interface Parser<out T : Any> {
|
||||||
|
operator fun invoke(tokens: List<IdentityStringToken>): ParserOutput<T>?
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun <T : Any> anyOf(vararg parser: Parser<T>): Parser<T> {
|
||||||
|
return AnyOfParser(parser.toList())
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class AnyOfParser<T : Any>(val parsers: List<Parser<T>>) : Parser<T> {
|
||||||
|
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<T>? {
|
||||||
|
return parsers.mapNotNull { parser -> parser(tokens) }.firstOrNull()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T : Any> Parser<T>.oneOrMore(): Parser<List<T>> {
|
||||||
|
return OneOrMoreParser(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class OneOrMoreParser<T : Any>(val parser: Parser<T>) : Parser<List<T>> {
|
||||||
|
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<List<T>>? {
|
||||||
|
val outputs = mutableListOf<T>()
|
||||||
|
var remainingTokens = tokens
|
||||||
|
while (true) {
|
||||||
|
val output = parser(remainingTokens) ?: break
|
||||||
|
if (output.remaining == remainingTokens) break
|
||||||
|
outputs.add(output.value)
|
||||||
|
remainingTokens = output.remaining
|
||||||
|
}
|
||||||
|
if (outputs.isEmpty()) {
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
return ParserOutput(outputs.toList(), remainingTokens)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T : Any> Parser<T>.ignore(token: IdentityStringToken): Parser<T> {
|
||||||
|
return IgnoreTokensParser(this, token)
|
||||||
|
}
|
||||||
|
|
||||||
|
private data class IgnoreTokensParser<T : Any>(val parser: Parser<T>, val ignoredToken: IdentityStringToken) : Parser<T> {
|
||||||
|
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<T>? {
|
||||||
|
return parser(
|
||||||
|
if (tokens.firstOrNull() == ignoredToken) tokens.drop(1) else tokens
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object LeafTargetParser : Parser<LeafTargetSyntaxNode> {
|
||||||
|
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<LeafTargetSyntaxNode>? {
|
||||||
|
val nextToken = tokens.firstOrNull() as? Word ?: return null
|
||||||
|
return ParserOutput(LeafTargetSyntaxNode(nextToken), tokens.drop(1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object SharedTargetParser : Parser<SharedTargetSyntaxNode> {
|
||||||
|
override fun invoke(tokens: List<IdentityStringToken>): ParserOutput<SharedTargetSyntaxNode>? {
|
||||||
|
if (tokens.firstOrNull() !is SharedTargetStart) return null
|
||||||
|
|
||||||
|
val innerParser = anyOf(LeafTargetParser, SharedTargetParser).ignore(Separator).oneOrMore()
|
||||||
|
val innerParserOutput = innerParser(tokens.drop(1)) ?: return null
|
||||||
|
|
||||||
|
val closingToken = innerParserOutput.remaining.firstOrNull()
|
||||||
|
if (closingToken != SharedTargetEnd) {
|
||||||
|
error("Missing ']' at ${tokens.joinToString("")}")
|
||||||
|
}
|
||||||
|
|
||||||
|
return ParserOutput(SharedTargetSyntaxNode(innerParserOutput.value), innerParserOutput.remaining.drop(1))
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
private sealed class IdentityStringSyntaxNode {
|
||||||
|
data class LeafTargetSyntaxNode(val token: Word) : IdentityStringSyntaxNode()
|
||||||
|
data class SharedTargetSyntaxNode(val children: List<IdentityStringSyntaxNode>) : IdentityStringSyntaxNode()
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion Tree
|
||||||
|
|
||||||
|
//region Build CommonizerTarget
|
||||||
|
|
||||||
|
private fun buildCommonizerTarget(node: IdentityStringSyntaxNode): CommonizerTarget {
|
||||||
|
return when (node) {
|
||||||
|
is LeafTargetSyntaxNode -> LeafCommonizerTarget(node.token.value)
|
||||||
|
is SharedTargetSyntaxNode -> SharedCommonizerTarget(
|
||||||
|
node.children.map { child -> buildCommonizerTarget(child) }.toSet()
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//endregion
|
||||||
+30
@@ -0,0 +1,30 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.konanHome
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import kotlin.test.Test
|
||||||
|
|
||||||
|
class CliCommonizerTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val temporaryOutputDirectory = TemporaryFolder()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun invokeCliWithEmptyArguments() {
|
||||||
|
val commonizer = CliCommonizer(this::class.java.classLoader)
|
||||||
|
commonizer.commonizeLibraries(
|
||||||
|
konanHome = konanHome,
|
||||||
|
inputLibraries = emptySet(),
|
||||||
|
dependencyLibraries = emptySet(),
|
||||||
|
outputCommonizerTarget = CommonizerTarget(KonanTarget.LINUX_X64, KonanTarget.MACOS_X64),
|
||||||
|
outputDirectory = temporaryOutputDirectory.root
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.konanHome
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget.LINUX_ARM64
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget.LINUX_X64
|
||||||
|
import org.junit.Rule
|
||||||
|
import org.junit.rules.TemporaryFolder
|
||||||
|
import java.io.File
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertTrue
|
||||||
|
import kotlin.test.fail
|
||||||
|
|
||||||
|
class CommonizeLibcurlTest {
|
||||||
|
|
||||||
|
@get:Rule
|
||||||
|
val temporaryOutputDirectory = TemporaryFolder()
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun commonizeSuccessfully() {
|
||||||
|
val libraries = File("testData/libcurl").walkTopDown().filter { it.isFile && it.extension == "klib" }.toSet()
|
||||||
|
val commonizer = CliCommonizer(this::class.java.classLoader)
|
||||||
|
|
||||||
|
commonizer.commonizeLibraries(
|
||||||
|
konanHome = konanHome,
|
||||||
|
inputLibraries = libraries,
|
||||||
|
dependencyLibraries = emptySet(),
|
||||||
|
outputCommonizerTarget = CommonizerTarget(LINUX_ARM64, LINUX_X64),
|
||||||
|
outputDirectory = temporaryOutputDirectory.root
|
||||||
|
)
|
||||||
|
|
||||||
|
val x64OutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_X64).identityString)
|
||||||
|
val arm64OutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_ARM64).identityString)
|
||||||
|
val commonOutputDirectory = temporaryOutputDirectory.root.resolve(CommonizerTarget(LINUX_X64, LINUX_ARM64).identityString)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
x64OutputDirectory.exists(),
|
||||||
|
"Missing output directory for x64 target"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
arm64OutputDirectory.exists(),
|
||||||
|
"Missing output directory for arm64 target"
|
||||||
|
)
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
commonOutputDirectory.exists(),
|
||||||
|
"Missing output directory for commonized x64&arm64 target"
|
||||||
|
)
|
||||||
|
|
||||||
|
fun assertContainsKnmFiles(file: File) {
|
||||||
|
assertTrue(
|
||||||
|
file.walkTopDown().any { it.extension == "knm" },
|
||||||
|
"Expected directory ${file.name} to contain at least one knm file"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertContainsKnmFiles(x64OutputDirectory)
|
||||||
|
assertContainsKnmFiles(arm64OutputDirectory)
|
||||||
|
assertContainsKnmFiles(commonOutputDirectory)
|
||||||
|
|
||||||
|
fun assertContainsManifestWithContent(directory: File, content: String) {
|
||||||
|
val manifest = directory.walkTopDown().firstOrNull { it.name == "manifest" }
|
||||||
|
?: fail("${directory.name} does not contain any manifest")
|
||||||
|
|
||||||
|
assertTrue(
|
||||||
|
content in manifest.readText(),
|
||||||
|
"Expected manifest in ${directory.name} to contain $content\n${manifest.readText()}"
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
assertContainsManifestWithContent(x64OutputDirectory, "native_targets=linux_x64")
|
||||||
|
assertContainsManifestWithContent(arm64OutputDirectory, "native_targets=linux_arm64")
|
||||||
|
assertContainsManifestWithContent(commonOutputDirectory, "native_targets=linux_x64 linux_arm64")
|
||||||
|
}
|
||||||
|
}
|
||||||
+137
@@ -0,0 +1,137 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||||
|
import kotlin.test.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class CommonizerTargetIdentityStringTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun leafTargets() {
|
||||||
|
KonanTarget.predefinedTargets.values.forEach { konanTarget ->
|
||||||
|
assertEquals(konanTarget.name, CommonizerTarget(konanTarget).identityString)
|
||||||
|
assertEquals(CommonizerTarget(konanTarget), parseCommonizerTarget(CommonizerTarget(konanTarget).identityString))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `simple shared targets are invariant under konanTarget order`() {
|
||||||
|
val macosFirst = CommonizerTarget(MACOS_X64, LINUX_X64)
|
||||||
|
val linuxFirst = CommonizerTarget(LINUX_X64, MACOS_X64)
|
||||||
|
|
||||||
|
assertEquals(macosFirst, linuxFirst)
|
||||||
|
assertEquals(macosFirst.identityString, linuxFirst.identityString)
|
||||||
|
assertEquals(linuxFirst, parseCommonizerTarget(linuxFirst.identityString))
|
||||||
|
assertEquals(macosFirst, parseCommonizerTarget(macosFirst.identityString))
|
||||||
|
assertEquals(macosFirst, parseCommonizerTarget(linuxFirst.identityString))
|
||||||
|
assertEquals(linuxFirst, parseCommonizerTarget(macosFirst.identityString))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `hierarchical commonizer targets`() {
|
||||||
|
val hierarchy = SharedCommonizerTarget(
|
||||||
|
CommonizerTarget(LINUX_X64, MACOS_X64),
|
||||||
|
CommonizerTarget(IOS_ARM64, IOS_X64)
|
||||||
|
)
|
||||||
|
assertEquals(setOf(LINUX_X64, MACOS_X64, IOS_ARM64, IOS_X64), hierarchy.konanTargets)
|
||||||
|
assertEquals(hierarchy, parseCommonizerTarget(hierarchy.identityString))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `multilevel hierarchical commonizer targets`() {
|
||||||
|
val hierarchy = SharedCommonizerTarget(
|
||||||
|
SharedCommonizerTarget(
|
||||||
|
SharedCommonizerTarget(
|
||||||
|
SharedCommonizerTarget(
|
||||||
|
CommonizerTarget(LINUX_X64, MACOS_X64),
|
||||||
|
CommonizerTarget(IOS_X64, IOS_ARM64)
|
||||||
|
),
|
||||||
|
CommonizerTarget(LINUX_ARM32_HFP)
|
||||||
|
),
|
||||||
|
CommonizerTarget(LINUX_MIPSEL32)
|
||||||
|
),
|
||||||
|
CommonizerTarget(WATCHOS_X86, WATCHOS_ARM64)
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(hierarchy, parseCommonizerTarget(hierarchy.identityString))
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `parsing CommonizerTarget`() {
|
||||||
|
val target = parseCommonizerTarget("(x, (x, y, (a, b), (b, c)))")
|
||||||
|
assertEquals(
|
||||||
|
SharedCommonizerTarget(
|
||||||
|
LeafCommonizerTarget("x"),
|
||||||
|
SharedCommonizerTarget(
|
||||||
|
LeafCommonizerTarget("x"),
|
||||||
|
LeafCommonizerTarget("y"),
|
||||||
|
SharedCommonizerTarget(
|
||||||
|
LeafCommonizerTarget("a"),
|
||||||
|
LeafCommonizerTarget("b"),
|
||||||
|
),
|
||||||
|
SharedCommonizerTarget(
|
||||||
|
LeafCommonizerTarget("b"),
|
||||||
|
LeafCommonizerTarget("c")
|
||||||
|
)
|
||||||
|
)
|
||||||
|
),
|
||||||
|
target
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 1`() {
|
||||||
|
parseCommonizerTarget("xxx,")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 2`() {
|
||||||
|
parseCommonizerTarget("")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 3`() {
|
||||||
|
parseCommonizerTarget("()")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 4`() {
|
||||||
|
parseCommonizerTarget("(xxx")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 5`() {
|
||||||
|
parseCommonizerTarget("xxx)")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 6`() {
|
||||||
|
parseCommonizerTarget("(xxx")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 7`() {
|
||||||
|
parseCommonizerTarget("(xxx yyy)")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 8`() {
|
||||||
|
parseCommonizerTarget(" ")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 9`() {
|
||||||
|
parseCommonizerTarget("xxx?")
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun `fail parsing CommonizerTarget 10`() {
|
||||||
|
parseCommonizerTarget("(x, (x, y)")
|
||||||
|
}
|
||||||
|
}
|
||||||
+88
@@ -0,0 +1,88 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.junit.Test
|
||||||
|
import kotlin.test.assertEquals
|
||||||
|
|
||||||
|
class CommonizerTargetPrettyNameTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun leafTargetNames() {
|
||||||
|
listOf(
|
||||||
|
Triple("foo", "[foo]", FOO),
|
||||||
|
Triple("bar", "[bar]", BAR),
|
||||||
|
Triple("baz_123", "[baz_123]", BAZ),
|
||||||
|
).forEach { (name, prettyName, target: LeafCommonizerTarget) ->
|
||||||
|
assertEquals(name, target.name)
|
||||||
|
assertEquals(prettyName, target.prettyName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun sharedTargetNames() {
|
||||||
|
listOf(
|
||||||
|
"[foo]" to SharedTarget(FOO),
|
||||||
|
"[bar, foo]" to SharedTarget(FOO, BAR),
|
||||||
|
"[bar, baz_123, foo]" to SharedTarget(FOO, BAR, BAZ),
|
||||||
|
"[bar, baz_123, foo, [bar, foo]]" to SharedTarget(FOO, BAR, BAZ, SharedTarget(FOO, BAR))
|
||||||
|
).forEach { (prettyName, target: SharedCommonizerTarget) ->
|
||||||
|
assertEquals(prettyName, target.prettyName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun prettyCommonizedName() {
|
||||||
|
val sharedTarget = SharedTarget(FOO, BAR, BAZ)
|
||||||
|
listOf(
|
||||||
|
"[bar, baz_123, foo(*)]" to FOO,
|
||||||
|
"[bar(*), baz_123, foo]" to BAR,
|
||||||
|
"[bar, baz_123(*), foo]" to BAZ,
|
||||||
|
"[bar, baz_123, foo]" to sharedTarget,
|
||||||
|
).forEach { (prettyCommonizerName, target: CommonizerTarget) ->
|
||||||
|
assertEquals(prettyCommonizerName, sharedTarget.prettyName(target))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun prettyNestedName() {
|
||||||
|
val target = parseCommonizerTarget("(a, b, (c, (d, e)))") as SharedCommonizerTarget
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[a, b, [c, [d, e]]]", target.prettyName
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[a, b, [c, [d, e(*)]]]", target.prettyName(LeafCommonizerTarget("e"))
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[a, b, [c, [d, e](*)]]", target.prettyName(parseCommonizerTarget("(d, e)"))
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[a, b, [c, [d, e]](*)]", target.prettyName(parseCommonizerTarget("(c, (d, e))"))
|
||||||
|
)
|
||||||
|
|
||||||
|
assertEquals(
|
||||||
|
"[a, b(*), [c, [d, e]]]", target.prettyName(LeafCommonizerTarget("b"))
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = IllegalArgumentException::class)
|
||||||
|
fun sharedTargetNoInnerTargets() {
|
||||||
|
SharedCommonizerTarget(emptySet<CommonizerTarget>())
|
||||||
|
}
|
||||||
|
|
||||||
|
private companion object {
|
||||||
|
val FOO = LeafCommonizerTarget("foo")
|
||||||
|
val BAR = LeafCommonizerTarget("bar")
|
||||||
|
val BAZ = LeafCommonizerTarget("baz_123")
|
||||||
|
|
||||||
|
@Suppress("TestFunctionName")
|
||||||
|
fun SharedTarget(vararg targets: CommonizerTarget) = SharedCommonizerTarget(linkedSetOf(*targets))
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer.utils
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal val konanHome: File
|
||||||
|
get() {
|
||||||
|
val konanHomePath = System.getenv("KONAN_HOME")?.toString() ?: error("Missing KONAN_HOME environment variable")
|
||||||
|
return File(konanHomePath)
|
||||||
|
}
|
||||||
Binary file not shown.
Binary file not shown.
@@ -16,11 +16,13 @@ configurations {
|
|||||||
dependencies {
|
dependencies {
|
||||||
embedded(project(":kotlinx-metadata-klib")) { isTransitive = false }
|
embedded(project(":kotlinx-metadata-klib")) { isTransitive = false }
|
||||||
embedded(project(":kotlinx-metadata")) { isTransitive = false }
|
embedded(project(":kotlinx-metadata")) { isTransitive = false }
|
||||||
|
embedded(project(":native:kotlin-klib-commonizer-api")) { isTransitive = false }
|
||||||
|
|
||||||
// N.B. The order of "kotlinx-metadata*" dependencies makes sense for runtime classpath
|
// N.B. The order of "kotlinx-metadata*" dependencies makes sense for runtime classpath
|
||||||
// of the "runCommonizer" task. Please, don't mix them up.
|
// of the "runCommonizer" task. Please, don't mix them up.
|
||||||
compileOnly(project(":kotlinx-metadata-klib")) { isTransitive = false }
|
compileOnly(project(":kotlinx-metadata-klib")) { isTransitive = false }
|
||||||
compileOnly(project(":kotlinx-metadata")) { isTransitive = false }
|
compileOnly(project(":kotlinx-metadata")) { isTransitive = false }
|
||||||
|
compileOnly(project(":native:kotlin-klib-commonizer-api")) { isTransitive = false }
|
||||||
compileOnly(project(":compiler:cli-common"))
|
compileOnly(project(":compiler:cli-common"))
|
||||||
compileOnly(project(":compiler:ir.serialization.common"))
|
compileOnly(project(":compiler:ir.serialization.common"))
|
||||||
compileOnly(project(":compiler:frontend"))
|
compileOnly(project(":compiler:frontend"))
|
||||||
@@ -38,6 +40,7 @@ dependencies {
|
|||||||
testImplementation(projectTests(":compiler:tests-common"))
|
testImplementation(projectTests(":compiler:tests-common"))
|
||||||
testImplementation(project(":kotlinx-metadata-klib")) { isTransitive = false }
|
testImplementation(project(":kotlinx-metadata-klib")) { isTransitive = false }
|
||||||
testImplementation(project(":kotlinx-metadata")) { isTransitive = false }
|
testImplementation(project(":kotlinx-metadata")) { isTransitive = false }
|
||||||
|
testImplementation(project(":native:kotlin-klib-commonizer-api"))
|
||||||
}
|
}
|
||||||
|
|
||||||
val runCommonizer by tasks.registering(JavaExec::class) {
|
val runCommonizer by tasks.registering(JavaExec::class) {
|
||||||
|
|||||||
+5
-10
@@ -5,16 +5,19 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer
|
package org.jetbrains.kotlin.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.TargetedNativeManifestDataProvider
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
|
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
|
||||||
|
|
||||||
class CommonizerParameters(
|
class CommonizerParameters(
|
||||||
|
val resultsConsumer: ResultsConsumer,
|
||||||
|
val manifestDataProvider: TargetedNativeManifestDataProvider,
|
||||||
val statsCollector: StatsCollector? = null,
|
val statsCollector: StatsCollector? = null,
|
||||||
val progressLogger: ((String) -> Unit)? = null
|
val progressLogger: ((String) -> Unit)? = null
|
||||||
) {
|
) {
|
||||||
// use linked hash map to preserve order
|
// use linked hash map to preserve order
|
||||||
private val _targetProviders = LinkedHashMap<LeafTarget, TargetProvider>()
|
private val _targetProviders = LinkedHashMap<LeafCommonizerTarget, TargetProvider>()
|
||||||
val targetProviders: List<TargetProvider> get() = _targetProviders.values.toList()
|
val targetProviders: List<TargetProvider> get() = _targetProviders.values.toList()
|
||||||
val sharedTarget: SharedTarget get() = SharedTarget(_targetProviders.keys)
|
val sharedTarget: SharedCommonizerTarget get() = SharedCommonizerTarget(_targetProviders.keys)
|
||||||
|
|
||||||
// common module dependencies (ex: Kotlin stdlib)
|
// common module dependencies (ex: Kotlin stdlib)
|
||||||
var dependencyModulesProvider: ModulesProvider? = null
|
var dependencyModulesProvider: ModulesProvider? = null
|
||||||
@@ -30,14 +33,6 @@ class CommonizerParameters(
|
|||||||
return this
|
return this
|
||||||
}
|
}
|
||||||
|
|
||||||
private var _resultsConsumer: ResultsConsumer? = null
|
|
||||||
var resultsConsumer: ResultsConsumer
|
|
||||||
get() = _resultsConsumer ?: error("Results consumer has not been set")
|
|
||||||
set(value) {
|
|
||||||
check(_resultsConsumer == null)
|
|
||||||
_resultsConsumer = value
|
|
||||||
}
|
|
||||||
|
|
||||||
fun getCommonModuleNames(): Set<String> {
|
fun getCommonModuleNames(): Set<String> {
|
||||||
if (_targetProviders.size < 2) return emptySet() // too few targets
|
if (_targetProviders.size < 2) return emptySet() // too few targets
|
||||||
|
|
||||||
|
|||||||
@@ -1,36 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2019 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.descriptors.commonizer
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
|
||||||
|
|
||||||
// N.B. TargetPlatform/SimplePlatform are non exhaustive enough to address both target platforms such as
|
|
||||||
// JVM, JS and concrete Kotlin/Native targets, e.g. macos_x64, ios_x64, linux_x64.
|
|
||||||
sealed class CommonizerTarget {
|
|
||||||
abstract val name: String
|
|
||||||
abstract val prettyName: String
|
|
||||||
|
|
||||||
fun prettyCommonizedName(sharedTarget: SharedTarget): String = when {
|
|
||||||
this == sharedTarget -> prettyName
|
|
||||||
this in sharedTarget.targets -> sharedTarget.targets.joinToString(prefix = "[", postfix = "]") {
|
|
||||||
if (it == this) "${it.name}(*)" else it.name
|
|
||||||
}
|
|
||||||
else -> error("Target $prettyName is not in ${sharedTarget.prettyName}")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
data class LeafTarget(override val name: String, val konanTarget: KonanTarget? = null) : CommonizerTarget() {
|
|
||||||
override val prettyName get() = "[$name]"
|
|
||||||
}
|
|
||||||
|
|
||||||
data class SharedTarget(val targets: Set<CommonizerTarget>) : CommonizerTarget() {
|
|
||||||
init {
|
|
||||||
require(targets.isNotEmpty())
|
|
||||||
}
|
|
||||||
|
|
||||||
override val name get() = targets.joinToString(prefix = "[", postfix = "]") { it.name }
|
|
||||||
override val prettyName get() = name
|
|
||||||
}
|
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.library.*
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal data class KonanDistribution(val root: File)
|
||||||
|
|
||||||
|
internal val KonanDistribution.stdlib: File
|
||||||
|
get() = root.resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME))
|
||||||
|
|
||||||
|
internal val KonanDistribution.klibDir: File
|
||||||
|
get() = root.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
||||||
|
|
||||||
|
internal val KonanDistribution.platformLibsDir: File
|
||||||
|
get() = klibDir.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR)
|
||||||
+44
@@ -0,0 +1,44 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
||||||
|
import org.jetbrains.kotlin.backend.common.serialization.metadata.metadataVersion
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeLibrary
|
||||||
|
import org.jetbrains.kotlin.library.ToolingSingleFileKlibResolveStrategy
|
||||||
|
import org.jetbrains.kotlin.library.resolveSingleFileKlib
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal fun interface NativeLibraryLoader {
|
||||||
|
operator fun invoke(file: File): NativeLibrary
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class DefaultNativeLibraryLoader(
|
||||||
|
private val logger: Logger
|
||||||
|
) : NativeLibraryLoader {
|
||||||
|
override fun invoke(file: File): NativeLibrary {
|
||||||
|
val library = resolveSingleFileKlib(
|
||||||
|
libraryFile = org.jetbrains.kotlin.konan.file.File(file.path),
|
||||||
|
logger = logger,
|
||||||
|
strategy = ToolingSingleFileKlibResolveStrategy
|
||||||
|
)
|
||||||
|
|
||||||
|
if (library.versions.metadataVersion == null)
|
||||||
|
logger.fatal("Library does not have metadata version specified in manifest: $file")
|
||||||
|
|
||||||
|
val metadataVersion = library.metadataVersion
|
||||||
|
if (metadataVersion?.isCompatible() != true)
|
||||||
|
logger.fatal(
|
||||||
|
"""
|
||||||
|
Library has incompatible metadata version ${metadataVersion ?: "\"unknown\""}: $file
|
||||||
|
Please make sure that all libraries passed to commonizer compatible metadata version ${KlibMetadataVersion.INSTANCE}
|
||||||
|
""".trimIndent()
|
||||||
|
)
|
||||||
|
|
||||||
|
return NativeLibrary(library)
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
-4
@@ -5,9 +5,14 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer
|
package org.jetbrains.kotlin.descriptors.commonizer
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeSensitiveManifestData
|
||||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
internal fun buildResultsConsumer(init: ResultsConsumerBuilder.() -> Unit): ResultsConsumer {
|
||||||
|
return ResultsConsumerBuilder().apply(init).build()
|
||||||
|
}
|
||||||
|
|
||||||
interface ResultsConsumer {
|
interface ResultsConsumer {
|
||||||
enum class Status { NOTHING_TO_DO, DONE }
|
enum class Status { NOTHING_TO_DO, DONE }
|
||||||
|
|
||||||
@@ -18,23 +23,70 @@ interface ResultsConsumer {
|
|||||||
override val libraryName: String get() = originalLocation.name
|
override val libraryName: String get() = originalLocation.name
|
||||||
}
|
}
|
||||||
|
|
||||||
class Commonized(override val libraryName: String, val metadata: SerializedMetadata) : ModuleResult()
|
class Commonized(
|
||||||
|
override val libraryName: String, val metadata: SerializedMetadata, val manifest: NativeSensitiveManifestData
|
||||||
|
) : ModuleResult()
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Consume a single [ModuleResult] for the specified [CommonizerTarget].
|
* Consume a single [ModuleResult] for the specified [CommonizerTarget].
|
||||||
*/
|
*/
|
||||||
fun consume(target: CommonizerTarget, moduleResult: ModuleResult)
|
fun consume(target: CommonizerTarget, moduleResult: ModuleResult) = Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Mark the specified [CommonizerTarget] as fully consumed.
|
* Mark the specified [CommonizerTarget] as fully consumed.
|
||||||
* It's forbidden to make subsequent [consume] calls for fully consumed targets.
|
* It's forbidden to make subsequent [consume] calls for fully consumed targets.
|
||||||
*/
|
*/
|
||||||
fun targetConsumed(target: CommonizerTarget)
|
fun targetConsumed(target: CommonizerTarget) = Unit
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Notify that all results have been consumed.
|
* Notify that all results have been consumed.
|
||||||
* It's forbidden to make any subsequent [consume] and [targetConsumed] calls after this call.
|
* It's forbidden to make any subsequent [consume] and [targetConsumed] calls after this call.
|
||||||
*/
|
*/
|
||||||
fun allConsumed(status: Status)
|
fun allConsumed(status: Status) = Unit
|
||||||
|
}
|
||||||
|
|
||||||
|
internal class ResultsConsumerBuilder {
|
||||||
|
private var resultsConsumer: ResultsConsumer? = null
|
||||||
|
|
||||||
|
infix fun add(consumer: ResultsConsumer) {
|
||||||
|
val resultsConsumer = this.resultsConsumer
|
||||||
|
if (resultsConsumer == null) {
|
||||||
|
this.resultsConsumer = consumer
|
||||||
|
return
|
||||||
|
}
|
||||||
|
this.resultsConsumer = resultsConsumer + consumer
|
||||||
|
}
|
||||||
|
|
||||||
|
fun build(): ResultsConsumer {
|
||||||
|
return resultsConsumer ?: object : ResultsConsumer {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
operator fun ResultsConsumer.plus(other: ResultsConsumer?): ResultsConsumer {
|
||||||
|
if (other == null) return this
|
||||||
|
if (this is CompositeResultsConsumer) {
|
||||||
|
return CompositeResultsConsumer(consumers + other)
|
||||||
|
}
|
||||||
|
return CompositeResultsConsumer(listOf(this, other))
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CompositeResultsConsumer(val consumers: List<ResultsConsumer>) : ResultsConsumer {
|
||||||
|
override fun consume(target: CommonizerTarget, moduleResult: ResultsConsumer.ModuleResult) {
|
||||||
|
consumers.forEach { consumer ->
|
||||||
|
consumer.consume(target, moduleResult)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun targetConsumed(target: CommonizerTarget) {
|
||||||
|
consumers.forEach { consumer ->
|
||||||
|
consumer.targetConsumed(target)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun allConsumed(status: ResultsConsumer.Status) {
|
||||||
|
consumers.forEach { consumer ->
|
||||||
|
consumer.allConsumed(status)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import org.jetbrains.kotlin.library.SerializedMetadata
|
|||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
class TargetProvider(
|
class TargetProvider(
|
||||||
val target: LeafTarget,
|
val target: LeafCommonizerTarget,
|
||||||
val modulesProvider: ModulesProvider,
|
val modulesProvider: ModulesProvider,
|
||||||
val dependencyModulesProvider: ModulesProvider?
|
val dependencyModulesProvider: ModulesProvider?
|
||||||
)
|
)
|
||||||
|
|||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer.cli
|
||||||
|
|
||||||
|
internal object DependencyLibrariesOptionType : LibrariesSetOptionType(
|
||||||
|
mandatory = true,
|
||||||
|
alias = "dependency-libraries",
|
||||||
|
description = "';' separated list of klib file paths that can be used as dependency"
|
||||||
|
)
|
||||||
+12
@@ -0,0 +1,12 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer.cli
|
||||||
|
|
||||||
|
internal object InputLibrariesOptionType : LibrariesSetOptionType(
|
||||||
|
mandatory = true,
|
||||||
|
alias = "input-libraries",
|
||||||
|
description = "';' separated list of klib file paths that will get commonized"
|
||||||
|
)
|
||||||
+25
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer.cli
|
||||||
|
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal abstract class LibrariesSetOptionType(
|
||||||
|
mandatory: Boolean,
|
||||||
|
alias: String,
|
||||||
|
description: String
|
||||||
|
) : OptionType<List<File>>(
|
||||||
|
mandatory = mandatory,
|
||||||
|
alias = alias,
|
||||||
|
description = description
|
||||||
|
) {
|
||||||
|
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<List<File>> {
|
||||||
|
if (rawValue.isBlank()) {
|
||||||
|
return Option(this, emptyList())
|
||||||
|
}
|
||||||
|
return Option(this, rawValue.split(";").map(::File))
|
||||||
|
}
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer.cli
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.parseCommonizerTarget
|
||||||
|
|
||||||
|
internal object OutputCommonizerTargetOptionType : OptionType<SharedCommonizerTarget>(
|
||||||
|
alias = "output-commonizer-target",
|
||||||
|
description = "Shared commonizer target representing the commonized output hierarchy",
|
||||||
|
mandatory = true
|
||||||
|
) {
|
||||||
|
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<SharedCommonizerTarget> {
|
||||||
|
return try {
|
||||||
|
Option(this, parseCommonizerTarget(rawValue) as SharedCommonizerTarget)
|
||||||
|
} catch (t: Throwable) {
|
||||||
|
onError("Failed parsing output-commonizer-target ($rawValue): ${t.message}")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer.cli
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
|
||||||
|
fun Logger.toProgressLogger(): Logger {
|
||||||
|
return ProgressLogger(this)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ProgressLogger(private val logger: Logger) : Logger by logger {
|
||||||
|
override fun log(message: String) {
|
||||||
|
logger.log("* $message")
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun warning(message: String) {
|
||||||
|
logger.log("* $message")
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
-1
@@ -5,7 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer.cli
|
package org.jetbrains.kotlin.descriptors.commonizer.cli
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType
|
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsType
|
||||||
|
|
||||||
internal object StatsTypeOptionType : OptionType<StatsType>("log-stats", DESCRIPTION, mandatory = false) {
|
internal object StatsTypeOptionType : OptionType<StatsType>("log-stats", DESCRIPTION, mandatory = false) {
|
||||||
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<StatsType> {
|
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<StatsType> {
|
||||||
|
|||||||
@@ -40,7 +40,21 @@ internal enum class TaskType(
|
|||||||
NativeDistributionOptionType
|
NativeDistributionOptionType
|
||||||
),
|
),
|
||||||
::NativeDistributionListTargets
|
::NativeDistributionListTargets
|
||||||
);
|
),
|
||||||
|
|
||||||
|
NATIVE_KLIB_COMMONIZE(
|
||||||
|
"native-klib-commonize",
|
||||||
|
"Commonize any platform-specific libraries",
|
||||||
|
listOf(
|
||||||
|
NativeDistributionOptionType,
|
||||||
|
OutputOptionType,
|
||||||
|
InputLibrariesOptionType,
|
||||||
|
DependencyLibrariesOptionType,
|
||||||
|
OutputCommonizerTargetOptionType,
|
||||||
|
),
|
||||||
|
::NativeKlibCommonize
|
||||||
|
)
|
||||||
|
;
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun getByAlias(alias: String) = values().firstOrNull { it.alias == alias }
|
fun getByAlias(alias: String) = values().firstOrNull { it.alias == alias }
|
||||||
|
|||||||
+81
-20
@@ -5,8 +5,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer.cli
|
package org.jetbrains.kotlin.descriptors.commonizer.cli
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.CopyUnconsumedModulesAsIsConsumer
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.CopyStdlibResultsConsumer
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.ModuleSerializer
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.repository.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.repository.EmptyRepository
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.repository.FilesRepository
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.repository.KonanDistributionRepository
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.repository.Repository
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.stats.FileStatsOutput
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsType
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
|
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
|
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
@@ -35,11 +47,52 @@ internal class NativeDistributionListTargets(options: Collection<Option<*>>) : T
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class NativeKlibCommonize(options: Collection<Option<*>>) : Task(options) {
|
||||||
|
override val category: Category = Category.COMMONIZATION
|
||||||
|
|
||||||
|
override fun execute(logPrefix: String) {
|
||||||
|
val distribution = KonanDistribution(getMandatory<File, NativeDistributionOptionType>())
|
||||||
|
val destination = getMandatory<File, OutputOptionType>()
|
||||||
|
val targetLibraries = getMandatory<List<File>, InputLibrariesOptionType>()
|
||||||
|
val dependencyLibraries = getMandatory<List<File>, DependencyLibrariesOptionType>()
|
||||||
|
val outputCommonizerTarget = getMandatory<SharedCommonizerTarget, OutputCommonizerTargetOptionType>()
|
||||||
|
val statsType = getOptional<StatsType, StatsTypeOptionType> { it == "log-stats" } ?: StatsType.NONE
|
||||||
|
|
||||||
|
val konanTargets = outputCommonizerTarget.konanTargets
|
||||||
|
val logger = CliLoggerAdapter(2)
|
||||||
|
val libraryLoader = DefaultNativeLibraryLoader(logger)
|
||||||
|
val statsCollector = StatsCollector(statsType, outputCommonizerTarget.konanTargets.toList())
|
||||||
|
val repository = FilesRepository(targetLibraries.toSet(), libraryLoader)
|
||||||
|
|
||||||
|
val resultsConsumer = buildResultsConsumer {
|
||||||
|
this add ModuleSerializer(destination, HierarchicalCommonizerOutputLayout)
|
||||||
|
this add CopyUnconsumedModulesAsIsConsumer(
|
||||||
|
repository, destination, konanTargets, NativeDistributionCommonizerOutputLayout, logger.toProgressLogger()
|
||||||
|
)
|
||||||
|
this add LoggingResultsConsumer(outputCommonizerTarget, logger.toProgressLogger())
|
||||||
|
}
|
||||||
|
|
||||||
|
NativeDistributionCommonizer(
|
||||||
|
konanDistribution = distribution,
|
||||||
|
repository = repository,
|
||||||
|
dependencies = KonanDistributionRepository(distribution, outputCommonizerTarget.konanTargets, libraryLoader) +
|
||||||
|
FilesRepository(dependencyLibraries.toSet(), libraryLoader),
|
||||||
|
libraryLoader = libraryLoader,
|
||||||
|
targets = outputCommonizerTarget.konanTargets.toList(),
|
||||||
|
resultsConsumer = resultsConsumer,
|
||||||
|
statsCollector = statsCollector,
|
||||||
|
logger = logger
|
||||||
|
).run()
|
||||||
|
|
||||||
|
statsCollector?.writeTo(FileStatsOutput(destination, statsType.name.toLowerCase()))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Task(options) {
|
internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Task(options) {
|
||||||
override val category get() = Category.COMMONIZATION
|
override val category get() = Category.COMMONIZATION
|
||||||
|
|
||||||
override fun execute(logPrefix: String) {
|
override fun execute(logPrefix: String) {
|
||||||
val distribution = getMandatory<File, NativeDistributionOptionType>()
|
val distribution = KonanDistribution(getMandatory<File, NativeDistributionOptionType>())
|
||||||
val destination = getMandatory<File, OutputOptionType>()
|
val destination = getMandatory<File, OutputOptionType>()
|
||||||
val targets = getMandatory<List<KonanTarget>, NativeTargetsOptionType>()
|
val targets = getMandatory<List<KonanTarget>, NativeTargetsOptionType>()
|
||||||
|
|
||||||
@@ -47,35 +100,43 @@ internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Tas
|
|||||||
val copyEndorsedLibs = getOptional<Boolean, BooleanOptionType> { it == "copy-endorsed-libs" } ?: false
|
val copyEndorsedLibs = getOptional<Boolean, BooleanOptionType> { it == "copy-endorsed-libs" } ?: false
|
||||||
val statsType = getOptional<StatsType, StatsTypeOptionType> { it == "log-stats" } ?: StatsType.NONE
|
val statsType = getOptional<StatsType, StatsTypeOptionType> { it == "log-stats" } ?: StatsType.NONE
|
||||||
|
|
||||||
val targetNames = targets.joinToString { "[${it.name}]" }
|
val logger = CliLoggerAdapter(2)
|
||||||
val descriptionSuffix = estimateLibrariesCount(distribution, targets)?.let { " ($it items)" } ?: ""
|
val libraryLoader = DefaultNativeLibraryLoader(logger)
|
||||||
val description = "${logPrefix}Preparing commonized Kotlin/Native libraries for targets $targetNames$descriptionSuffix"
|
val repository = KonanDistributionRepository(distribution, targets.toSet(), libraryLoader)
|
||||||
|
val statsCollector = StatsCollector(statsType, targets.toList())
|
||||||
|
|
||||||
|
val resultsConsumer = buildResultsConsumer {
|
||||||
|
this add ModuleSerializer(destination, NativeDistributionCommonizerOutputLayout)
|
||||||
|
this add CopyUnconsumedModulesAsIsConsumer(
|
||||||
|
repository, destination, targets.toSet(), NativeDistributionCommonizerOutputLayout, logger.toProgressLogger()
|
||||||
|
)
|
||||||
|
if (copyStdlib) this add CopyStdlibResultsConsumer(distribution, destination, logger.toProgressLogger())
|
||||||
|
if (copyEndorsedLibs) this add CopyEndorsedLibrairesResultsConsumer(distribution, destination, logger.toProgressLogger())
|
||||||
|
this add LoggingResultsConsumer(SharedCommonizerTarget(targets), logger.toProgressLogger())
|
||||||
|
}
|
||||||
|
|
||||||
|
val targetNames = targets.joinToString { "[${it.name}]" }
|
||||||
|
val descriptionSuffix = estimateLibrariesCount(repository, targets).let { " ($it items)" }
|
||||||
|
val description = "${logPrefix}Preparing commonized Kotlin/Native libraries for targets $targetNames$descriptionSuffix"
|
||||||
println(description)
|
println(description)
|
||||||
|
|
||||||
NativeDistributionCommonizer(
|
NativeDistributionCommonizer(
|
||||||
repository = distribution,
|
repository = repository,
|
||||||
|
konanDistribution = distribution,
|
||||||
|
dependencies = EmptyRepository,
|
||||||
|
libraryLoader = libraryLoader,
|
||||||
targets = targets,
|
targets = targets,
|
||||||
destination = destination,
|
resultsConsumer = resultsConsumer,
|
||||||
copyStdlib = copyStdlib,
|
statsCollector = statsCollector,
|
||||||
copyEndorsedLibs = copyEndorsedLibs,
|
logger = logger
|
||||||
statsType = statsType,
|
|
||||||
logger = CliLoggerAdapter(2)
|
|
||||||
).run()
|
).run()
|
||||||
|
|
||||||
println("$description: Done")
|
println("$description: Done")
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun estimateLibrariesCount(distribution: File, targets: List<KonanTarget>): Int? {
|
private fun estimateLibrariesCount(repository: Repository, targets: List<KonanTarget>): Int {
|
||||||
val targetNames = targets.map { it.name }
|
return targets.flatMap { repository.getLibraries(LeafCommonizerTarget(it)) }.count()
|
||||||
return distribution.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
|
||||||
.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR)
|
|
||||||
.listFiles()
|
|
||||||
?.filter { it.name in targetNames }
|
|
||||||
?.mapNotNull { it.listFiles() }
|
|
||||||
?.flatMap { it.toList() }
|
|
||||||
?.size
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+6
-6
@@ -5,24 +5,24 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer.core
|
package org.jetbrains.kotlin.descriptors.commonizer.core
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.LeafTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.SharedTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirRoot
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirRoot
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirRootFactory
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirRootFactory
|
||||||
|
|
||||||
class RootCommonizer : AbstractStandardCommonizer<CirRoot, CirRoot>() {
|
class RootCommonizer : AbstractStandardCommonizer<CirRoot, CirRoot>() {
|
||||||
private val leafTargets = mutableSetOf<LeafTarget>()
|
private val leafTargets = mutableSetOf<LeafCommonizerTarget>()
|
||||||
|
|
||||||
override fun commonizationResult() = CirRootFactory.create(
|
override fun commonizationResult() = CirRootFactory.create(
|
||||||
target = SharedTarget(leafTargets)
|
target = SharedCommonizerTarget(leafTargets)
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun initialize(first: CirRoot) {
|
override fun initialize(first: CirRoot) {
|
||||||
leafTargets += first.target as LeafTarget
|
leafTargets += first.target as LeafCommonizerTarget
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun doCommonizeWith(next: CirRoot): Boolean {
|
override fun doCommonizeWith(next: CirRoot): Boolean {
|
||||||
leafTargets += next.target as LeafTarget
|
leafTargets += next.target as LeafCommonizerTarget
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -67,11 +67,11 @@ private fun serializeTarget(mergeResult: CirTreeMergeResult, targetIndex: Int, p
|
|||||||
val serializedMetadata = with(metadataModule.write(KLIB_FRAGMENT_WRITE_STRATEGY)) {
|
val serializedMetadata = with(metadataModule.write(KLIB_FRAGMENT_WRITE_STRATEGY)) {
|
||||||
SerializedMetadata(header, fragments, fragmentNames)
|
SerializedMetadata(header, fragments, fragmentNames)
|
||||||
}
|
}
|
||||||
|
val manifestData = parameters.manifestDataProvider.getManifest(target, libraryName)
|
||||||
parameters.resultsConsumer.consume(target, ModuleResult.Commonized(libraryName, serializedMetadata))
|
parameters.resultsConsumer.consume(target, ModuleResult.Commonized(libraryName, serializedMetadata, manifestData))
|
||||||
}
|
}
|
||||||
|
|
||||||
if (target is LeafTarget) {
|
if (target is LeafCommonizerTarget) {
|
||||||
mergeResult.missingModuleInfos.getValue(target).forEach {
|
mergeResult.missingModuleInfos.getValue(target).forEach {
|
||||||
parameters.resultsConsumer.consume(target, ModuleResult.Missing(it.originalLocation))
|
parameters.resultsConsumer.consume(target, ModuleResult.Missing(it.originalLocation))
|
||||||
}
|
}
|
||||||
|
|||||||
+62
@@ -0,0 +1,62 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
@file:Suppress("FunctionName")
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.descriptors.commonizer.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.KonanDistribution
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.klibDir
|
||||||
|
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
|
||||||
|
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal fun CopyStdlibResultsConsumer(
|
||||||
|
konanDistribution: KonanDistribution,
|
||||||
|
destination: File,
|
||||||
|
logger: Logger
|
||||||
|
): ResultsConsumer {
|
||||||
|
return CopyLibrariesFromKonanDistributionResultsConsumer(
|
||||||
|
konanDistribution,
|
||||||
|
destination,
|
||||||
|
invokeWhenCopied = { logger.log("Copied standard library") },
|
||||||
|
copyFileIf = { file -> file.endsWith(KONAN_STDLIB_NAME) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
internal fun CopyEndorsedLibrairesResultsConsumer(
|
||||||
|
konanDistribution: KonanDistribution,
|
||||||
|
destination: File,
|
||||||
|
logger: Logger
|
||||||
|
): ResultsConsumer {
|
||||||
|
return CopyLibrariesFromKonanDistributionResultsConsumer(
|
||||||
|
konanDistribution,
|
||||||
|
destination,
|
||||||
|
invokeWhenCopied = { logger.log("Copied endorsed libraries") },
|
||||||
|
copyFileIf = { file -> !file.endsWith(KONAN_STDLIB_NAME) }
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CopyLibrariesFromKonanDistributionResultsConsumer(
|
||||||
|
private val konanDistribution: KonanDistribution,
|
||||||
|
private val destination: File,
|
||||||
|
private val invokeWhenCopied: () -> Unit = {},
|
||||||
|
private val copyFileIf: (File) -> Boolean = { true }
|
||||||
|
) : ResultsConsumer {
|
||||||
|
override fun allConsumed(status: ResultsConsumer.Status) {
|
||||||
|
konanDistribution.klibDir
|
||||||
|
.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
|
||||||
|
.listFiles().orEmpty()
|
||||||
|
.filter { it.isDirectory }
|
||||||
|
.filterNot(copyFileIf)
|
||||||
|
.forEach { libraryOrigin ->
|
||||||
|
val libraryDestination = destination.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR).resolve(libraryOrigin.name)
|
||||||
|
libraryOrigin.copyRecursively(libraryDestination)
|
||||||
|
}
|
||||||
|
invokeWhenCopied()
|
||||||
|
}
|
||||||
|
}
|
||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.repository.Repository
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal class CopyUnconsumedModulesAsIsConsumer(
|
||||||
|
private val repository: Repository,
|
||||||
|
private val destination: File,
|
||||||
|
private val targets: Set<KonanTarget>,
|
||||||
|
private val outputLayout: CommonizerOutputLayout,
|
||||||
|
private val logger: Logger? = null
|
||||||
|
) : ResultsConsumer {
|
||||||
|
|
||||||
|
private val consumedTargets = mutableSetOf<KonanTarget>()
|
||||||
|
|
||||||
|
override fun targetConsumed(target: CommonizerTarget) {
|
||||||
|
if (target is LeafCommonizerTarget) {
|
||||||
|
consumedTargets.add(target.konanTarget)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun allConsumed(status: ResultsConsumer.Status) {
|
||||||
|
when (status) {
|
||||||
|
ResultsConsumer.Status.NOTHING_TO_DO -> targets.forEach(::copyTargetAsIs)
|
||||||
|
ResultsConsumer.Status.DONE -> targets.minus(consumedTargets).forEach(::copyTargetAsIs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun copyTargetAsIs(target: KonanTarget) {
|
||||||
|
val commonizerTarget = CommonizerTarget(target)
|
||||||
|
val libraries = repository.getLibraries(commonizerTarget)
|
||||||
|
val librariesDestination = outputLayout.getTargetDirectory(destination, commonizerTarget)
|
||||||
|
librariesDestination.mkdirs() // always create an empty directory even if there is nothing to copy
|
||||||
|
libraries.map { it.library.libraryFile.absolutePath }.map(::File).forEach { libraryFile ->
|
||||||
|
libraryFile.copyRecursively(destination.resolve(libraryFile.name))
|
||||||
|
}
|
||||||
|
|
||||||
|
logger?.log("Copied ${libraries.size} libraries for ${commonizerTarget.prettyName}")
|
||||||
|
}
|
||||||
|
}
|
||||||
+20
@@ -0,0 +1,20 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.prettyName
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
|
||||||
|
internal class LoggingResultsConsumer(
|
||||||
|
private val outputCommonizerTarget: SharedCommonizerTarget, private val logger: Logger
|
||||||
|
) : ResultsConsumer {
|
||||||
|
override fun targetConsumed(target: CommonizerTarget) {
|
||||||
|
logger.log("Written libraries for ${outputCommonizerTarget.prettyName(target)}")
|
||||||
|
}
|
||||||
|
}
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2021 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.descriptors.commonizer.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.*
|
||||||
|
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||||
|
import org.jetbrains.kotlin.library.impl.BaseWriterImpl
|
||||||
|
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
|
||||||
|
import org.jetbrains.kotlin.library.impl.KotlinLibraryLayoutForWriter
|
||||||
|
import org.jetbrains.kotlin.library.impl.KotlinLibraryWriterImpl
|
||||||
|
import org.jetbrains.kotlin.util.Logger
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal class ModuleSerializer(
|
||||||
|
private val destination: File,
|
||||||
|
private val outputLayout: CommonizerOutputLayout,
|
||||||
|
) : ResultsConsumer {
|
||||||
|
override fun consume(target: CommonizerTarget, moduleResult: ResultsConsumer.ModuleResult) {
|
||||||
|
val librariesDestination = outputLayout.getTargetDirectory(destination, target)
|
||||||
|
when (moduleResult) {
|
||||||
|
is ResultsConsumer.ModuleResult.Commonized -> {
|
||||||
|
val libraryName = moduleResult.libraryName
|
||||||
|
val libraryDestination = librariesDestination.resolve(libraryName)
|
||||||
|
writeLibrary(moduleResult.metadata, moduleResult.manifest, libraryDestination)
|
||||||
|
}
|
||||||
|
is ResultsConsumer.ModuleResult.Missing -> {
|
||||||
|
val libraryName = moduleResult.libraryName
|
||||||
|
val missingModuleLocation = moduleResult.originalLocation
|
||||||
|
missingModuleLocation.copyRecursively(librariesDestination.resolve(libraryName))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun writeLibrary(
|
||||||
|
metadata: SerializedMetadata,
|
||||||
|
manifestData: NativeSensitiveManifestData,
|
||||||
|
libraryDestination: File
|
||||||
|
) {
|
||||||
|
val layout = org.jetbrains.kotlin.konan.file.File(libraryDestination.path).let { KotlinLibraryLayoutForWriter(it, it) }
|
||||||
|
val library = KotlinLibraryWriterImpl(
|
||||||
|
moduleName = manifestData.uniqueName,
|
||||||
|
versions = manifestData.versions,
|
||||||
|
builtInsPlatform = BuiltInsPlatform.NATIVE,
|
||||||
|
nativeTargets = emptyList(), // will be overwritten with NativeSensitiveManifestData.applyTo() below
|
||||||
|
nopack = true,
|
||||||
|
shortName = manifestData.shortName,
|
||||||
|
layout = layout
|
||||||
|
)
|
||||||
|
library.addMetadata(metadata)
|
||||||
|
manifestData.applyTo(library.base as BaseWriterImpl)
|
||||||
|
library.commit()
|
||||||
|
}
|
||||||
+36
-105
@@ -5,160 +5,91 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer.konan
|
package org.jetbrains.kotlin.descriptors.commonizer.konan
|
||||||
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.KlibMetadataVersion
|
|
||||||
import org.jetbrains.kotlin.backend.common.serialization.metadata.metadataVersion
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.*
|
import org.jetbrains.kotlin.descriptors.commonizer.*
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.StatsType.*
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.stats.*
|
import org.jetbrains.kotlin.descriptors.commonizer.cli.toProgressLogger
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeDistributionCommonizer.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.repository.Repository
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.stats.StatsCollector
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.ResettableClockMark
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.ResettableClockMark
|
||||||
import org.jetbrains.kotlin.konan.library.*
|
import org.jetbrains.kotlin.konan.library.*
|
||||||
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.ToolingSingleFileKlibResolveStrategy
|
|
||||||
import org.jetbrains.kotlin.library.resolveSingleFileKlib
|
|
||||||
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
import org.jetbrains.kotlin.storage.LockBasedStorageManager
|
||||||
import org.jetbrains.kotlin.util.Logger
|
import org.jetbrains.kotlin.util.Logger
|
||||||
import java.io.File
|
|
||||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
|
||||||
|
|
||||||
class NativeDistributionCommonizer(
|
internal class NativeDistributionCommonizer internal constructor(
|
||||||
private val repository: File,
|
private val konanDistribution: KonanDistribution,
|
||||||
|
private val repository: Repository,
|
||||||
|
private val dependencies: Repository,
|
||||||
|
private val libraryLoader: NativeLibraryLoader,
|
||||||
private val targets: List<KonanTarget>,
|
private val targets: List<KonanTarget>,
|
||||||
private val destination: File,
|
private val resultsConsumer: ResultsConsumer,
|
||||||
private val copyStdlib: Boolean,
|
private val statsCollector: StatsCollector?,
|
||||||
private val copyEndorsedLibs: Boolean,
|
|
||||||
private val statsType: StatsType,
|
|
||||||
private val logger: Logger
|
private val logger: Logger
|
||||||
) {
|
) {
|
||||||
enum class StatsType { RAW, AGGREGATED, NONE }
|
|
||||||
|
|
||||||
private val clockMark = ResettableClockMark()
|
private val clockMark = ResettableClockMark()
|
||||||
|
|
||||||
fun run() {
|
fun run() {
|
||||||
checkPreconditions()
|
checkPreconditions()
|
||||||
clockMark.reset()
|
clockMark.reset()
|
||||||
|
|
||||||
// 1. load libraries
|
|
||||||
val allLibraries = loadLibraries()
|
val allLibraries = loadLibraries()
|
||||||
|
|
||||||
// 2. run commonization & write new libraries
|
|
||||||
commonizeAndSaveResults(allLibraries)
|
commonizeAndSaveResults(allLibraries)
|
||||||
|
|
||||||
logTotal()
|
logTotal()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun checkPreconditions() {
|
|
||||||
if (!repository.isDirectory)
|
|
||||||
logger.fatal("Repository does not exist: $repository")
|
|
||||||
|
|
||||||
when (targets.size) {
|
|
||||||
0 -> logger.fatal("No targets specified")
|
|
||||||
1 -> logger.fatal("Too few targets specified: $targets")
|
|
||||||
}
|
|
||||||
|
|
||||||
when {
|
|
||||||
!destination.exists() -> destination.mkdirs()
|
|
||||||
!destination.isDirectory -> logger.fatal("Output already exists: $destination")
|
|
||||||
destination.walkTopDown().any { it != destination } -> logger.fatal("Output is not empty: $destination")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun logProgress(message: String) = logger.log("* $message in ${clockMark.elapsedSinceLast()}")
|
|
||||||
|
|
||||||
private fun logTotal() = logger.log("TOTAL: ${clockMark.elapsedSinceStart()}")
|
|
||||||
|
|
||||||
private fun loadLibraries(): AllNativeLibraries {
|
private fun loadLibraries(): AllNativeLibraries {
|
||||||
val stdlibPath = repository.resolve(konanCommonLibraryPath(KONAN_STDLIB_NAME))
|
val stdlib = libraryLoader(konanDistribution.stdlib)
|
||||||
val stdlib = NativeLibrary(loadLibrary(stdlibPath))
|
|
||||||
|
|
||||||
val librariesByTargets = targets.associate { target ->
|
val librariesByTargets = targets.map(::LeafCommonizerTarget).associateWith { target ->
|
||||||
val leafTarget = LeafTarget(target.name, target)
|
NativeLibrariesToCommonize(repository.getLibraries(target).toList())
|
||||||
|
|
||||||
val platformLibs = leafTarget.platformLibrariesSource
|
|
||||||
.takeIf { it.isDirectory }
|
|
||||||
?.listFiles()
|
|
||||||
?.takeIf { it.isNotEmpty() }
|
|
||||||
?.map { NativeLibrary(loadLibrary(it)) }
|
|
||||||
.orEmpty()
|
|
||||||
|
|
||||||
if (platformLibs.isEmpty())
|
|
||||||
logger.warning("No platform libraries found for target ${leafTarget.prettyName}. This target will be excluded from commonization.")
|
|
||||||
|
|
||||||
leafTarget to NativeLibrariesToCommonize(platformLibs)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
librariesByTargets.forEach { (target, librariesToCommonize) ->
|
||||||
|
if (librariesToCommonize.libraries.isEmpty()) {
|
||||||
|
logger.warning("No platform libraries found for target $target. This target will be excluded from commonization.")
|
||||||
|
}
|
||||||
|
}
|
||||||
logProgress("Read lazy (uninitialized) libraries")
|
logProgress("Read lazy (uninitialized) libraries")
|
||||||
|
|
||||||
return AllNativeLibraries(stdlib, librariesByTargets)
|
return AllNativeLibraries(stdlib, librariesByTargets)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun loadLibrary(location: File): KotlinLibrary {
|
|
||||||
if (!location.isDirectory)
|
|
||||||
logger.fatal("Library not found: $location")
|
|
||||||
|
|
||||||
val library = resolveSingleFileKlib(
|
|
||||||
libraryFile = KFile(location.path),
|
|
||||||
logger = logger,
|
|
||||||
strategy = ToolingSingleFileKlibResolveStrategy
|
|
||||||
)
|
|
||||||
|
|
||||||
if (library.versions.metadataVersion == null)
|
|
||||||
logger.fatal("Library does not have metadata version specified in manifest: $location")
|
|
||||||
|
|
||||||
val metadataVersion = library.metadataVersion
|
|
||||||
if (metadataVersion?.isCompatible() != true)
|
|
||||||
logger.fatal(
|
|
||||||
"""
|
|
||||||
Library has incompatible metadata version ${metadataVersion ?: "\"unknown\""}: $location
|
|
||||||
Please make sure that all libraries passed to commonizer compatible metadata version ${KlibMetadataVersion.INSTANCE}
|
|
||||||
""".trimIndent()
|
|
||||||
)
|
|
||||||
|
|
||||||
return library
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun commonizeAndSaveResults(allLibraries: AllNativeLibraries) {
|
private fun commonizeAndSaveResults(allLibraries: AllNativeLibraries) {
|
||||||
val statsCollector = when (statsType) {
|
val manifestProvider = TargetedNativeManifestDataProvider(allLibraries)
|
||||||
RAW -> RawStatsCollector(targets)
|
|
||||||
AGGREGATED -> AggregatedStatsCollector(targets)
|
|
||||||
NONE -> null
|
|
||||||
}
|
|
||||||
|
|
||||||
val parameters = CommonizerParameters(statsCollector, ::logProgress).apply {
|
val parameters = CommonizerParameters(resultsConsumer, manifestProvider, statsCollector, ::logProgress).apply {
|
||||||
val storageManager = LockBasedStorageManager("Commonized modules")
|
val storageManager = LockBasedStorageManager("Commonized modules")
|
||||||
|
|
||||||
resultsConsumer = NativeDistributionResultsConsumer(
|
|
||||||
repository = repository,
|
|
||||||
originalLibraries = allLibraries,
|
|
||||||
destination = destination,
|
|
||||||
copyStdlib = copyStdlib,
|
|
||||||
copyEndorsedLibs = copyEndorsedLibs,
|
|
||||||
logProgress = ::logProgress
|
|
||||||
)
|
|
||||||
dependencyModulesProvider = NativeDistributionModulesProvider.forStandardLibrary(storageManager, allLibraries.stdlib)
|
dependencyModulesProvider = NativeDistributionModulesProvider.forStandardLibrary(storageManager, allLibraries.stdlib)
|
||||||
|
|
||||||
allLibraries.librariesByTargets.forEach { (target, librariesToCommonize) ->
|
allLibraries.librariesByTargets.forEach { (target, librariesToCommonize) ->
|
||||||
if (librariesToCommonize.libraries.isEmpty()) return@forEach
|
if (librariesToCommonize.libraries.isEmpty()) return@forEach
|
||||||
|
|
||||||
val modulesProvider = NativeDistributionModulesProvider.platformLibraries(storageManager, librariesToCommonize)
|
val modulesProvider = NativeDistributionModulesProvider.platformLibraries(storageManager, librariesToCommonize)
|
||||||
|
val dependencyModuleProvider = NativeDistributionModulesProvider.platformLibraries(
|
||||||
|
storageManager, NativeLibrariesToCommonize(dependencies.getLibraries(target).toList()),
|
||||||
|
)
|
||||||
|
|
||||||
addTarget(
|
addTarget(
|
||||||
TargetProvider(
|
TargetProvider(
|
||||||
target = target,
|
target = target,
|
||||||
modulesProvider = modulesProvider,
|
modulesProvider = modulesProvider,
|
||||||
dependencyModulesProvider = null // stdlib is already set as common dependency
|
dependencyModulesProvider = dependencyModuleProvider
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
runCommonization(parameters)
|
runCommonization(parameters)
|
||||||
|
|
||||||
statsCollector?.writeTo(FileStatsOutput(destination, statsType.name.toLowerCase()))
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private val LeafTarget.platformLibrariesSource: File
|
private fun checkPreconditions() {
|
||||||
get() = repository.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
when (targets.size) {
|
||||||
.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR)
|
0 -> logger.fatal("No targets specified")
|
||||||
.resolve(name)
|
1 -> logger.fatal("Too few targets specified: $targets")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun logProgress(message: String) = logger.toProgressLogger().log("$message in ${clockMark.elapsedSinceLast()}")
|
||||||
|
|
||||||
|
private fun logTotal() = logger.log("TOTAL: ${clockMark.elapsedSinceStart()}")
|
||||||
}
|
}
|
||||||
|
|||||||
-2
@@ -34,8 +34,6 @@ internal abstract class NativeDistributionModulesProvider(libraries: Collection<
|
|||||||
protected val moduleInfoMap: Map<String, NativeModuleInfo>
|
protected val moduleInfoMap: Map<String, NativeModuleInfo>
|
||||||
|
|
||||||
init {
|
init {
|
||||||
check(libraries.isNotEmpty()) { "No libraries supplied" }
|
|
||||||
|
|
||||||
val libraryMap = mutableMapOf<String, NativeLibrary>()
|
val libraryMap = mutableMapOf<String, NativeLibrary>()
|
||||||
val moduleInfoMap = mutableMapOf<String, NativeModuleInfo>()
|
val moduleInfoMap = mutableMapOf<String, NativeModuleInfo>()
|
||||||
|
|
||||||
|
|||||||
-172
@@ -1,172 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2021 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.descriptors.commonizer.konan
|
|
||||||
|
|
||||||
import com.intellij.util.containers.FactoryMap
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.ModuleResult
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.Status
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.LeafTarget
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.SharedTarget
|
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_COMMON_LIBS_DIR
|
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
|
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR
|
|
||||||
import org.jetbrains.kotlin.konan.library.KONAN_STDLIB_NAME
|
|
||||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
|
||||||
import org.jetbrains.kotlin.library.impl.BaseWriterImpl
|
|
||||||
import org.jetbrains.kotlin.library.impl.BuiltInsPlatform
|
|
||||||
import org.jetbrains.kotlin.library.impl.KotlinLibraryLayoutForWriter
|
|
||||||
import org.jetbrains.kotlin.library.impl.KotlinLibraryWriterImpl
|
|
||||||
import java.io.File
|
|
||||||
import org.jetbrains.kotlin.konan.file.File as KFile
|
|
||||||
|
|
||||||
internal class NativeDistributionResultsConsumer(
|
|
||||||
private val repository: File,
|
|
||||||
private val originalLibraries: AllNativeLibraries,
|
|
||||||
private val destination: File,
|
|
||||||
private val copyStdlib: Boolean,
|
|
||||||
private val copyEndorsedLibs: Boolean,
|
|
||||||
private val logProgress: (String) -> Unit
|
|
||||||
) : ResultsConsumer {
|
|
||||||
private val allLeafTargets = originalLibraries.librariesByTargets.keys
|
|
||||||
|
|
||||||
private val allLeafCommonizedTargets = originalLibraries.librariesByTargets.filterValues { it.libraries.isNotEmpty() }.keys
|
|
||||||
private val sharedTarget = SharedTarget(allLeafCommonizedTargets)
|
|
||||||
|
|
||||||
private val consumedTargets = LinkedHashSet<CommonizerTarget>()
|
|
||||||
|
|
||||||
private val cachedManifestProviders = FactoryMap.create<CommonizerTarget, NativeManifestDataProvider> { target ->
|
|
||||||
when (target) {
|
|
||||||
is LeafTarget -> originalLibraries.librariesByTargets.getValue(target)
|
|
||||||
is SharedTarget -> CommonNativeManifestDataProvider(originalLibraries.librariesByTargets.values)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private val cachedLibrariesDestination = FactoryMap.create<CommonizerTarget, File> { target ->
|
|
||||||
val librariesDestination = when (target) {
|
|
||||||
is LeafTarget -> destination.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.name)
|
|
||||||
is SharedTarget -> destination.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
|
|
||||||
}
|
|
||||||
|
|
||||||
librariesDestination.mkdirs() // always create an empty directory even if there is nothing to copy
|
|
||||||
librariesDestination
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun consume(target: CommonizerTarget, moduleResult: ModuleResult) {
|
|
||||||
check(target in allLeafCommonizedTargets || target == sharedTarget)
|
|
||||||
consumedTargets += target
|
|
||||||
|
|
||||||
serializeModule(target, moduleResult)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun targetConsumed(target: CommonizerTarget) {
|
|
||||||
check(target in consumedTargets)
|
|
||||||
|
|
||||||
logProgress("Written libraries for ${target.prettyCommonizedName(sharedTarget)}")
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun allConsumed(status: Status) {
|
|
||||||
// optimization: stdlib and endorsed libraries effectively remain the same across all Kotlin/Native targets,
|
|
||||||
// so they can be just copied to the new destination without running serializer
|
|
||||||
copyCommonStandardLibraries()
|
|
||||||
|
|
||||||
when (status) {
|
|
||||||
Status.NOTHING_TO_DO -> {
|
|
||||||
// It may happen that all targets to be commonized (or at least all but one target) miss platform libraries.
|
|
||||||
// In such case commonizer will do nothing and raise a special status value 'NOTHING_TO_DO'.
|
|
||||||
// So, let's just copy platform libraries from the target where they are to the new destination.
|
|
||||||
allLeafTargets.forEach(::copyTargetAsIs)
|
|
||||||
}
|
|
||||||
Status.DONE -> {
|
|
||||||
// 'targetsToCopy' are some leaf targets with empty set of platform libraries
|
|
||||||
val targetsToCopy = allLeafTargets - consumedTargets.filterIsInstance<LeafTarget>()
|
|
||||||
targetsToCopy.forEach(::copyTargetAsIs)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun copyCommonStandardLibraries() {
|
|
||||||
if (copyStdlib || copyEndorsedLibs) {
|
|
||||||
repository.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
|
||||||
.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR)
|
|
||||||
.listFiles()
|
|
||||||
?.filter { it.isDirectory }
|
|
||||||
?.let {
|
|
||||||
if (copyStdlib) {
|
|
||||||
if (copyEndorsedLibs) it else it.filter { dir -> dir.endsWith(KONAN_STDLIB_NAME) }
|
|
||||||
} else
|
|
||||||
it.filter { dir -> !dir.endsWith(KONAN_STDLIB_NAME) }
|
|
||||||
}?.forEach { libraryOrigin ->
|
|
||||||
val libraryDestination = destination.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR).resolve(libraryOrigin.name)
|
|
||||||
libraryOrigin.copyRecursively(libraryDestination)
|
|
||||||
}
|
|
||||||
|
|
||||||
val what = listOfNotNull(
|
|
||||||
"standard library".takeIf { copyStdlib },
|
|
||||||
"endorsed libraries".takeIf { copyEndorsedLibs }
|
|
||||||
).joinToString(separator = " and ")
|
|
||||||
|
|
||||||
logProgress("Copied $what")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun copyTargetAsIs(leafTarget: LeafTarget) {
|
|
||||||
val librariesCount = originalLibraries.librariesByTargets.getValue(leafTarget).libraries.size
|
|
||||||
val librariesDestination = cachedLibrariesDestination.getValue(leafTarget)
|
|
||||||
|
|
||||||
val librariesSource = leafTarget.platformLibrariesSource
|
|
||||||
if (librariesSource.isDirectory) librariesSource.copyRecursively(librariesDestination)
|
|
||||||
|
|
||||||
logProgress("Copied $librariesCount libraries for ${leafTarget.prettyName}")
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun serializeModule(target: CommonizerTarget, moduleResult: ModuleResult) {
|
|
||||||
val librariesDestination = cachedLibrariesDestination.getValue(target)
|
|
||||||
|
|
||||||
when (moduleResult) {
|
|
||||||
is ModuleResult.Commonized -> {
|
|
||||||
val libraryName = moduleResult.libraryName
|
|
||||||
|
|
||||||
val manifestData = cachedManifestProviders.getValue(target).getManifest(libraryName)
|
|
||||||
val libraryDestination = librariesDestination.resolve(libraryName)
|
|
||||||
|
|
||||||
writeLibrary(moduleResult.metadata, manifestData, libraryDestination)
|
|
||||||
}
|
|
||||||
is ModuleResult.Missing -> {
|
|
||||||
val libraryName = moduleResult.libraryName
|
|
||||||
val missingModuleLocation = moduleResult.originalLocation
|
|
||||||
|
|
||||||
missingModuleLocation.copyRecursively(librariesDestination.resolve(libraryName))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun writeLibrary(
|
|
||||||
metadata: SerializedMetadata,
|
|
||||||
manifestData: NativeSensitiveManifestData,
|
|
||||||
libraryDestination: File
|
|
||||||
) {
|
|
||||||
val layout = KFile(libraryDestination.path).let { KotlinLibraryLayoutForWriter(it, it) }
|
|
||||||
val library = KotlinLibraryWriterImpl(
|
|
||||||
moduleName = manifestData.uniqueName,
|
|
||||||
versions = manifestData.versions,
|
|
||||||
builtInsPlatform = BuiltInsPlatform.NATIVE,
|
|
||||||
nativeTargets = emptyList(), // will be overwritten with NativeSensitiveManifestData.applyTo() below
|
|
||||||
nopack = true,
|
|
||||||
shortName = manifestData.shortName,
|
|
||||||
layout = layout
|
|
||||||
)
|
|
||||||
library.addMetadata(metadata)
|
|
||||||
manifestData.applyTo(library.base as BaseWriterImpl)
|
|
||||||
library.commit()
|
|
||||||
}
|
|
||||||
|
|
||||||
private val LeafTarget.platformLibrariesSource: File
|
|
||||||
get() = repository.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
|
|
||||||
.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR)
|
|
||||||
.resolve(name)
|
|
||||||
}
|
|
||||||
+21
-2
@@ -5,14 +5,33 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer.konan
|
package org.jetbrains.kotlin.descriptors.commonizer.konan
|
||||||
|
|
||||||
|
import com.intellij.util.containers.FactoryMap
|
||||||
import gnu.trove.THashMap
|
import gnu.trove.THashMap
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.LeafTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget
|
||||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||||
|
|
||||||
|
fun interface TargetedNativeManifestDataProvider {
|
||||||
|
fun getManifest(target: CommonizerTarget, libraryName: String): NativeSensitiveManifestData
|
||||||
|
}
|
||||||
|
|
||||||
internal interface NativeManifestDataProvider {
|
internal interface NativeManifestDataProvider {
|
||||||
fun getManifest(libraryName: String): NativeSensitiveManifestData
|
fun getManifest(libraryName: String): NativeSensitiveManifestData
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal fun TargetedNativeManifestDataProvider(libraries: AllNativeLibraries): TargetedNativeManifestDataProvider {
|
||||||
|
val cachedManifestProviders: Map<CommonizerTarget, NativeManifestDataProvider> = FactoryMap.create { target ->
|
||||||
|
when (target) {
|
||||||
|
is LeafCommonizerTarget -> libraries.librariesByTargets.getValue(target)
|
||||||
|
is SharedCommonizerTarget -> CommonNativeManifestDataProvider(libraries.librariesByTargets.values)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return TargetedNativeManifestDataProvider { target, libraryName ->
|
||||||
|
cachedManifestProviders.getValue(target).getManifest(libraryName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A separate Kotlin/Native library.
|
* A separate Kotlin/Native library.
|
||||||
*/
|
*/
|
||||||
@@ -37,7 +56,7 @@ internal class NativeLibrariesToCommonize(val libraries: List<NativeLibrary>) :
|
|||||||
|
|
||||||
internal class AllNativeLibraries(
|
internal class AllNativeLibraries(
|
||||||
val stdlib: NativeLibrary,
|
val stdlib: NativeLibrary,
|
||||||
val librariesByTargets: Map<LeafTarget, NativeLibrariesToCommonize>
|
val librariesByTargets: Map<LeafCommonizerTarget, NativeLibrariesToCommonize>
|
||||||
)
|
)
|
||||||
|
|
||||||
internal class CommonNativeManifestDataProvider(
|
internal class CommonNativeManifestDataProvider(
|
||||||
|
|||||||
+1
-1
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.library.impl.BaseWriterImpl
|
|||||||
* The set of properties in manifest of Kotlin/Native library that should be
|
* The set of properties in manifest of Kotlin/Native library that should be
|
||||||
* preserved in commonized libraries (both for "common" and platform-specific library parts).
|
* preserved in commonized libraries (both for "common" and platform-specific library parts).
|
||||||
*/
|
*/
|
||||||
internal data class NativeSensitiveManifestData(
|
data class NativeSensitiveManifestData(
|
||||||
val uniqueName: String,
|
val uniqueName: String,
|
||||||
val versions: KotlinLibraryVersioning,
|
val versions: KotlinLibraryVersioning,
|
||||||
val dependencies: List<String>,
|
val dependencies: List<String>,
|
||||||
|
|||||||
+2
-4
@@ -6,10 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
|
package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.LeafTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.*
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.ModuleInfo
|
import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.ModuleInfo
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerParameters
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.TargetProvider
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
|
||||||
@@ -49,7 +47,7 @@ class CirTreeMerger(
|
|||||||
) {
|
) {
|
||||||
class CirTreeMergeResult(
|
class CirTreeMergeResult(
|
||||||
val root: CirRootNode,
|
val root: CirRootNode,
|
||||||
val missingModuleInfos: Map<LeafTarget, Collection<ModuleInfo>>
|
val missingModuleInfos: Map<LeafCommonizerTarget, Collection<ModuleInfo>>
|
||||||
)
|
)
|
||||||
|
|
||||||
private val size = parameters.targetProviders.size
|
private val size = parameters.targetProviders.size
|
||||||
|
|||||||
+2
-2
@@ -8,7 +8,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.mergedtree
|
|||||||
import gnu.trove.THashMap
|
import gnu.trove.THashMap
|
||||||
import gnu.trove.THashSet
|
import gnu.trove.THashSet
|
||||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.SharedTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirPackageName
|
||||||
@@ -25,7 +25,7 @@ class CirKnownClassifiers(
|
|||||||
) {
|
) {
|
||||||
// a shortcut for fast access
|
// a shortcut for fast access
|
||||||
val commonDependencies: CirProvidedClassifiers =
|
val commonDependencies: CirProvidedClassifiers =
|
||||||
dependencies.filterKeys { it is SharedTarget }.values.singleOrNull() ?: CirProvidedClassifiers.EMPTY
|
dependencies.filterKeys { it is SharedCommonizerTarget }.values.singleOrNull() ?: CirProvidedClassifiers.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
interface CirCommonizedClassifiers {
|
interface CirCommonizedClassifiers {
|
||||||
|
|||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer.repository
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.NativeLibraryLoader
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeLibrary
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
import java.io.File
|
||||||
|
|
||||||
|
internal class FilesRepository(
|
||||||
|
private val libraryFiles: Set<File>,
|
||||||
|
private val libraryLoader: NativeLibraryLoader
|
||||||
|
) : Repository {
|
||||||
|
|
||||||
|
private val librariesByTarget: Map<CommonizerTarget, Set<NativeLibrary>> by lazy {
|
||||||
|
libraryFiles
|
||||||
|
.map(libraryLoader::invoke)
|
||||||
|
.groupBy { library -> CommonizerTarget(library.manifestData.nativeTargets.map(::konanTargetOrThrow)) }
|
||||||
|
.mapValues { (_, list) -> list.toSet() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLibraries(target: LeafCommonizerTarget): Set<NativeLibrary> {
|
||||||
|
return librariesByTarget[target].orEmpty()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun konanTargetOrThrow(value: String): KonanTarget {
|
||||||
|
return KonanTarget.predefinedTargets[value] ?: error("Unexpected KonanTarget $value")
|
||||||
|
}
|
||||||
+37
@@ -0,0 +1,37 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer.repository
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.KonanDistribution
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.NativeLibraryLoader
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeLibrary
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.platformLibsDir
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
|
||||||
|
internal class KonanDistributionRepository(
|
||||||
|
konanDistribution: KonanDistribution,
|
||||||
|
targets: Set<KonanTarget>,
|
||||||
|
libraryLoader: NativeLibraryLoader,
|
||||||
|
) : Repository {
|
||||||
|
|
||||||
|
private val librariesByTarget: Map<LeafCommonizerTarget, Lazy<Set<NativeLibrary>>> =
|
||||||
|
targets.map(::LeafCommonizerTarget).associateWith { target ->
|
||||||
|
lazy {
|
||||||
|
konanDistribution.platformLibsDir
|
||||||
|
.resolve(target.name)
|
||||||
|
.takeIf { it.isDirectory }
|
||||||
|
?.listFiles()
|
||||||
|
.orEmpty().toList()
|
||||||
|
.map { libraryLoader(it) }
|
||||||
|
.toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun getLibraries(target: LeafCommonizerTarget): Set<NativeLibrary> {
|
||||||
|
return librariesByTarget[target]?.value ?: error("Missing target $target")
|
||||||
|
}
|
||||||
|
}
|
||||||
+32
@@ -0,0 +1,32 @@
|
|||||||
|
/*
|
||||||
|
* 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.descriptors.commonizer.repository
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeLibrary
|
||||||
|
|
||||||
|
internal interface Repository {
|
||||||
|
fun getLibraries(target: LeafCommonizerTarget): Set<NativeLibrary>
|
||||||
|
}
|
||||||
|
|
||||||
|
internal operator fun Repository.plus(other: Repository): Repository {
|
||||||
|
if (this is CompositeRepository) {
|
||||||
|
return CompositeRepository(this.repositories + other)
|
||||||
|
}
|
||||||
|
return CompositeRepository(listOf(this, other))
|
||||||
|
}
|
||||||
|
|
||||||
|
private class CompositeRepository(val repositories: Iterable<Repository>) : Repository {
|
||||||
|
override fun getLibraries(target: LeafCommonizerTarget): Set<NativeLibrary> {
|
||||||
|
return repositories.map { it.getLibraries(target) }.flatten().toSet()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
internal object EmptyRepository : Repository {
|
||||||
|
override fun getLibraries(target: LeafCommonizerTarget): Set<NativeLibrary> {
|
||||||
|
return emptySet()
|
||||||
|
}
|
||||||
|
}
|
||||||
+14
@@ -5,6 +5,20 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.descriptors.commonizer.stats
|
package org.jetbrains.kotlin.descriptors.commonizer.stats
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
|
|
||||||
|
fun StatsCollector(type: StatsType, targets: List<KonanTarget>): StatsCollector? {
|
||||||
|
return when (type) {
|
||||||
|
StatsType.RAW -> RawStatsCollector(targets)
|
||||||
|
StatsType.AGGREGATED -> AggregatedStatsCollector(targets)
|
||||||
|
StatsType.NONE -> null
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
enum class StatsType {
|
||||||
|
RAW, AGGREGATED, NONE;
|
||||||
|
}
|
||||||
|
|
||||||
interface StatsCollector {
|
interface StatsCollector {
|
||||||
data class StatsKey(
|
data class StatsKey(
|
||||||
val id: String,
|
val id: String,
|
||||||
|
|||||||
+30
-29
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.descriptors.PackageFragmentProvider
|
|||||||
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.ModuleResult
|
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.ModuleResult
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.Status
|
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.Status
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.SourceModuleRoot.Companion.SHARED_TARGET_NAME
|
import org.jetbrains.kotlin.descriptors.commonizer.SourceModuleRoot.Companion.SHARED_TARGET_NAME
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.TargetedNativeManifestDataProvider
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ClassCollector
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.ClassCollector
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.FunctionCollector
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.FunctionCollector
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.collectMembers
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.collectMembers
|
||||||
@@ -75,7 +76,7 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
|
|||||||
runCommonization(analyzedModules.toCommonizerParameters(results))
|
runCommonization(analyzedModules.toCommonizerParameters(results))
|
||||||
assertEquals(Status.DONE, results.status)
|
assertEquals(Status.DONE, results.status)
|
||||||
|
|
||||||
val sharedTarget: SharedTarget = analyzedModules.sharedTarget
|
val sharedTarget: SharedCommonizerTarget = analyzedModules.sharedTarget
|
||||||
assertEquals(sharedTarget, results.sharedTarget)
|
assertEquals(sharedTarget, results.sharedTarget)
|
||||||
|
|
||||||
val sharedModuleAsExpected: SerializedMetadata = analyzedModules.commonizedModules.getValue(sharedTarget)
|
val sharedModuleAsExpected: SerializedMetadata = analyzedModules.commonizedModules.getValue(sharedTarget)
|
||||||
@@ -84,7 +85,7 @@ abstract class AbstractCommonizationFromSourcesTest : KtUsefulTestCase() {
|
|||||||
|
|
||||||
assertModulesAreEqual(sharedModuleAsExpected, sharedModuleByCommonizer, sharedTarget)
|
assertModulesAreEqual(sharedModuleAsExpected, sharedModuleByCommonizer, sharedTarget)
|
||||||
|
|
||||||
val leafTargets: Set<LeafTarget> = analyzedModules.leafTargets
|
val leafTargets: Set<LeafCommonizerTarget> = analyzedModules.leafTargets
|
||||||
assertEquals(leafTargets, results.leafTargets)
|
assertEquals(leafTargets, results.leafTargets)
|
||||||
|
|
||||||
for (leafTarget in leafTargets) {
|
for (leafTarget in leafTargets) {
|
||||||
@@ -116,18 +117,18 @@ private data class SourceModuleRoot(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class SourceModuleRoots(
|
private class SourceModuleRoots(
|
||||||
val originalRoots: Map<LeafTarget, SourceModuleRoot>,
|
val originalRoots: Map<LeafCommonizerTarget, SourceModuleRoot>,
|
||||||
val commonizedRoots: Map<CommonizerTarget, SourceModuleRoot>,
|
val commonizedRoots: Map<CommonizerTarget, SourceModuleRoot>,
|
||||||
val dependencyRoots: Map<CommonizerTarget, SourceModuleRoot>
|
val dependencyRoots: Map<CommonizerTarget, SourceModuleRoot>
|
||||||
) {
|
) {
|
||||||
val leafTargets: Set<LeafTarget> = originalRoots.keys
|
val leafTargets: Set<LeafCommonizerTarget> = originalRoots.keys
|
||||||
val sharedTarget: SharedTarget
|
val sharedTarget: SharedCommonizerTarget
|
||||||
|
|
||||||
init {
|
init {
|
||||||
check(leafTargets.size >= 2)
|
check(leafTargets.size >= 2)
|
||||||
check(leafTargets.none { it.name == SHARED_TARGET_NAME })
|
check(leafTargets.none { it.name == SHARED_TARGET_NAME })
|
||||||
|
|
||||||
val sharedTargets = commonizedRoots.keys.filterIsInstance<SharedTarget>()
|
val sharedTargets = commonizedRoots.keys.filterIsInstance<SharedCommonizerTarget>()
|
||||||
check(sharedTargets.size == 1)
|
check(sharedTargets.size == 1)
|
||||||
|
|
||||||
sharedTarget = sharedTargets.single()
|
sharedTarget = sharedTargets.single()
|
||||||
@@ -140,10 +141,10 @@ private class SourceModuleRoots(
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun load(dataDir: File): SourceModuleRoots = try {
|
fun load(dataDir: File): SourceModuleRoots = try {
|
||||||
val originalRoots = listRoots(dataDir, ORIGINAL_ROOTS_DIR).mapKeys { LeafTarget(it.key) }
|
val originalRoots = listRoots(dataDir, ORIGINAL_ROOTS_DIR).mapKeys { LeafCommonizerTarget(it.key) }
|
||||||
|
|
||||||
val leafTargets = originalRoots.keys
|
val leafTargets = originalRoots.keys
|
||||||
val sharedTarget = SharedTarget(leafTargets)
|
val sharedTarget = SharedCommonizerTarget(leafTargets)
|
||||||
|
|
||||||
fun getTarget(targetName: String): CommonizerTarget =
|
fun getTarget(targetName: String): CommonizerTarget =
|
||||||
if (targetName == SHARED_TARGET_NAME) sharedTarget else leafTargets.first { it.name == targetName }
|
if (targetName == SHARED_TARGET_NAME) sharedTarget else leafTargets.first { it.name == targetName }
|
||||||
@@ -185,41 +186,41 @@ private class AnalyzedModules(
|
|||||||
val commonizedModules: Map<CommonizerTarget, SerializedMetadata>,
|
val commonizedModules: Map<CommonizerTarget, SerializedMetadata>,
|
||||||
val dependencyModules: Map<CommonizerTarget, List<ModuleDescriptor>>
|
val dependencyModules: Map<CommonizerTarget, List<ModuleDescriptor>>
|
||||||
) {
|
) {
|
||||||
val leafTargets: Set<LeafTarget>
|
val leafTargets: Set<LeafCommonizerTarget>
|
||||||
val sharedTarget: SharedTarget
|
val sharedTarget: SharedCommonizerTarget
|
||||||
|
|
||||||
init {
|
init {
|
||||||
originalModules.keys.let { targets ->
|
originalModules.keys.let { targets ->
|
||||||
check(targets.isNotEmpty())
|
check(targets.isNotEmpty())
|
||||||
|
|
||||||
leafTargets = targets.filterIsInstance<LeafTarget>().toSet()
|
leafTargets = targets.filterIsInstance<LeafCommonizerTarget>().toSet()
|
||||||
check(targets.size == leafTargets.size)
|
check(targets.size == leafTargets.size)
|
||||||
}
|
}
|
||||||
|
|
||||||
sharedTarget = SharedTarget(leafTargets)
|
sharedTarget = SharedCommonizerTarget(leafTargets)
|
||||||
val allTargets = leafTargets + sharedTarget
|
val allTargets = leafTargets + sharedTarget
|
||||||
|
|
||||||
check(commonizedModules.keys == allTargets)
|
check(commonizedModules.keys == allTargets)
|
||||||
check(allTargets.containsAll(dependencyModules.keys))
|
check(allTargets.containsAll(dependencyModules.keys))
|
||||||
}
|
}
|
||||||
|
|
||||||
fun toCommonizerParameters(resultsConsumer: ResultsConsumer) =
|
fun toCommonizerParameters(
|
||||||
CommonizerParameters().also { parameters ->
|
resultsConsumer: ResultsConsumer, manifestDataProvider: TargetedNativeManifestDataProvider = MockNativeManifestDataProvider()
|
||||||
parameters.resultsConsumer = resultsConsumer
|
) = CommonizerParameters(resultsConsumer, manifestDataProvider).also { parameters ->
|
||||||
parameters.dependencyModulesProvider = dependencyModules[sharedTarget]?.let(MockModulesProvider::create)
|
parameters.dependencyModulesProvider = dependencyModules[sharedTarget]?.let(MockModulesProvider::create)
|
||||||
|
|
||||||
leafTargets.forEach { leafTarget ->
|
leafTargets.forEach { leafTarget ->
|
||||||
val originalModule = originalModules.getValue(leafTarget)
|
val originalModule = originalModules.getValue(leafTarget)
|
||||||
|
|
||||||
parameters.addTarget(
|
parameters.addTarget(
|
||||||
TargetProvider(
|
TargetProvider(
|
||||||
target = leafTarget,
|
target = leafTarget,
|
||||||
modulesProvider = MockModulesProvider.create(originalModule),
|
modulesProvider = MockModulesProvider.create(originalModule),
|
||||||
dependencyModulesProvider = dependencyModules[leafTarget]?.let(MockModulesProvider::create)
|
dependencyModulesProvider = dependencyModules[leafTarget]?.let(MockModulesProvider::create)
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
fun create(
|
fun create(
|
||||||
@@ -242,7 +243,7 @@ private class AnalyzedModules(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createDependencyModules(
|
private fun createDependencyModules(
|
||||||
sharedTarget: SharedTarget,
|
sharedTarget: SharedCommonizerTarget,
|
||||||
dependencyRoots: Map<out CommonizerTarget, SourceModuleRoot>,
|
dependencyRoots: Map<out CommonizerTarget, SourceModuleRoot>,
|
||||||
parentDisposable: Disposable
|
parentDisposable: Disposable
|
||||||
): Pair<Map<CommonizerTarget, List<ModuleDescriptor>>, AnalyzedModuleDependencies> {
|
): Pair<Map<CommonizerTarget, List<ModuleDescriptor>>, AnalyzedModuleDependencies> {
|
||||||
@@ -263,7 +264,7 @@ private class AnalyzedModules(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createModules(
|
private fun createModules(
|
||||||
sharedTarget: SharedTarget,
|
sharedTarget: SharedCommonizerTarget,
|
||||||
moduleRoots: Map<out CommonizerTarget, SourceModuleRoot>,
|
moduleRoots: Map<out CommonizerTarget, SourceModuleRoot>,
|
||||||
dependencies: AnalyzedModuleDependencies,
|
dependencies: AnalyzedModuleDependencies,
|
||||||
parentDisposable: Disposable,
|
parentDisposable: Disposable,
|
||||||
@@ -290,7 +291,7 @@ private class AnalyzedModules(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun createModule(
|
private fun createModule(
|
||||||
sharedTarget: SharedTarget,
|
sharedTarget: SharedCommonizerTarget,
|
||||||
currentTarget: CommonizerTarget,
|
currentTarget: CommonizerTarget,
|
||||||
moduleRoot: SourceModuleRoot,
|
moduleRoot: SourceModuleRoot,
|
||||||
dependencies: AnalyzedModuleDependencies,
|
dependencies: AnalyzedModuleDependencies,
|
||||||
@@ -338,7 +339,7 @@ private class AnalyzedModules(
|
|||||||
}
|
}
|
||||||
|
|
||||||
private class DependenciesContainerImpl(
|
private class DependenciesContainerImpl(
|
||||||
sharedTarget: SharedTarget,
|
sharedTarget: SharedCommonizerTarget,
|
||||||
currentTarget: CommonizerTarget,
|
currentTarget: CommonizerTarget,
|
||||||
dependencies: AnalyzedModuleDependencies
|
dependencies: AnalyzedModuleDependencies
|
||||||
) : CommonDependenciesContainer {
|
) : CommonDependenciesContainer {
|
||||||
|
|||||||
+14
-12
@@ -7,8 +7,11 @@ package org.jetbrains.kotlin.descriptors.commonizer
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.ModuleResult
|
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.ModuleResult
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.Status
|
import org.jetbrains.kotlin.descriptors.commonizer.ResultsConsumer.Status
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.CommonNativeManifestDataProvider
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.TargetedNativeManifestDataProvider
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.MockResultsConsumer
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.MockResultsConsumer
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.utils.MockModulesProvider
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.MockModulesProvider
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.utils.MockNativeManifestDataProvider
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import kotlin.contracts.ExperimentalContracts
|
import kotlin.contracts.ExperimentalContracts
|
||||||
import kotlin.test.assertEquals
|
import kotlin.test.assertEquals
|
||||||
@@ -62,20 +65,19 @@ class CommonizerFacadeTest {
|
|||||||
)
|
)
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
private fun Map<String, List<String>>.toCommonizerParameters(resultsConsumer: ResultsConsumer) =
|
private fun Map<String, List<String>>.toCommonizerParameters(
|
||||||
CommonizerParameters().also { parameters ->
|
resultsConsumer: ResultsConsumer, manifestDataProvider: TargetedNativeManifestDataProvider = MockNativeManifestDataProvider()
|
||||||
parameters.resultsConsumer = resultsConsumer
|
) = CommonizerParameters(resultsConsumer, manifestDataProvider).also { parameters ->
|
||||||
|
forEach { (targetName, moduleNames) ->
|
||||||
forEach { (targetName, moduleNames) ->
|
parameters.addTarget(
|
||||||
parameters.addTarget(
|
TargetProvider(
|
||||||
TargetProvider(
|
target = LeafCommonizerTarget(targetName),
|
||||||
target = LeafTarget(targetName),
|
modulesProvider = MockModulesProvider.create(moduleNames),
|
||||||
modulesProvider = MockModulesProvider.create(moduleNames),
|
dependencyModulesProvider = null
|
||||||
dependencyModulesProvider = null
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
}
|
)
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun doTestNothingToCommonize(originalModules: Map<String, List<String>>) {
|
private fun doTestNothingToCommonize(originalModules: Map<String, List<String>>) {
|
||||||
val results = MockResultsConsumer()
|
val results = MockResultsConsumer()
|
||||||
|
|||||||
-70
@@ -1,70 +0,0 @@
|
|||||||
/*
|
|
||||||
* Copyright 2010-2021 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.descriptors.commonizer
|
|
||||||
|
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
|
||||||
import org.junit.Test
|
|
||||||
import kotlin.test.assertEquals
|
|
||||||
|
|
||||||
class CommonizerTargetTest {
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun leafTargetNames() {
|
|
||||||
listOf(
|
|
||||||
Triple("foo", "[foo]", FOO),
|
|
||||||
Triple("bar", "[bar]", BAR),
|
|
||||||
Triple("baz_123", "[baz_123]", BAZ),
|
|
||||||
).forEach { (name, prettyName, target: LeafTarget) ->
|
|
||||||
assertEquals(name, target.name)
|
|
||||||
assertEquals(prettyName, target.prettyName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun sharedTargetNames() {
|
|
||||||
listOf(
|
|
||||||
"[foo]" to SharedTarget(FOO),
|
|
||||||
"[foo, bar]" to SharedTarget(FOO, BAR),
|
|
||||||
"[foo, bar, baz_123]" to SharedTarget(FOO, BAR, BAZ),
|
|
||||||
"[foo, bar, baz_123, [foo, bar]]" to SharedTarget(FOO, BAR, BAZ, SharedTarget(FOO, BAR))
|
|
||||||
).forEach { (prettyName, target: SharedTarget) ->
|
|
||||||
assertEquals(prettyName, target.prettyName)
|
|
||||||
assertEquals(prettyName, target.name)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun prettyCommonizedName() {
|
|
||||||
val sharedTarget = SharedTarget(FOO, BAR, BAZ)
|
|
||||||
listOf(
|
|
||||||
"[foo(*), bar, baz_123]" to FOO,
|
|
||||||
"[foo, bar(*), baz_123]" to BAR,
|
|
||||||
"[foo, bar, baz_123(*)]" to BAZ,
|
|
||||||
"[foo, bar, baz_123]" to sharedTarget
|
|
||||||
).forEach { (prettyCommonizerName, target: CommonizerTarget) ->
|
|
||||||
assertEquals(prettyCommonizerName, target.prettyCommonizedName(sharedTarget))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalStateException::class)
|
|
||||||
fun prettyCommonizedNameFailure() {
|
|
||||||
FOO.prettyCommonizedName(SharedTarget(BAR, BAZ))
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test(expected = IllegalArgumentException::class)
|
|
||||||
fun sharedTargetNoInnerTargets() {
|
|
||||||
SharedTarget(emptySet())
|
|
||||||
}
|
|
||||||
|
|
||||||
private companion object {
|
|
||||||
val FOO = LeafTarget("foo")
|
|
||||||
val BAR = LeafTarget("bar", KonanTarget.IOS_X64)
|
|
||||||
val BAZ = LeafTarget("baz_123", KonanTarget.MACOS_X64)
|
|
||||||
|
|
||||||
@Suppress("TestFunctionName")
|
|
||||||
fun SharedTarget(vararg targets: CommonizerTarget) = SharedTarget(linkedSetOf(*targets))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+44
-72
@@ -6,8 +6,8 @@
|
|||||||
package org.jetbrains.kotlin.descriptors.commonizer.core
|
package org.jetbrains.kotlin.descriptors.commonizer.core
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.LeafTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.SharedTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirRoot
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirRoot
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirRootFactory
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirRootFactory
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
@@ -17,114 +17,86 @@ class RootCommonizerTest : AbstractCommonizerTest<CirRoot, CirRoot>() {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun allAreNative() = doTestSuccess(
|
fun allAreNative() = doTestSuccess(
|
||||||
expected = SharedTarget(
|
expected = SharedCommonizerTarget(
|
||||||
setOf(
|
setOf(
|
||||||
LeafTarget("ios_x64", KonanTarget.IOS_X64),
|
LeafCommonizerTarget(KonanTarget.IOS_X64),
|
||||||
LeafTarget("ios_arm64", KonanTarget.IOS_ARM64),
|
LeafCommonizerTarget(KonanTarget.IOS_ARM64),
|
||||||
LeafTarget("ios_arm32", KonanTarget.IOS_ARM32)
|
LeafCommonizerTarget(KonanTarget.IOS_ARM32)
|
||||||
)
|
)
|
||||||
).toMock(),
|
).toMock(),
|
||||||
LeafTarget("ios_x64", KonanTarget.IOS_X64).toMock(),
|
LeafCommonizerTarget(KonanTarget.IOS_X64).toMock(),
|
||||||
LeafTarget("ios_arm64", KonanTarget.IOS_ARM64).toMock(),
|
LeafCommonizerTarget(KonanTarget.IOS_ARM64).toMock(),
|
||||||
LeafTarget("ios_arm32", KonanTarget.IOS_ARM32).toMock()
|
LeafCommonizerTarget(KonanTarget.IOS_ARM32).toMock()
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun jvmAndNative1() = doTestSuccess(
|
fun jvmAndNative1() = doTestSuccess(
|
||||||
expected = SharedTarget(
|
expected = SharedCommonizerTarget(
|
||||||
setOf(
|
setOf(
|
||||||
LeafTarget("jvm1"),
|
LeafCommonizerTarget("jvm1"),
|
||||||
LeafTarget("ios_x64", KonanTarget.IOS_X64),
|
LeafCommonizerTarget(KonanTarget.IOS_X64),
|
||||||
LeafTarget("jvm2")
|
LeafCommonizerTarget("jvm2")
|
||||||
)
|
)
|
||||||
).toMock(),
|
).toMock(),
|
||||||
LeafTarget("jvm1").toMock(),
|
LeafCommonizerTarget("jvm1").toMock(),
|
||||||
LeafTarget("ios_x64", KonanTarget.IOS_X64).toMock(),
|
LeafCommonizerTarget(KonanTarget.IOS_X64).toMock(),
|
||||||
LeafTarget("jvm2").toMock()
|
LeafCommonizerTarget("jvm2").toMock()
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun jvmAndNative2() = doTestSuccess(
|
fun jvmAndNative2() = doTestSuccess(
|
||||||
expected = SharedTarget(
|
expected = SharedCommonizerTarget(
|
||||||
setOf(
|
setOf(
|
||||||
LeafTarget("ios_x64", KonanTarget.IOS_X64),
|
LeafCommonizerTarget(KonanTarget.IOS_X64),
|
||||||
LeafTarget("jvm"),
|
LeafCommonizerTarget("jvm"),
|
||||||
LeafTarget("ios_arm64", KonanTarget.IOS_ARM64)
|
LeafCommonizerTarget(KonanTarget.IOS_ARM64)
|
||||||
)
|
)
|
||||||
).toMock(),
|
).toMock(),
|
||||||
LeafTarget("ios_x64", KonanTarget.IOS_X64).toMock(),
|
LeafCommonizerTarget(KonanTarget.IOS_X64).toMock(),
|
||||||
LeafTarget("jvm").toMock(),
|
LeafCommonizerTarget("jvm").toMock(),
|
||||||
LeafTarget("ios_arm64", KonanTarget.IOS_ARM64).toMock()
|
LeafCommonizerTarget(KonanTarget.IOS_ARM64).toMock()
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noNative1() = doTestSuccess(
|
fun noNative1() = doTestSuccess(
|
||||||
expected = SharedTarget(
|
expected = SharedCommonizerTarget(
|
||||||
setOf(
|
setOf(
|
||||||
LeafTarget("default1"),
|
LeafCommonizerTarget("default1"),
|
||||||
LeafTarget("default2"),
|
LeafCommonizerTarget("default2"),
|
||||||
LeafTarget("default3")
|
LeafCommonizerTarget("default3")
|
||||||
)
|
)
|
||||||
).toMock(),
|
).toMock(),
|
||||||
LeafTarget("default1").toMock(),
|
LeafCommonizerTarget("default1").toMock(),
|
||||||
LeafTarget("default2").toMock(),
|
LeafCommonizerTarget("default2").toMock(),
|
||||||
LeafTarget("default3").toMock()
|
LeafCommonizerTarget("default3").toMock()
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noNative2() = doTestSuccess(
|
fun noNative2() = doTestSuccess(
|
||||||
expected = SharedTarget(
|
expected = SharedCommonizerTarget(
|
||||||
setOf(
|
setOf(
|
||||||
LeafTarget("jvm1"),
|
LeafCommonizerTarget("jvm1"),
|
||||||
LeafTarget("default"),
|
LeafCommonizerTarget("default"),
|
||||||
LeafTarget("jvm2")
|
LeafCommonizerTarget("jvm2")
|
||||||
)
|
)
|
||||||
).toMock(),
|
).toMock(),
|
||||||
LeafTarget("jvm1").toMock(),
|
LeafCommonizerTarget("jvm1").toMock(),
|
||||||
LeafTarget("default").toMock(),
|
LeafCommonizerTarget("default").toMock(),
|
||||||
LeafTarget("jvm2").toMock()
|
LeafCommonizerTarget("jvm2").toMock()
|
||||||
)
|
)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun noNative3() = doTestSuccess(
|
fun noNative3() = doTestSuccess(
|
||||||
expected = SharedTarget(
|
expected = SharedCommonizerTarget(
|
||||||
setOf(
|
setOf(
|
||||||
LeafTarget("jvm1"),
|
LeafCommonizerTarget("jvm1"),
|
||||||
LeafTarget("jvm2"),
|
LeafCommonizerTarget("jvm2"),
|
||||||
LeafTarget("jvm3")
|
LeafCommonizerTarget("jvm3")
|
||||||
)
|
)
|
||||||
).toMock(),
|
).toMock(),
|
||||||
LeafTarget("jvm1").toMock(),
|
LeafCommonizerTarget("jvm1").toMock(),
|
||||||
LeafTarget("jvm2").toMock(),
|
LeafCommonizerTarget("jvm2").toMock(),
|
||||||
LeafTarget("jvm3").toMock()
|
LeafCommonizerTarget("jvm3").toMock()
|
||||||
)
|
|
||||||
|
|
||||||
@Test(expected = ObjectsNotEqual::class)
|
|
||||||
fun misconfiguration1() = doTestSuccess(
|
|
||||||
expected = SharedTarget(
|
|
||||||
setOf(
|
|
||||||
LeafTarget("ios_x64", KonanTarget.IOS_X64),
|
|
||||||
LeafTarget("ios_arm64", KonanTarget.IOS_ARM64),
|
|
||||||
LeafTarget("ios_arm32", KonanTarget.IOS_ARM32)
|
|
||||||
)
|
|
||||||
).toMock(),
|
|
||||||
LeafTarget("ios_x64").toMock(), // KonanTarget is missing here!
|
|
||||||
LeafTarget("ios_arm64", KonanTarget.IOS_ARM64).toMock(),
|
|
||||||
LeafTarget("ios_arm32", KonanTarget.IOS_ARM32).toMock()
|
|
||||||
)
|
|
||||||
|
|
||||||
@Test(expected = ObjectsNotEqual::class)
|
|
||||||
fun misconfiguration2() = doTestSuccess(
|
|
||||||
expected = SharedTarget(
|
|
||||||
setOf(
|
|
||||||
LeafTarget("jvm1"),
|
|
||||||
LeafTarget("jvm2"),
|
|
||||||
LeafTarget("jvm3")
|
|
||||||
)
|
|
||||||
).toMock(),
|
|
||||||
LeafTarget("jvm1", KonanTarget.IOS_X64).toMock(), // mistakenly specified KonanTarget!
|
|
||||||
LeafTarget("jvm2").toMock(),
|
|
||||||
LeafTarget("jvm3").toMock()
|
|
||||||
)
|
)
|
||||||
|
|
||||||
override fun createCommonizer() = RootCommonizer()
|
override fun createCommonizer() = RootCommonizer()
|
||||||
|
|||||||
+3
-3
@@ -7,8 +7,8 @@ package org.jetbrains.kotlin.descriptors.commonizer.core
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.LeafTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.LeafCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.SharedTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.SharedCommonizerTarget
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirType
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirType
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirClassFactory
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirClassFactory
|
||||||
@@ -537,7 +537,7 @@ class TypeCommonizerTest : AbstractCommonizerTest<CirType, CirType>() {
|
|||||||
fun areEqual(classifiers: CirKnownClassifiers, a: CirType, b: CirType): Boolean =
|
fun areEqual(classifiers: CirKnownClassifiers, a: CirType, b: CirType): Boolean =
|
||||||
TypeCommonizer(classifiers).run { commonizeWith(a) && commonizeWith(b) }
|
TypeCommonizer(classifiers).run { commonizeWith(a) && commonizeWith(b) }
|
||||||
|
|
||||||
private val FAKE_SHARED_TARGET = SharedTarget(setOf(LeafTarget("a"), LeafTarget("b")))
|
private val FAKE_SHARED_TARGET = SharedCommonizerTarget(setOf(LeafCommonizerTarget("a"), LeafCommonizerTarget("b")))
|
||||||
|
|
||||||
private fun CirKnownClassifiers.classNode(classId: CirEntityId, computation: () -> CirClassNode) =
|
private fun CirKnownClassifiers.classNode(classId: CirEntityId, computation: () -> CirClassNode) =
|
||||||
commonized.classNode(classId) ?: computation()
|
commonized.classNode(classId) ?: computation()
|
||||||
|
|||||||
+2
-1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.descriptors.commonizer.utils
|
|||||||
|
|
||||||
import kotlinx.metadata.klib.KlibModuleMetadata
|
import kotlinx.metadata.klib.KlibModuleMetadata
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
import org.jetbrains.kotlin.descriptors.commonizer.CommonizerTarget
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.identityString
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator
|
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.Mismatch
|
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.Mismatch
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.Result
|
import org.jetbrains.kotlin.descriptors.commonizer.metadata.utils.MetadataDeclarationsComparator.Result
|
||||||
@@ -38,7 +39,7 @@ fun assertModulesAreEqual(reference: SerializedMetadata, generated: SerializedMe
|
|||||||
val digitCount = mismatches.size.toString().length
|
val digitCount = mismatches.size.toString().length
|
||||||
|
|
||||||
val failureMessage = buildString {
|
val failureMessage = buildString {
|
||||||
appendLine("${mismatches.size} mismatches found while comparing reference module ${referenceModule.name} (A) and generated module ${generatedModule.name} (B) for target ${target.prettyName}:")
|
appendLine("${mismatches.size} mismatches found while comparing reference module ${referenceModule.name} (A) and generated module ${generatedModule.name} (B) for target ${target.identityString}:")
|
||||||
mismatches.forEachIndexed { index, mismatch ->
|
mismatches.forEachIndexed { index, mismatch ->
|
||||||
appendLine((index + 1).toString().padStart(digitCount, ' ') + ". " + mismatch)
|
appendLine((index + 1).toString().padStart(digitCount, ' ') + ". " + mismatch)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,9 +16,12 @@ import org.jetbrains.kotlin.descriptors.commonizer.ModulesProvider.ModuleInfo
|
|||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirEntityId
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.CirName
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirClassFactory
|
import org.jetbrains.kotlin.descriptors.commonizer.cir.factory.CirClassFactory
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.NativeSensitiveManifestData
|
||||||
|
import org.jetbrains.kotlin.descriptors.commonizer.konan.TargetedNativeManifestDataProvider
|
||||||
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
|
import org.jetbrains.kotlin.descriptors.commonizer.mergedtree.*
|
||||||
import org.jetbrains.kotlin.descriptors.impl.AbstractTypeAliasDescriptor
|
import org.jetbrains.kotlin.descriptors.impl.AbstractTypeAliasDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
import org.jetbrains.kotlin.descriptors.impl.ClassDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.library.KotlinLibraryVersioning
|
||||||
import org.jetbrains.kotlin.library.SerializedMetadata
|
import org.jetbrains.kotlin.library.SerializedMetadata
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.parentOrNull
|
import org.jetbrains.kotlin.name.parentOrNull
|
||||||
@@ -204,8 +207,8 @@ internal class MockResultsConsumer : ResultsConsumer {
|
|||||||
val modulesByTargets: Map<CommonizerTarget, Collection<ModuleResult>>
|
val modulesByTargets: Map<CommonizerTarget, Collection<ModuleResult>>
|
||||||
get() = _modulesByTargets.mapValues { it.value.values }
|
get() = _modulesByTargets.mapValues { it.value.values }
|
||||||
|
|
||||||
val sharedTarget: SharedTarget by lazy { modulesByTargets.keys.filterIsInstance<SharedTarget>().single() }
|
val sharedTarget: SharedCommonizerTarget by lazy { modulesByTargets.keys.filterIsInstance<SharedCommonizerTarget>().single() }
|
||||||
val leafTargets: Set<LeafTarget> by lazy { modulesByTargets.keys.filterIsInstance<LeafTarget>().toSet() }
|
val leafTargets: Set<LeafCommonizerTarget> by lazy { modulesByTargets.keys.filterIsInstance<LeafCommonizerTarget>().toSet() }
|
||||||
|
|
||||||
private val finishedTargets = mutableSetOf<CommonizerTarget>()
|
private val finishedTargets = mutableSetOf<CommonizerTarget>()
|
||||||
|
|
||||||
@@ -232,3 +235,25 @@ internal class MockResultsConsumer : ResultsConsumer {
|
|||||||
this.status = status
|
this.status = status
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun MockNativeManifestDataProvider(
|
||||||
|
uniqueName: String = "mock",
|
||||||
|
versions: KotlinLibraryVersioning = KotlinLibraryVersioning(null, null, null, null, null),
|
||||||
|
dependencies: List<String> = emptyList(),
|
||||||
|
isInterop: Boolean = true,
|
||||||
|
packageFqName: String? = "mock",
|
||||||
|
exportForwardDeclarations: List<String> = emptyList(),
|
||||||
|
nativeTargets: Collection<String> = emptyList(),
|
||||||
|
shortName: String? = "mock"
|
||||||
|
): TargetedNativeManifestDataProvider = TargetedNativeManifestDataProvider { target, libraryName ->
|
||||||
|
NativeSensitiveManifestData(
|
||||||
|
uniqueName = uniqueName,
|
||||||
|
versions = versions,
|
||||||
|
dependencies = dependencies,
|
||||||
|
isInterop = isInterop,
|
||||||
|
packageFqName = packageFqName,
|
||||||
|
exportForwardDeclarations = exportForwardDeclarations,
|
||||||
|
nativeTargets = nativeTargets,
|
||||||
|
shortName = shortName
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|||||||
+3
-1
@@ -136,6 +136,7 @@ include ":benchmarks",
|
|||||||
":native:kotlin-native-utils",
|
":native:kotlin-native-utils",
|
||||||
":native:frontend.native",
|
":native:frontend.native",
|
||||||
":native:kotlin-klib-commonizer",
|
":native:kotlin-klib-commonizer",
|
||||||
|
":native:kotlin-klib-commonizer-api",
|
||||||
":native:kotlin-klib-commonizer-embeddable",
|
":native:kotlin-klib-commonizer-embeddable",
|
||||||
":jps-plugin",
|
":jps-plugin",
|
||||||
":kotlin-jps-plugin",
|
":kotlin-jps-plugin",
|
||||||
@@ -492,6 +493,7 @@ project(':kotlin-util-klib-metadata').projectDir = "$rootDir/compiler/util-klib-
|
|||||||
project(':native:kotlin-native-utils').projectDir = "$rootDir/native/utils" as File
|
project(':native:kotlin-native-utils').projectDir = "$rootDir/native/utils" as File
|
||||||
project(':native:frontend.native').projectDir = "$rootDir/native/frontend" as File
|
project(':native:frontend.native').projectDir = "$rootDir/native/frontend" as File
|
||||||
project(':native:kotlin-klib-commonizer').projectDir = "$rootDir/native/commonizer" as File
|
project(':native:kotlin-klib-commonizer').projectDir = "$rootDir/native/commonizer" as File
|
||||||
|
project(":native:kotlin-klib-commonizer-api").projectDir = "$rootDir/native/commonizer-api" as File
|
||||||
project(':native:kotlin-klib-commonizer-embeddable').projectDir = "$rootDir/native/commonizer-embeddable" as File
|
project(':native:kotlin-klib-commonizer-embeddable').projectDir = "$rootDir/native/commonizer-embeddable" as File
|
||||||
project(':kotlin-jps-plugin').projectDir = "$rootDir/prepare/jps-plugin" as File
|
project(':kotlin-jps-plugin').projectDir = "$rootDir/prepare/jps-plugin" as File
|
||||||
project(':idea:idea-android-output-parser').projectDir = "$rootDir/idea/idea-android/idea-android-output-parser" as File
|
project(':idea:idea-android-output-parser').projectDir = "$rootDir/idea/idea-android/idea-android-output-parser" as File
|
||||||
@@ -569,7 +571,7 @@ project(':plugins:jvm-abi-gen').projectDir = "$rootDir/plugins/jvm-abi-gen" as F
|
|||||||
project(':plugins:jvm-abi-gen-embeddable').projectDir = "$rootDir/plugins/jvm-abi-gen/embeddable" as File
|
project(':plugins:jvm-abi-gen-embeddable').projectDir = "$rootDir/plugins/jvm-abi-gen/embeddable" as File
|
||||||
project(":dukat").projectDir = "$rootDir/libraries/tools/dukat" as File
|
project(":dukat").projectDir = "$rootDir/libraries/tools/dukat" as File
|
||||||
|
|
||||||
project(':js:js.tests').projectDir = "$rootDir/js/js.tests" as File
|
project(':js:js.tests').projectDir = "$rootDir/js/js.tests" as File
|
||||||
project(':js:js.engines').projectDir = "$rootDir/js/js.engines" as File
|
project(':js:js.engines').projectDir = "$rootDir/js/js.engines" as File
|
||||||
|
|
||||||
project(':kotlinx-serialization-compiler-plugin').projectDir = file("$rootDir/plugins/kotlin-serialization/kotlin-serialization-compiler")
|
project(':kotlinx-serialization-compiler-plugin').projectDir = file("$rootDir/plugins/kotlin-serialization/kotlin-serialization-compiler")
|
||||||
|
|||||||
Reference in New Issue
Block a user