[Commonizer] Gracefully handle absent targets for hierarchical commonization

This commit is contained in:
sebastian.sellmair
2021-04-06 15:52:00 +02:00
parent bbe499c1b6
commit 933c52d470
26 changed files with 297 additions and 118 deletions
@@ -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)
)
}
@@ -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
)
@@ -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)
)
}
}
@@ -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)
@@ -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))
}
}
@@ -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)
@@ -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
@@ -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,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()
}
}
@@ -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()
}
}