[Commonizer] Gracefully handle absent targets for hierarchical commonization
This commit is contained in:
+13
-23
@@ -48,22 +48,6 @@ internal open class CInteropCommonizerTask : AbstractCInteropCommonizerTask() {
|
||||
internal var cinterops = setOf<CInteropGist>()
|
||||
private set
|
||||
|
||||
/**
|
||||
* All library files produced by the [Project.commonizeNativeDistributionTask] that are relevant for commonization
|
||||
*/
|
||||
@get:Classpath
|
||||
internal val nonHierarchicalNativeDistributionLibraries: Set<File>
|
||||
get() {
|
||||
val commonizeNativeDistribution = project.commonizeNativeDistributionTask.get()
|
||||
return getCommonizationParameters().flatMapTo(mutableSetOf()) { parameters ->
|
||||
parameters.commonizerTarget.withAllAncestors().flatMap { target ->
|
||||
commonizeNativeDistribution.commonizerTargetOutputDirectories.flatMap { outputDirectory ->
|
||||
NativeDistributionCommonizerOutputLayout.getTargetDirectory(outputDirectory, target)
|
||||
.listFiles().orEmpty().toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@OutputDirectories
|
||||
fun getAllOutputDirectories(): Set<File> {
|
||||
@@ -109,23 +93,29 @@ internal open class CInteropCommonizerTask : AbstractCInteropCommonizerTask() {
|
||||
GradleCliCommonizer(project).commonizeLibraries(
|
||||
konanHome = project.file(project.konanHome),
|
||||
outputCommonizerTarget = parameters.commonizerTarget,
|
||||
inputLibraries = cinteropsForTarget.map { it.libraryFile.get() }.toSet(),
|
||||
dependencyLibraries = cinteropsForTarget.flatMap { it.dependencies.files }.toSet() + nativeDistributionLibraries(parameters),
|
||||
inputLibraries = cinteropsForTarget.map { it.libraryFile.get() }.filter { it.exists() }.toSet(),
|
||||
dependencyLibraries = cinteropsForTarget.flatMap { it.dependencies.files }.map(::NonTargetedCommonizerDependency).toSet()
|
||||
+ nativeDistributionDependencies(parameters),
|
||||
outputDirectory = outputDirectory(parameters)
|
||||
)
|
||||
}
|
||||
|
||||
private fun nativeDistributionLibraries(parameters: CInteropCommonizationParameters): Set<File> {
|
||||
val task = project.commonizeNativeDistributionHierarchicalTask?.get() ?: return nonHierarchicalNativeDistributionLibraries
|
||||
private fun nativeDistributionDependencies(parameters: CInteropCommonizationParameters): Set<CommonizerDependency> {
|
||||
val task = project.commonizeNativeDistributionHierarchicalTask?.get() ?: return emptySet()
|
||||
|
||||
val rootTarget = task.rootCommonizerTargets
|
||||
.firstOrNull { rootTarget -> parameters.commonizerTarget in rootTarget } ?: return emptySet()
|
||||
|
||||
val rootTargetOutput = task.getRootOutputDirectory(rootTarget)
|
||||
|
||||
return parameters.commonizerTarget.withAllAncestors().flatMap { target ->
|
||||
HierarchicalCommonizerOutputLayout.getTargetDirectory(rootTargetOutput, target).listFiles().orEmpty().toList()
|
||||
}.toSet()
|
||||
return parameters.commonizerTarget.withAllAncestors()
|
||||
.flatMap { target -> createCommonizerDependencies(rootTargetOutput, target) }
|
||||
.toSet()
|
||||
}
|
||||
|
||||
private fun createCommonizerDependencies(rootOutput: File, target: CommonizerTarget): List<TargetedCommonizerDependency> {
|
||||
return HierarchicalCommonizerOutputLayout.getTargetDirectory(rootOutput, target).listFiles().orEmpty()
|
||||
.map { file -> TargetedCommonizerDependency(target, file) }
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -25,7 +25,7 @@ public class CliCommonizer(private val executor: Executor) : Commonizer {
|
||||
override fun commonizeLibraries(
|
||||
konanHome: File,
|
||||
inputLibraries: Set<File>,
|
||||
dependencyLibraries: Set<File>,
|
||||
dependencyLibraries: Set<CommonizerDependency>,
|
||||
outputCommonizerTarget: SharedCommonizerTarget,
|
||||
outputDirectory: File
|
||||
) {
|
||||
@@ -37,7 +37,7 @@ public class CliCommonizer(private val executor: Executor) : Commonizer {
|
||||
add("-output-commonizer-target"); add(outputCommonizerTarget.identityString)
|
||||
add("-output-path"); add(outputDirectory.absolutePath)
|
||||
if (dependencyLibraries.isNotEmpty()) {
|
||||
add("-dependency-libraries"); add(dependencyLibraries.joinToString(";") { it.absolutePath })
|
||||
add("-dependency-libraries"); add(dependencyLibraries.joinToString(";"))
|
||||
}
|
||||
}
|
||||
executor(arguments)
|
||||
|
||||
@@ -14,7 +14,7 @@ public interface Commonizer : Serializable {
|
||||
public fun commonizeLibraries(
|
||||
konanHome: File,
|
||||
inputLibraries: Set<File>,
|
||||
dependencyLibraries: Set<File>,
|
||||
dependencyLibraries: Set<CommonizerDependency>,
|
||||
outputCommonizerTarget: SharedCommonizerTarget,
|
||||
outputDirectory: File
|
||||
)
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
/*
|
||||
* 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.commonizer
|
||||
|
||||
import java.io.File
|
||||
|
||||
public sealed class CommonizerDependency {
|
||||
public abstract val file: File
|
||||
|
||||
final override fun toString(): String {
|
||||
return this.identityString
|
||||
}
|
||||
}
|
||||
|
||||
public data class TargetedCommonizerDependency(
|
||||
public val target: CommonizerTarget,
|
||||
public override val file: File
|
||||
) : CommonizerDependency()
|
||||
|
||||
public data class NonTargetedCommonizerDependency(
|
||||
public override val file: File
|
||||
) : CommonizerDependency()
|
||||
|
||||
public val CommonizerDependency.identityString: String
|
||||
get() = when (this) {
|
||||
is NonTargetedCommonizerDependency -> this.file.canonicalPath
|
||||
is TargetedCommonizerDependency -> "${target.identityString}::${file.canonicalPath}"
|
||||
}
|
||||
|
||||
|
||||
public fun parseCommonizerDependency(identityString: String): CommonizerDependency {
|
||||
val split = identityString.split("::", limit = 2)
|
||||
if (split.size == 2) {
|
||||
parseTargetedCommonizerDependencyOrNull(split[0], split[1])?.let { return it }
|
||||
}
|
||||
return NonTargetedCommonizerDependency(File(identityString))
|
||||
}
|
||||
|
||||
private fun parseTargetedCommonizerDependencyOrNull(commonizerTarget: String, canonicalFilePath: String): TargetedCommonizerDependency? {
|
||||
return TargetedCommonizerDependency(
|
||||
target = parseCommonizerTargetOrNull(commonizerTarget) ?: return null,
|
||||
file = File(canonicalFilePath)
|
||||
)
|
||||
}
|
||||
+10
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* 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.commonizer
|
||||
|
||||
public fun isCommonizerTargetIdentityString(value: String): Boolean {
|
||||
return parseCommonizerTargetOrNull(value) != null
|
||||
}
|
||||
@@ -9,6 +9,14 @@ import org.jetbrains.kotlin.commonizer.IdentityStringSyntaxNode.LeafTargetSyntax
|
||||
import org.jetbrains.kotlin.commonizer.IdentityStringSyntaxNode.SharedTargetSyntaxNode
|
||||
import org.jetbrains.kotlin.commonizer.IdentityStringToken.*
|
||||
|
||||
public fun parseCommonizerTargetOrNull(identityString: String): CommonizerTarget? {
|
||||
return try {
|
||||
parseCommonizerTarget(identityString)
|
||||
} catch (t: IllegalArgumentException) {
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
public fun parseCommonizerTarget(identityString: String): CommonizerTarget {
|
||||
try {
|
||||
val tokens = tokenizeIdentityString(identityString)
|
||||
|
||||
@@ -28,8 +28,13 @@ class CommonizeLibcurlTest {
|
||||
commonizer.commonizeLibraries(
|
||||
konanHome = konanHome,
|
||||
inputLibraries = libraries,
|
||||
dependencyLibraries = KonanDistribution(konanHome).platformLibsDir.resolve(LINUX_X64.name).listFiles().orEmpty().toSet() +
|
||||
KonanDistribution(konanHome).platformLibsDir.resolve(LINUX_ARM64.name).listFiles().orEmpty().toSet(),
|
||||
dependencyLibraries = emptySet<CommonizerDependency>() +
|
||||
KonanDistribution(konanHome).platformLibsDir.resolve(LINUX_X64.name).listFiles().orEmpty()
|
||||
.map { TargetedCommonizerDependency(LeafCommonizerTarget(LINUX_X64), it) }.toSet() +
|
||||
|
||||
KonanDistribution(konanHome).platformLibsDir.resolve(LINUX_ARM64.name).listFiles().orEmpty()
|
||||
.map { TargetedCommonizerDependency(LeafCommonizerTarget(LINUX_ARM64), it) }
|
||||
.toSet(),
|
||||
outputCommonizerTarget = CommonizerTarget(LINUX_ARM64, LINUX_X64),
|
||||
outputDirectory = temporaryOutputDirectory.root
|
||||
)
|
||||
|
||||
+34
@@ -0,0 +1,34 @@
|
||||
/*
|
||||
* 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.commonizer
|
||||
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class CommonizerDependencyTest {
|
||||
|
||||
@Test
|
||||
fun `sample identityString`() {
|
||||
assertEquals(
|
||||
"((a, b), c)::/hello.txt",
|
||||
TargetedCommonizerDependency(parseCommonizerTarget("((a,b), c)"), File("/hello.txt")).identityString
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test serialize deserialize`() {
|
||||
assertEquals(
|
||||
parseCommonizerDependency(NonTargetedCommonizerDependency(File("hello.txt")).identityString),
|
||||
NonTargetedCommonizerDependency(File("hello.txt").canonicalFile)
|
||||
)
|
||||
|
||||
assertEquals(
|
||||
parseCommonizerDependency(TargetedCommonizerDependency(parseCommonizerTarget("((a,b), c)"), File("hello.txt")).identityString),
|
||||
TargetedCommonizerDependency(parseCommonizerTarget("((a,b), c)"), File("hello.txt").canonicalFile)
|
||||
)
|
||||
}
|
||||
}
|
||||
+17
-2
@@ -7,8 +7,7 @@ package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget.*
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.*
|
||||
|
||||
class CommonizerTargetIdentityStringTest {
|
||||
|
||||
@@ -134,4 +133,20 @@ class CommonizerTargetIdentityStringTest {
|
||||
fun `fail parsing CommonizerTarget 10`() {
|
||||
parseCommonizerTarget("(x, (x, y)")
|
||||
}
|
||||
|
||||
@Test
|
||||
fun isCommonizerIdentityString() {
|
||||
assertFalse(isCommonizerTargetIdentityString(""))
|
||||
assertTrue(isCommonizerTargetIdentityString("()"))
|
||||
assertTrue(isCommonizerTargetIdentityString("(a,b)"))
|
||||
assertFalse(isCommonizerTargetIdentityString("..."))
|
||||
assertTrue(isCommonizerTargetIdentityString("x"))
|
||||
assertFalse(isCommonizerTargetIdentityString("((a)"))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun parseCommonizerTargetOrNull() {
|
||||
assertEquals(parseCommonizerTarget("((a,b),c)"), parseCommonizerTargetOrNull("((a,b),c)"))
|
||||
assertNull(parseCommonizerTargetOrNull(""))
|
||||
}
|
||||
}
|
||||
|
||||
@@ -14,16 +14,17 @@ class CommonizerParameters(
|
||||
val outputTarget: SharedCommonizerTarget,
|
||||
val manifestProvider: TargetDependent<NativeManifestDataProvider>,
|
||||
val dependenciesProvider: TargetDependent<ModulesProvider?>,
|
||||
val targetProviders: TargetDependent<TargetProvider>,
|
||||
val targetProviders: TargetDependent<TargetProvider?>,
|
||||
val resultsConsumer: ResultsConsumer,
|
||||
val statsCollector: StatsCollector? = null,
|
||||
val progressLogger: ((String) -> Unit)? = null
|
||||
val progressLogger: ((String) -> Unit)? = null,
|
||||
)
|
||||
|
||||
fun CommonizerParameters.getCommonModuleNames(): Set<String> {
|
||||
if (targetProviders.size < 2) return emptySet() // too few targets
|
||||
val supportedTargets = targetProviders.filterNonNull()
|
||||
if (supportedTargets.size < 2) return emptySet() // too few targets
|
||||
|
||||
val allModuleNames: List<Set<String>> = targetProviders.toList().map { targetProvider ->
|
||||
val allModuleNames: List<Set<String>> = supportedTargets.toList().map { targetProvider ->
|
||||
targetProvider.modulesProvider.loadModuleInfos().mapTo(HashSet()) { it.name }
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ sealed interface TargetDependent<T> : Iterable<T> {
|
||||
val targets: List<CommonizerTarget>
|
||||
fun indexOf(target: CommonizerTarget): Int = targets.indexOf(target)
|
||||
|
||||
fun <R : Any> map(mapper: (target: CommonizerTarget, T) -> R): TargetDependent<R> {
|
||||
fun <R> map(mapper: (target: CommonizerTarget, T) -> R): TargetDependent<R> {
|
||||
return TargetDependent(targets) { target ->
|
||||
mapper(target, get(target))
|
||||
}
|
||||
@@ -54,6 +54,9 @@ internal fun <T, R> TargetDependent<T>.mapTargets(mapper: (CommonizerTarget) ->
|
||||
return TargetDependent(targets) { target -> mapper(target) }
|
||||
}
|
||||
|
||||
internal inline fun <T> TargetDependent<T>.forEachWithTarget(action: (target: CommonizerTarget, T) -> Unit) {
|
||||
targets.forEach { target -> action(target, this[target]) }
|
||||
}
|
||||
|
||||
internal fun <T> TargetDependent(map: Map<out CommonizerTarget, T>): TargetDependent<T> {
|
||||
return MapBasedTargetDependent(map.toMap())
|
||||
@@ -66,6 +69,7 @@ internal fun <T> TargetDependent(keys: Iterable<CommonizerTarget>, factory: (tar
|
||||
internal fun <T> EagerTargetDependent(keys: Iterable<CommonizerTarget>, factory: (target: CommonizerTarget) -> T): TargetDependent<T> {
|
||||
return keys.associateWith(factory).toTargetDependent()
|
||||
}
|
||||
|
||||
private class MapBasedTargetDependent<T>(private val map: Map<CommonizerTarget, T>) : TargetDependent<T> {
|
||||
override val targets: List<CommonizerTarget> = map.keys.toList()
|
||||
override fun get(target: CommonizerTarget): T = map.getValue(target)
|
||||
|
||||
+26
@@ -0,0 +1,26 @@
|
||||
/*
|
||||
* 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.commonizer.cli
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerDependency
|
||||
import org.jetbrains.kotlin.commonizer.parseCommonizerDependency
|
||||
|
||||
internal abstract class DependenciesLibrariesSetOptionType(
|
||||
mandatory: Boolean,
|
||||
alias: String,
|
||||
description: String
|
||||
) : OptionType<List<CommonizerDependency>>(
|
||||
mandatory = mandatory,
|
||||
alias = alias,
|
||||
description = description
|
||||
) {
|
||||
override fun parse(rawValue: String, onError: (reason: String) -> Nothing): Option<List<CommonizerDependency>> {
|
||||
if (rawValue.isBlank()) {
|
||||
return Option(this, emptyList())
|
||||
}
|
||||
return Option(this, rawValue.split(";").map(::parseCommonizerDependency))
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.commonizer.cli
|
||||
|
||||
internal object DependencyLibrariesOptionType : LibrariesSetOptionType(
|
||||
internal object DependencyLibrariesOptionType : DependenciesLibrariesSetOptionType(
|
||||
mandatory = false,
|
||||
alias = "dependency-libraries",
|
||||
description = "';' separated list of klib file paths that can be used as dependency"
|
||||
|
||||
@@ -47,7 +47,7 @@ internal class NativeKlibCommonize(options: Collection<Option<*>>) : Task(option
|
||||
val distribution = KonanDistribution(getMandatory<File, NativeDistributionOptionType>())
|
||||
val destination = getMandatory<File, OutputOptionType>()
|
||||
val targetLibraries = getMandatory<List<File>, InputLibrariesOptionType>()
|
||||
val dependencyLibraries = getOptional<List<File>, DependencyLibrariesOptionType>().orEmpty()
|
||||
val dependencyLibraries = getOptional<List<CommonizerDependency>, DependencyLibrariesOptionType>().orEmpty()
|
||||
val outputCommonizerTarget = compatGetOutputTarget()
|
||||
val statsType = getOptional<StatsType, StatsTypeOptionType> { it == "log-stats" } ?: StatsType.NONE
|
||||
|
||||
@@ -71,7 +71,7 @@ internal class NativeKlibCommonize(options: Collection<Option<*>>) : Task(option
|
||||
outputTarget = outputCommonizerTarget,
|
||||
repository = repository,
|
||||
dependencies = StdlibRepository(distribution, libraryLoader) +
|
||||
FilesRepository(dependencyLibraries.toSet(), libraryLoader),
|
||||
CommonizerDependencyRepository(dependencyLibraries.toSet(), libraryLoader),
|
||||
resultsConsumer = resultsConsumer,
|
||||
statsCollector = statsCollector,
|
||||
progressLogger = progressLogger
|
||||
@@ -100,7 +100,7 @@ internal class NativeDistributionCommonize(options: Collection<Option<*>>) : Tas
|
||||
|
||||
val progressLogger = ProgressLogger(CliLoggerAdapter(2), startImmediately = true)
|
||||
val libraryLoader = DefaultNativeLibraryLoader(progressLogger)
|
||||
val repository = KonanDistributionRepository(distribution, outputTarget.allLeaves(), libraryLoader)
|
||||
val repository = KonanDistributionRepository(distribution, outputTarget.konanTargets, libraryLoader)
|
||||
val statsCollector = StatsCollector(statsType, outputTarget.withAllAncestors().toList())
|
||||
|
||||
val resultsConsumer = buildResultsConsumer {
|
||||
|
||||
@@ -7,14 +7,15 @@ package org.jetbrains.kotlin.commonizer
|
||||
|
||||
import kotlinx.metadata.klib.ChunkedKlibModuleFragmentWriteStrategy
|
||||
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult
|
||||
import org.jetbrains.kotlin.commonizer.ResultsConsumer.ModuleResult.Missing
|
||||
import org.jetbrains.kotlin.commonizer.ResultsConsumer.Status
|
||||
import org.jetbrains.kotlin.commonizer.core.CommonizationVisitor
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirCommonizedClassifierNodes
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirKnownClassifiers
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.indexOfCommon
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.indices
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirNode.Companion.targetIndices
|
||||
import org.jetbrains.kotlin.commonizer.mergedtree.CirRootNode
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer
|
||||
import org.jetbrains.kotlin.commonizer.metadata.CirTreeSerializer.serializeSingleTarget
|
||||
import org.jetbrains.kotlin.commonizer.tree.CirTreeRoot
|
||||
import org.jetbrains.kotlin.commonizer.tree.assembleCirTree
|
||||
import org.jetbrains.kotlin.commonizer.tree.deserializeCirTree
|
||||
@@ -38,7 +39,7 @@ private fun commonize(
|
||||
parameters: CommonizerParameters,
|
||||
storageManager: StorageManager,
|
||||
target: SharedCommonizerTarget,
|
||||
): CirRootNode {
|
||||
): CirRootNode? {
|
||||
val cirTrees = getCirTree(parameters, storageManager, target)
|
||||
parameters.progressLogger?.invoke("Build cir tree for $target")
|
||||
|
||||
@@ -48,11 +49,11 @@ private fun commonize(
|
||||
commonDependencies = parameters.dependencyClassifiers(target)
|
||||
)
|
||||
|
||||
val mergedTree = mergeCirTree(storageManager, classifiers, cirTrees)
|
||||
val mergedTree = merge(storageManager, classifiers, cirTrees) ?: return null
|
||||
mergedTree.accept(CommonizationVisitor(classifiers, mergedTree), Unit)
|
||||
parameters.progressLogger?.invoke("Commonized declarations for $target")
|
||||
|
||||
serialize(mergedTree, parameters)
|
||||
serialize(parameters, mergedTree, target)
|
||||
parameters.progressLogger?.invoke("Commonized target $target")
|
||||
|
||||
return mergedTree
|
||||
@@ -60,40 +61,61 @@ private fun commonize(
|
||||
|
||||
private fun getCirTree(
|
||||
parameters: CommonizerParameters, storageManager: StorageManager, target: SharedCommonizerTarget
|
||||
): TargetDependent<CirTreeRoot> {
|
||||
): TargetDependent<CirTreeRoot?> {
|
||||
return EagerTargetDependent(target.targets) { childTarget ->
|
||||
when (childTarget) {
|
||||
is LeafCommonizerTarget -> deserializeCirTree(parameters, parameters.targetProviders[childTarget])
|
||||
is SharedCommonizerTarget -> commonize(parameters, storageManager, childTarget).assembleCirTree()
|
||||
is LeafCommonizerTarget -> deserialize(parameters, childTarget)
|
||||
is SharedCommonizerTarget -> commonize(parameters, storageManager, childTarget)?.assembleCirTree()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun serialize(mergedTree: CirRootNode, parameters: CommonizerParameters) {
|
||||
for (targetIndex in mergedTree.indices) {
|
||||
serializeTarget(mergedTree, targetIndex, parameters)
|
||||
}
|
||||
private fun deserialize(parameters: CommonizerParameters, target: CommonizerTarget): CirTreeRoot? {
|
||||
val targetProvider = parameters.targetProviders[target] ?: return null
|
||||
return deserializeCirTree(parameters, targetProvider)
|
||||
}
|
||||
|
||||
private fun serializeTarget(mergedTree: CirRootNode, targetIndex: Int, parameters: CommonizerParameters) {
|
||||
val target = mergedTree.getTarget(targetIndex)
|
||||
private fun merge(
|
||||
storageManager: StorageManager, classifiers: CirKnownClassifiers, cirTrees: TargetDependent<CirTreeRoot?>,
|
||||
): CirRootNode? {
|
||||
val availableTrees = cirTrees.filterNonNull()
|
||||
/* Nothing to merge */
|
||||
if (availableTrees.size == 0) return null
|
||||
|
||||
if (target in parameters.targetProviders.targets) {
|
||||
parameters.targetProviders[target].modulesProvider.loadModuleInfos()
|
||||
/* No propagation from leaves */
|
||||
if (availableTrees.size == 1 && availableTrees.targets.single() is LeafCommonizerTarget) return null
|
||||
|
||||
return mergeCirTree(storageManager, classifiers, availableTrees)
|
||||
}
|
||||
|
||||
private fun serialize(parameters: CommonizerParameters, mergedTree: CirRootNode, commonTarget: CommonizerTarget) {
|
||||
for (targetIndex in mergedTree.targetIndices) {
|
||||
val target = mergedTree.targetDeclarations[targetIndex]?.target ?: continue
|
||||
serializeMissingModules(parameters, target)
|
||||
if (target is LeafCommonizerTarget) {
|
||||
serialize(parameters, mergedTree, target, targetIndex)
|
||||
}
|
||||
}
|
||||
serialize(parameters, mergedTree, commonTarget, mergedTree.indexOfCommon)
|
||||
}
|
||||
|
||||
private fun serialize(parameters: CommonizerParameters, mergedTree: CirRootNode, target: CommonizerTarget, targetIndex: Int) {
|
||||
serializeSingleTarget(mergedTree, targetIndex, parameters.statsCollector) { metadataModule ->
|
||||
val libraryName = metadataModule.name
|
||||
val serializedMetadata = with(metadataModule.write(KLIB_FRAGMENT_WRITE_STRATEGY)) {
|
||||
SerializedMetadata(header, fragments, fragmentNames)
|
||||
}
|
||||
val manifestData = parameters.manifestProvider[target].getManifest(libraryName)
|
||||
parameters.resultsConsumer.consume(target, ModuleResult.Commonized(libraryName, serializedMetadata, manifestData))
|
||||
}
|
||||
parameters.resultsConsumer.targetConsumed(target)
|
||||
}
|
||||
|
||||
private fun serializeMissingModules(parameters: CommonizerParameters, requestedTarget: CommonizerTarget) {
|
||||
if (requestedTarget in parameters.targetProviders.targets) {
|
||||
parameters.targetProviders[requestedTarget]?.modulesProvider?.loadModuleInfos().orEmpty()
|
||||
.filter { it.name !in parameters.getCommonModuleNames() }
|
||||
.forEach { missingModule -> parameters.resultsConsumer.consume(target, ModuleResult.Missing(missingModule.originalLocation)) }
|
||||
}
|
||||
|
||||
if (targetIndex == mergedTree.indexOfCommon || target is LeafCommonizerTarget) {
|
||||
CirTreeSerializer.serializeSingleTarget(mergedTree, targetIndex, parameters.statsCollector) { metadataModule ->
|
||||
val libraryName = metadataModule.name
|
||||
val serializedMetadata = with(metadataModule.write(KLIB_FRAGMENT_WRITE_STRATEGY)) {
|
||||
SerializedMetadata(header, fragments, fragmentNames)
|
||||
}
|
||||
val manifestData = parameters.manifestProvider[target].getManifest(libraryName)
|
||||
parameters.resultsConsumer.consume(target, ModuleResult.Commonized(libraryName, serializedMetadata, manifestData))
|
||||
}
|
||||
parameters.resultsConsumer.targetConsumed(target)
|
||||
.forEach { missingModule -> parameters.resultsConsumer.consume(requestedTarget, Missing(missingModule.originalLocation)) }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.commonizer.*
|
||||
import org.jetbrains.kotlin.commonizer.repository.Repository
|
||||
import org.jetbrains.kotlin.commonizer.stats.StatsCollector
|
||||
import org.jetbrains.kotlin.commonizer.utils.ProgressLogger
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.ifNotEmpty
|
||||
|
||||
internal class LibraryCommonizer internal constructor(
|
||||
private val outputTarget: SharedCommonizerTarget,
|
||||
@@ -26,26 +27,27 @@ internal class LibraryCommonizer internal constructor(
|
||||
progressLogger.logTotal()
|
||||
}
|
||||
|
||||
private fun loadLibraries(): TargetDependent<NativeLibrariesToCommonize> {
|
||||
val librariesByTargets = outputTarget.allLeaves().associateWith { target ->
|
||||
NativeLibrariesToCommonize(repository.getLibraries(target).toList())
|
||||
private fun loadLibraries(): TargetDependent<NativeLibrariesToCommonize?> {
|
||||
val libraries = EagerTargetDependent(outputTarget.allLeaves()) { target ->
|
||||
repository.getLibraries(target).toList().ifNotEmpty(::NativeLibrariesToCommonize)
|
||||
}
|
||||
|
||||
librariesByTargets.forEach { (target, librariesToCommonize) ->
|
||||
if (librariesToCommonize.libraries.isEmpty()) {
|
||||
progressLogger.warning("No platform libraries found for target ${target.prettyName}. This target will be excluded from commonization.")
|
||||
}
|
||||
libraries.forEachWithTarget { target, librariesOrNull ->
|
||||
if (librariesOrNull == null)
|
||||
progressLogger.warning(
|
||||
"No libraries found for target ${target.prettyName}. This target will be excluded from commonization."
|
||||
)
|
||||
}
|
||||
|
||||
progressLogger.log("Resolved libraries to be commonized")
|
||||
return TargetDependent(librariesByTargets)
|
||||
return libraries
|
||||
}
|
||||
|
||||
private fun commonizeAndSaveResults(allLibraries: TargetDependent<NativeLibrariesToCommonize>) {
|
||||
private fun commonizeAndSaveResults(libraries: TargetDependent<NativeLibrariesToCommonize?>) {
|
||||
val parameters = CommonizerParameters(
|
||||
outputTarget = outputTarget,
|
||||
targetProviders = TargetDependent(outputTarget.allLeaves()) { target -> createTargetProvider(target, allLibraries[target]) }
|
||||
.filterNonNull(),
|
||||
manifestProvider = createManifestProvider(allLibraries),
|
||||
targetProviders = libraries.map { target, targetLibraries -> createTargetProvider(target, targetLibraries) },
|
||||
manifestProvider = createManifestProvider(libraries),
|
||||
dependenciesProvider = createDependenciesProvider(),
|
||||
resultsConsumer = resultsConsumer,
|
||||
statsCollector = statsCollector,
|
||||
@@ -54,8 +56,8 @@ internal class LibraryCommonizer internal constructor(
|
||||
runCommonization(parameters)
|
||||
}
|
||||
|
||||
private fun createTargetProvider(target: CommonizerTarget, libraries: NativeLibrariesToCommonize): TargetProvider? {
|
||||
if (libraries.libraries.isEmpty()) return null
|
||||
private fun createTargetProvider(target: CommonizerTarget, libraries: NativeLibrariesToCommonize?): TargetProvider? {
|
||||
if (libraries == null) return null
|
||||
return TargetProvider(
|
||||
target = target,
|
||||
modulesProvider = DefaultModulesProvider.create(libraries)
|
||||
@@ -69,13 +71,13 @@ internal class LibraryCommonizer internal constructor(
|
||||
}
|
||||
|
||||
private fun createManifestProvider(
|
||||
libraries: TargetDependent<NativeLibrariesToCommonize>
|
||||
libraries: TargetDependent<NativeLibrariesToCommonize?>
|
||||
): TargetDependent<NativeManifestDataProvider> {
|
||||
return TargetDependent(outputTarget.withAllAncestors()) { target ->
|
||||
when (target) {
|
||||
is LeafCommonizerTarget -> libraries[target]
|
||||
is LeafCommonizerTarget -> libraries[target] ?: error("Can't provide manifest for missing target $target")
|
||||
is SharedCommonizerTarget -> CommonNativeManifestDataProvider(
|
||||
target.allLeaves().map { leafTarget -> libraries[leafTarget] }
|
||||
target.allLeaves().mapNotNull { leafTarget -> libraries.getOrNull(leafTarget) }
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,9 +8,6 @@
|
||||
package org.jetbrains.kotlin.commonizer.konan
|
||||
|
||||
import gnu.trove.THashMap
|
||||
import org.jetbrains.kotlin.commonizer.LeafCommonizerTarget
|
||||
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
|
||||
import org.jetbrains.kotlin.commonizer.TargetDependent
|
||||
import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
|
||||
interface NativeManifestDataProvider {
|
||||
|
||||
@@ -22,6 +22,8 @@ interface CirNode<T : CirDeclaration, R : CirDeclaration> {
|
||||
companion object {
|
||||
inline val CirNode<*, *>.indices: IntRange get() = 0..targetDeclarations.size
|
||||
|
||||
inline val CirNode<*, *>.targetIndices: List<Int> get() = indices - indexOfCommon
|
||||
|
||||
inline val CirNode<*, *>.indexOfCommon: Int
|
||||
get() = targetDeclarations.size
|
||||
|
||||
|
||||
@@ -19,9 +19,6 @@ class CirRootNode(
|
||||
) : CirNode<CirRoot, CirRoot> {
|
||||
val modules: MutableMap<CirName, CirModuleNode> = THashMap()
|
||||
|
||||
fun getTarget(targetIndex: Int): CommonizerTarget =
|
||||
(if (targetIndex == indexOfCommon) commonDeclaration() else targetDeclarations[targetIndex])!!.target
|
||||
|
||||
override fun <T, R> accept(visitor: CirNodeVisitor<T, R>, data: T): R =
|
||||
visitor.visitRootNode(this, data)
|
||||
|
||||
|
||||
+1
-1
@@ -23,7 +23,7 @@ internal class RootMerger(
|
||||
val commonModuleNames = parameters.getCommonModuleNames()
|
||||
val missingModuleInfosByTargets = mutableMapOf<CommonizerTarget, Collection<ModulesProvider.ModuleInfo>>()
|
||||
|
||||
parameters.targetProviders.forEachIndexed { targetIndex, targetProvider ->
|
||||
parameters.targetProviders.filterNotNull().forEachIndexed { targetIndex, targetProvider ->
|
||||
val allModuleInfos = targetProvider.modulesProvider.loadModuleInfos()
|
||||
|
||||
val (commonModuleInfos, missingModuleInfos) = allModuleInfos.partition { it.name in commonModuleNames }
|
||||
|
||||
@@ -293,7 +293,6 @@ private class CirTreeSerializationVisitor(
|
||||
|
||||
internal data class CirTreeSerializationContext(
|
||||
val targetIndex: Int,
|
||||
val target: CommonizerTarget,
|
||||
val isCommon: Boolean,
|
||||
val typeParameterIndexOffset: Int,
|
||||
val currentPath: Path
|
||||
@@ -332,7 +331,6 @@ internal data class CirTreeSerializationContext(
|
||||
|
||||
return CirTreeSerializationContext(
|
||||
targetIndex = targetIndex,
|
||||
target = target,
|
||||
isCommon = isCommon,
|
||||
typeParameterIndexOffset = 0,
|
||||
currentPath = Path.Module(moduleName)
|
||||
@@ -344,7 +342,6 @@ internal data class CirTreeSerializationContext(
|
||||
|
||||
return CirTreeSerializationContext(
|
||||
targetIndex = targetIndex,
|
||||
target = target,
|
||||
isCommon = isCommon,
|
||||
typeParameterIndexOffset = 0,
|
||||
currentPath = Path.Package(packageName)
|
||||
@@ -369,7 +366,6 @@ internal data class CirTreeSerializationContext(
|
||||
|
||||
return CirTreeSerializationContext(
|
||||
targetIndex = targetIndex,
|
||||
target = target,
|
||||
isCommon = isCommon,
|
||||
typeParameterIndexOffset = typeParameterIndexOffset + outerClassTypeParametersCount,
|
||||
currentPath = newPath
|
||||
@@ -394,7 +390,6 @@ internal data class CirTreeSerializationContext(
|
||||
|
||||
return CirTreeSerializationContext(
|
||||
targetIndex = targetIndex,
|
||||
target = target,
|
||||
isCommon = isCommon,
|
||||
typeParameterIndexOffset = typeParameterIndexOffset + ownerClassTypeParametersCount,
|
||||
currentPath = newPath
|
||||
@@ -417,7 +412,6 @@ internal data class CirTreeSerializationContext(
|
||||
fun rootContext(rootNode: CirRootNode, targetIndex: Int): CirTreeSerializationContext =
|
||||
CirTreeSerializationContext(
|
||||
targetIndex = targetIndex,
|
||||
target = rootNode.getTarget(targetIndex),
|
||||
isCommon = rootNode.indexOfCommon == targetIndex,
|
||||
typeParameterIndexOffset = 0,
|
||||
currentPath = Path.Empty
|
||||
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* 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.commonizer.repository
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.*
|
||||
import org.jetbrains.kotlin.commonizer.NativeLibraryLoader
|
||||
import org.jetbrains.kotlin.commonizer.konan.NativeLibrary
|
||||
|
||||
internal class CommonizerDependencyRepository(
|
||||
private val dependencies: Set<CommonizerDependency>,
|
||||
private val libraryLoader: NativeLibraryLoader
|
||||
) : Repository {
|
||||
|
||||
private val nonTargetedDependencyRepository = FilesRepository(
|
||||
libraryFiles = dependencies.filterIsInstance<NonTargetedCommonizerDependency>().map { it.file }.toSet(),
|
||||
libraryLoader = libraryLoader
|
||||
)
|
||||
|
||||
private val targetedDependencies: Map<CommonizerTarget, Lazy<Set<NativeLibrary>>> by lazy {
|
||||
dependencies
|
||||
.filterIsInstance<TargetedCommonizerDependency>()
|
||||
.groupBy { it.target }
|
||||
.mapValues { (_, dependencies) -> lazy { dependencies.map { libraryLoader(it.file) }.toSet() } }
|
||||
}
|
||||
|
||||
override fun getLibraries(target: CommonizerTarget): Set<NativeLibrary> {
|
||||
return targetedDependencies[target]?.value.orEmpty() + nonTargetedDependencyRepository.getLibraries(target)
|
||||
}
|
||||
}
|
||||
@@ -17,7 +17,7 @@ internal class FilesRepository(
|
||||
private val libraryLoader: NativeLibraryLoader
|
||||
) : Repository {
|
||||
|
||||
private val librariesByTarget: Map<Set<KonanTarget>, Set<NativeLibrary>> by lazy {
|
||||
private val librariesByKonanTargets: Map<Set<KonanTarget>, Set<NativeLibrary>> by lazy {
|
||||
libraryFiles
|
||||
.map(libraryLoader::invoke)
|
||||
.groupBy { library -> library.manifestData.nativeTargets.map(::konanTargetOrThrow).toSet() }
|
||||
@@ -25,10 +25,11 @@ internal class FilesRepository(
|
||||
}
|
||||
|
||||
override fun getLibraries(target: CommonizerTarget): Set<NativeLibrary> {
|
||||
return librariesByTarget[target.konanTargets].orEmpty()
|
||||
return librariesByKonanTargets[target.konanTargets].orEmpty()
|
||||
}
|
||||
|
||||
private fun konanTargetOrThrow(value: String): KonanTarget {
|
||||
return KonanTarget.predefinedTargets[value] ?: error("Unexpected KonanTarget $value")
|
||||
}
|
||||
}
|
||||
|
||||
private fun konanTargetOrThrow(value: String): KonanTarget {
|
||||
return KonanTarget.predefinedTargets[value] ?: error("Unexpected KonanTarget $value")
|
||||
}
|
||||
|
||||
+6
-6
@@ -6,14 +6,16 @@
|
||||
package org.jetbrains.kotlin.commonizer.repository
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.*
|
||||
import org.jetbrains.kotlin.commonizer.NativeLibraryLoader
|
||||
import org.jetbrains.kotlin.commonizer.konan.NativeLibrary
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
internal class KonanDistributionRepository(
|
||||
konanDistribution: KonanDistribution,
|
||||
targets: Set<LeafCommonizerTarget>,
|
||||
targets: Set<KonanTarget>,
|
||||
libraryLoader: NativeLibraryLoader,
|
||||
) : Repository {
|
||||
private val librariesByTarget: Map<LeafCommonizerTarget, Lazy<Set<NativeLibrary>>> =
|
||||
private val librariesByTarget: Map<KonanTarget, Lazy<Set<NativeLibrary>>> =
|
||||
targets.associateWith { target ->
|
||||
lazy {
|
||||
konanDistribution.platformLibsDir
|
||||
@@ -27,9 +29,7 @@ internal class KonanDistributionRepository(
|
||||
}
|
||||
|
||||
override fun getLibraries(target: CommonizerTarget): Set<NativeLibrary> {
|
||||
return when (target) {
|
||||
is LeafCommonizerTarget -> librariesByTarget[target]?.value ?: error("Missing target libraries for: $target")
|
||||
is SharedCommonizerTarget -> emptySet()
|
||||
}
|
||||
val singleTarget = target.konanTargets.singleOrNull() ?: return emptySet()
|
||||
return librariesByTarget[singleTarget]?.value ?: error("Missing target libraries for $target")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,7 +6,6 @@
|
||||
package org.jetbrains.kotlin.commonizer.repository
|
||||
|
||||
import org.jetbrains.kotlin.commonizer.CommonizerTarget
|
||||
import org.jetbrains.kotlin.commonizer.LeafCommonizerTarget
|
||||
import org.jetbrains.kotlin.commonizer.konan.NativeLibrary
|
||||
|
||||
internal interface Repository {
|
||||
@@ -25,9 +24,3 @@ private class CompositeRepository(val repositories: Iterable<Repository>) : Repo
|
||||
return repositories.map { it.getLibraries(target) }.flatten().toSet()
|
||||
}
|
||||
}
|
||||
|
||||
internal object EmptyRepository : Repository {
|
||||
override fun getLibraries(target: CommonizerTarget): Set<NativeLibrary> {
|
||||
return emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
+1
-2
@@ -18,7 +18,6 @@ internal class StdlibRepository(
|
||||
}
|
||||
|
||||
override fun getLibraries(target: CommonizerTarget): Set<NativeLibrary> {
|
||||
return if (target is SharedCommonizerTarget) setOf(stdlib)
|
||||
else emptySet()
|
||||
return if (target is SharedCommonizerTarget) setOf(stdlib) else emptySet()
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user