diff --git a/compiler/util-klib/src/org/jetbrains/kotlin/library/impl/KotlinLibraryWriterImpl.kt b/compiler/util-klib/src/org/jetbrains/kotlin/library/impl/KotlinLibraryWriterImpl.kt index 9aeda2ed7ed..8a9f61fec7c 100644 --- a/compiler/util-klib/src/org/jetbrains/kotlin/library/impl/KotlinLibraryWriterImpl.kt +++ b/compiler/util-klib/src/org/jetbrains/kotlin/library/impl/KotlinLibraryWriterImpl.kt @@ -23,6 +23,7 @@ open class BaseWriterImpl( moduleName: String, override val versions: KotlinLibraryVersioning, builtInsPlatform: BuiltInsPlatform, + nativeTargets: List = emptyList(), val nopack: Boolean = false, val shortName: String? = null ) : BaseWriter { @@ -39,11 +40,14 @@ open class BaseWriterImpl( // TODO: : will go somewhere around here. manifestProperties.setProperty(KLIB_PROPERTY_UNIQUE_NAME, moduleName) manifestProperties.writeKonanLibraryVersioning(versions) - if (builtInsPlatform != BuiltInsPlatform.COMMON) + + if (builtInsPlatform != BuiltInsPlatform.COMMON) { manifestProperties.setProperty(KLIB_PROPERTY_BUILTINS_PLATFORM, builtInsPlatform.name) - shortName?.let { - manifestProperties.setProperty(KLIB_PROPERTY_SHORT_NAME, it) + if (builtInsPlatform == BuiltInsPlatform.NATIVE) + manifestProperties.setProperty(KLIB_PROPERTY_NATIVE_TARGETS, nativeTargets.joinToString(" ")) } + + shortName?.let { manifestProperties.setProperty(KLIB_PROPERTY_SHORT_NAME, it) } } override fun addLinkDependencies(libraries: List) { @@ -86,12 +90,13 @@ class KoltinLibraryWriterImpl( moduleName: String, versions: KotlinLibraryVersioning, builtInsPlatform: BuiltInsPlatform, + nativeTargets: List, nopack: Boolean = false, shortName: String? = null, val layout: KotlinLibraryLayoutForWriter = KotlinLibraryLayoutForWriter(libDir), - val base: BaseWriter = BaseWriterImpl(layout, moduleName, versions, builtInsPlatform, nopack, shortName), + val base: BaseWriter = BaseWriterImpl(layout, moduleName, versions, builtInsPlatform, nativeTargets, nopack, shortName), metadata: MetadataWriter = MetadataWriterImpl(layout), ir: IrWriter = IrMonoliticWriterImpl(layout) // ir: IrWriter = IrPerFileWriterImpl(layout) @@ -108,10 +113,11 @@ fun buildKoltinLibrary( nopack: Boolean, manifestProperties: Properties?, dataFlowGraph: ByteArray?, - builtInsPlatform: BuiltInsPlatform + builtInsPlatform: BuiltInsPlatform, + nativeTargets: List = emptyList() ): KotlinLibraryLayout { - val library = KoltinLibraryWriterImpl(File(output), moduleName, versions, builtInsPlatform, nopack) + val library = KoltinLibraryWriterImpl(File(output), moduleName, versions, builtInsPlatform, nativeTargets, nopack) library.addMetadata(metadata) diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt index 46d3b8b81b4..503c8f31172 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionCommonizer.kt @@ -169,6 +169,8 @@ class NativeDistributionCommonizer( } } + val commonManifestProvider = CommonNativeManifestDataProvider(originalLibrariesByTargets.values) + val serializer = KlibMetadataMonolithicSerializer( languageVersionSettings = LanguageVersionSettingsImpl.DEFAULT, metadataVersion = KlibMetadataVersion.INSTANCE, @@ -177,16 +179,16 @@ class NativeDistributionCommonizer( fun serializeTarget(target: Target) { val libsDestination: File - val originalLibraries: NativeDistributionLibraries + val manifestProvider: NativeManifestDataProvider when (target) { is InputTarget -> { libsDestination = destination.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.konanTarget!!.name) - originalLibraries = originalLibrariesByTargets.getValue(target) + manifestProvider = originalLibrariesByTargets.getValue(target) } is OutputTarget -> { libsDestination = destination.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR) - originalLibraries = originalLibrariesByTargets.values.first() // just take the first one + manifestProvider = commonManifestProvider } } @@ -201,7 +203,7 @@ class NativeDistributionCommonizer( val metadata = serializer.serializeModule(newModule) val plainName = libraryName.asString().removePrefix("<").removeSuffix(">") - val manifestData = originalLibraries.index.getValue(plainName).manifestData + val manifestData = manifestProvider.getManifest(plainName) val libraryDestination = libsDestination.resolve(plainName) writeLibrary(metadata, manifestData, libraryDestination) @@ -218,10 +220,11 @@ class NativeDistributionCommonizer( destination: File ) { val library = KoltinLibraryWriterImpl( - KFile(destination.path), - manifestData.uniqueName, - manifestData.versions, - BuiltInsPlatform.NATIVE, + libDir = KFile(destination.path), + moduleName = manifestData.uniqueName, + versions = manifestData.versions, + builtInsPlatform = BuiltInsPlatform.NATIVE, + nativeTargets = emptyList(), // will be overwritten with NativeSensitiveManifestData.applyTo() below nopack = true, shortName = manifestData.shortName ) diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionLibrary.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionLibrary.kt index a42ba6f479a..7a08dea53d3 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionLibrary.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionLibrary.kt @@ -7,20 +7,63 @@ package org.jetbrains.kotlin.descriptors.commonizer.konan import org.jetbrains.kotlin.library.KotlinLibrary +internal interface NativeManifestDataProvider { + fun getManifest(libraryName: String): NativeSensitiveManifestData +} + +/** + * A separate Kotlin/Native library from the distribution. + */ internal class NativeDistributionLibrary( val library: KotlinLibrary ) { val manifestData = NativeSensitiveManifestData.readFrom(library) } +/** + * A collection of Kotlin/Native libraries for a certain Native target + stdlib from the distribution. + */ internal class NativeDistributionLibraries( val stdlib: NativeDistributionLibrary, val platformLibs: List -) { +) : NativeManifestDataProvider { constructor(stdlib: KotlinLibrary, platformLibs: List) : this( NativeDistributionLibrary(stdlib), platformLibs.map(::NativeDistributionLibrary) ) - val index: Map = (platformLibs + stdlib).associateBy { it.manifestData.uniqueName } + private val manifestIndex: Map = buildManifestIndex() + + override fun getManifest(libraryName: String) = manifestIndex.getValue(libraryName) } + +internal class CommonNativeManifestDataProvider( + libraryGroups: Collection +) : NativeManifestDataProvider { + private val manifestIndex: Map + + init { + val iterator = libraryGroups.iterator() + val index = iterator.next().buildManifestIndex() + + while (iterator.hasNext()) { + val otherIndex = iterator.next().buildManifestIndex() + otherIndex.forEach { (libraryName, otherManifestData) -> + val manifestData = index[libraryName] + if (manifestData != null) { + // merge manifests + index[libraryName] = manifestData.mergeWith(otherManifestData) + } else { + index[libraryName] = otherManifestData + } + } + } + + manifestIndex = index + } + + override fun getManifest(libraryName: String) = manifestIndex.getValue(libraryName) +} + +private fun NativeDistributionLibraries.buildManifestIndex(): MutableMap = + (platformLibs + stdlib).map { it.manifestData }.associateByTo(HashMap()) { it.uniqueName } diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionModulesProvider.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionModulesProvider.kt index a43bc18413a..c6cee0bc459 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionModulesProvider.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeDistributionModulesProvider.kt @@ -56,9 +56,7 @@ internal class NativeDistributionModulesProvider( ) platformModulesMap.forEach { (name, module) -> - val dependencies = libraries.index - .getValue(name) - .manifestData + val dependencies = libraries.getManifest(name) .dependencies .map { if (it == KONAN_STDLIB_NAME) stdlib else platformModulesMap.getValue(it) } diff --git a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeSensitiveManifestData.kt b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeSensitiveManifestData.kt index e1189fc4f4d..a83c58b40d1 100644 --- a/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeSensitiveManifestData.kt +++ b/native/commonizer/src/org/jetbrains/kotlin/descriptors/commonizer/konan/NativeSensitiveManifestData.kt @@ -9,6 +9,10 @@ import org.jetbrains.kotlin.konan.properties.propertyList import org.jetbrains.kotlin.library.* import org.jetbrains.kotlin.library.impl.BaseWriterImpl +/** + * 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). + */ internal data class NativeSensitiveManifestData( val uniqueName: String, val versions: KotlinLibraryVersioning, @@ -16,6 +20,7 @@ internal data class NativeSensitiveManifestData( val isInterop: Boolean, val packageFqName: String?, val exportForwardDeclarations: List, + val nativeTargets: Collection, val shortName: String? ) { fun applyTo(library: BaseWriterImpl) { @@ -33,11 +38,36 @@ internal data class NativeSensitiveManifestData( addOptionalProperty(KLIB_PROPERTY_INTEROP, isInterop) { "true" } addOptionalProperty(KLIB_PROPERTY_PACKAGE, packageFqName != null) { packageFqName!! } addOptionalProperty(KLIB_PROPERTY_EXPORT_FORWARD_DECLARATIONS, exportForwardDeclarations.isNotEmpty()) { - exportForwardDeclarations.joinToString(separator = " ") + exportForwardDeclarations.joinToString(" ") + } + addOptionalProperty(KLIB_PROPERTY_NATIVE_TARGETS, nativeTargets.isNotEmpty()) { + nativeTargets.joinToString(" ") } addOptionalProperty(KLIB_PROPERTY_SHORT_NAME, shortName != null) { shortName!! } } + fun mergeWith(other: NativeSensitiveManifestData): NativeSensitiveManifestData { + if (this === other) return this + + check(uniqueName == other.uniqueName) + + // Assumption: It's enough to merge native targets list, other properties can be taken from 'this' manifest. + + return NativeSensitiveManifestData( + uniqueName = uniqueName, + versions = versions, + dependencies = dependencies, + isInterop = isInterop, + packageFqName = packageFqName, + exportForwardDeclarations = exportForwardDeclarations, + nativeTargets = HashSet().apply { + addAll(nativeTargets) + addAll(other.nativeTargets) + }, + shortName = shortName + ) + } + companion object { fun readFrom(library: KotlinLibrary) = NativeSensitiveManifestData( uniqueName = library.uniqueName, @@ -46,6 +76,7 @@ internal data class NativeSensitiveManifestData( isInterop = library.isInterop, packageFqName = library.packageFqName, exportForwardDeclarations = library.exportForwardDeclarations, + nativeTargets = library.nativeTargets, shortName = library.shortName ) }