[IR] Enhance error reporting for IR linking issues
^KT-44626 Support correct error reporting both with native static caches and without native static caches.
This commit is contained in:
+9
-6
@@ -67,6 +67,7 @@ class SignatureIdNotFoundInModuleWithDependencies(
|
|||||||
allModules = allModules,
|
allModules = allModules,
|
||||||
problemModuleIds = setOf(problemModuleId),
|
problemModuleIds = setOf(problemModuleId),
|
||||||
problemCause = "This module requires symbol ${idSignature.render()}",
|
problemCause = "This module requires symbol ${idSignature.render()}",
|
||||||
|
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
|
||||||
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -113,6 +114,7 @@ class SymbolTypeMismatch(
|
|||||||
potentiallyConflictingDependencies = findPotentiallyConflictingIncomingDependencies(
|
potentiallyConflictingDependencies = findPotentiallyConflictingIncomingDependencies(
|
||||||
problemModuleId = declaringModuleId,
|
problemModuleId = declaringModuleId,
|
||||||
allModules = allModules,
|
allModules = allModules,
|
||||||
|
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
|
||||||
),
|
),
|
||||||
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
||||||
)
|
)
|
||||||
@@ -125,6 +127,7 @@ class SymbolTypeMismatch(
|
|||||||
problemCause = "This module contains ${
|
problemCause = "This module contains ${
|
||||||
idSignature?.render()?.let { "symbol $it" } ?: "a symbol"
|
idSignature?.render()?.let { "symbol $it" } ?: "a symbol"
|
||||||
} that is the cause of the conflict",
|
} that is the cause of the conflict",
|
||||||
|
sourceCodeModuleId = userVisibleIrModulesSupport.sourceCodeModuleId,
|
||||||
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
moduleIdComparator = userVisibleIrModulesSupport.moduleIdComparator
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -159,6 +162,7 @@ private fun StringBuilder.appendProjectDependencies(
|
|||||||
allModules: Map<ResolvedDependencyId, ResolvedDependency>,
|
allModules: Map<ResolvedDependencyId, ResolvedDependency>,
|
||||||
problemModuleIds: Set<ResolvedDependencyId>,
|
problemModuleIds: Set<ResolvedDependencyId>,
|
||||||
problemCause: String,
|
problemCause: String,
|
||||||
|
sourceCodeModuleId: ResolvedDependencyId,
|
||||||
moduleIdComparator: Comparator<ResolvedDependencyId>
|
moduleIdComparator: Comparator<ResolvedDependencyId>
|
||||||
) {
|
) {
|
||||||
append("\n\nProject dependencies:")
|
append("\n\nProject dependencies:")
|
||||||
@@ -195,8 +199,7 @@ private fun StringBuilder.appendProjectDependencies(
|
|||||||
append('\n').append(data.regularLinePrefix)
|
append('\n').append(data.regularLinePrefix)
|
||||||
append(module.id)
|
append(module.id)
|
||||||
|
|
||||||
val incomingDependencyId: ResolvedDependencyId = parentData?.incomingDependencyId
|
val incomingDependencyId: ResolvedDependencyId = parentData?.incomingDependencyId ?: sourceCodeModuleId
|
||||||
?: ResolvedDependencyId.SOURCE_CODE_MODULE_ID
|
|
||||||
val requestedVersion: ResolvedDependencyVersion = module.requestedVersionsByIncomingDependencies.getValue(incomingDependencyId)
|
val requestedVersion: ResolvedDependencyVersion = module.requestedVersionsByIncomingDependencies.getValue(incomingDependencyId)
|
||||||
if (!requestedVersion.isEmpty() || !module.selectedVersion.isEmpty()) {
|
if (!requestedVersion.isEmpty() || !module.selectedVersion.isEmpty()) {
|
||||||
append(": ")
|
append(": ")
|
||||||
@@ -240,8 +243,7 @@ private fun StringBuilder.appendProjectDependencies(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find first-level dependencies. I.e. the modules that the source code module directly depends on.
|
// Find first-level dependencies. I.e. the modules that the source code module directly depends on.
|
||||||
val firstLevelDependencies: Collection<ResolvedDependency> =
|
val firstLevelDependencies: Collection<ResolvedDependency> = incomingDependencyIdToDependencies.getValue(sourceCodeModuleId)
|
||||||
incomingDependencyIdToDependencies.getValue(ResolvedDependencyId.SOURCE_CODE_MODULE_ID)
|
|
||||||
|
|
||||||
renderModules(firstLevelDependencies, parentData = null)
|
renderModules(firstLevelDependencies, parentData = null)
|
||||||
|
|
||||||
@@ -375,7 +377,8 @@ private fun findPotentiallyConflictingOutgoingDependencies(
|
|||||||
*/
|
*/
|
||||||
private fun findPotentiallyConflictingIncomingDependencies(
|
private fun findPotentiallyConflictingIncomingDependencies(
|
||||||
problemModuleId: ResolvedDependencyId,
|
problemModuleId: ResolvedDependencyId,
|
||||||
allModules: Map<ResolvedDependencyId, ResolvedDependency>
|
allModules: Map<ResolvedDependencyId, ResolvedDependency>,
|
||||||
|
sourceCodeModuleId: ResolvedDependencyId
|
||||||
): Map<ResolvedDependencyId, PotentialConflictDescription> {
|
): Map<ResolvedDependencyId, PotentialConflictDescription> {
|
||||||
|
|
||||||
val dependencyStatesMap: MutableMap<ResolvedDependencyId, MutableSet<DependencyState>> = mutableMapOf()
|
val dependencyStatesMap: MutableMap<ResolvedDependencyId, MutableSet<DependencyState>> = mutableMapOf()
|
||||||
@@ -384,7 +387,7 @@ private fun findPotentiallyConflictingIncomingDependencies(
|
|||||||
val module = allModules.findMatchingModule(moduleId)
|
val module = allModules.findMatchingModule(moduleId)
|
||||||
|
|
||||||
module.requestedVersionsByIncomingDependencies.forEach { (incomingDependencyId, requestedVersion) ->
|
module.requestedVersionsByIncomingDependencies.forEach { (incomingDependencyId, requestedVersion) ->
|
||||||
if (incomingDependencyId == ResolvedDependencyId.SOURCE_CODE_MODULE_ID) return@forEach
|
if (incomingDependencyId == sourceCodeModuleId) return@forEach
|
||||||
|
|
||||||
val dependencyState: DependencyState = when {
|
val dependencyState: DependencyState = when {
|
||||||
aboveConflictingDependency -> {
|
aboveConflictingDependency -> {
|
||||||
|
|||||||
+31
-14
@@ -13,7 +13,7 @@ import org.jetbrains.kotlin.library.KotlinLibrary
|
|||||||
import org.jetbrains.kotlin.library.uniqueName
|
import org.jetbrains.kotlin.library.uniqueName
|
||||||
import org.jetbrains.kotlin.utils.*
|
import org.jetbrains.kotlin.utils.*
|
||||||
|
|
||||||
open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader: ExternalDependenciesLoader) {
|
open class UserVisibleIrModulesSupport(externalDependenciesLoader: ExternalDependenciesLoader) {
|
||||||
/**
|
/**
|
||||||
* Load external [ResolvedDependency]s provided by the build system. These dependencies:
|
* Load external [ResolvedDependency]s provided by the build system. These dependencies:
|
||||||
* - all have [ResolvedDependency.selectedVersion] specified
|
* - all have [ResolvedDependency.selectedVersion] specified
|
||||||
@@ -23,24 +23,24 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
|||||||
* not visible to the build system
|
* not visible to the build system
|
||||||
*/
|
*/
|
||||||
interface ExternalDependenciesLoader {
|
interface ExternalDependenciesLoader {
|
||||||
fun load(): Collection<ResolvedDependency>
|
fun load(): ResolvedDependencies
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val EMPTY = object : ExternalDependenciesLoader {
|
val EMPTY = object : ExternalDependenciesLoader {
|
||||||
override fun load(): Collection<ResolvedDependency> = emptyList()
|
override fun load(): ResolvedDependencies = ResolvedDependencies.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
fun from(externalDependenciesFile: File?, onMalformedExternalDependencies: (String) -> Unit): ExternalDependenciesLoader =
|
fun from(externalDependenciesFile: File?, onMalformedExternalDependencies: (String) -> Unit): ExternalDependenciesLoader =
|
||||||
if (externalDependenciesFile != null)
|
if (externalDependenciesFile != null)
|
||||||
object : ExternalDependenciesLoader {
|
object : ExternalDependenciesLoader {
|
||||||
override fun load(): Collection<ResolvedDependency> {
|
override fun load(): ResolvedDependencies {
|
||||||
return if (externalDependenciesFile.exists) {
|
return if (externalDependenciesFile.exists) {
|
||||||
// Deserialize external dependencies from the [externalDependenciesFile].
|
// Deserialize external dependencies from the [externalDependenciesFile].
|
||||||
val externalDependenciesText = String(externalDependenciesFile.readBytes())
|
val externalDependenciesText = String(externalDependenciesFile.readBytes())
|
||||||
ResolvedDependenciesSupport.deserialize(externalDependenciesText) { lineNo, line ->
|
ResolvedDependenciesSupport.deserialize(externalDependenciesText) { lineNo, line ->
|
||||||
onMalformedExternalDependencies("Malformed external dependencies at $externalDependenciesFile:$lineNo: $line")
|
onMalformedExternalDependencies("Malformed external dependencies at $externalDependenciesFile:$lineNo: $line")
|
||||||
}
|
}
|
||||||
} else emptyList()
|
} else ResolvedDependencies.EMPTY
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@@ -48,6 +48,16 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val externalDependencies: ResolvedDependencies by lazy {
|
||||||
|
externalDependenciesLoader.load()
|
||||||
|
}
|
||||||
|
|
||||||
|
private val externalDependencyModules: Collection<ResolvedDependency>
|
||||||
|
get() = externalDependencies.modules
|
||||||
|
|
||||||
|
val sourceCodeModuleId: ResolvedDependencyId
|
||||||
|
get() = externalDependencies.sourceCodeModuleId
|
||||||
|
|
||||||
fun getUserVisibleModuleId(deserializer: IrModuleDeserializer): ResolvedDependencyId {
|
fun getUserVisibleModuleId(deserializer: IrModuleDeserializer): ResolvedDependencyId {
|
||||||
val nameFromMetadataModuleHeader: String = deserializer.moduleFragment.name.asStringStripSpecialMarkers()
|
val nameFromMetadataModuleHeader: String = deserializer.moduleFragment.name.asStringStripSpecialMarkers()
|
||||||
val nameFromKlibManifest: String? = deserializer.kotlinLibrary?.uniqueName
|
val nameFromKlibManifest: String? = deserializer.kotlinLibrary?.uniqueName
|
||||||
@@ -65,23 +75,30 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
|||||||
* (and therefore are missing in [ExternalDependenciesLoader.load]) but are provided by the compiler. For Kotlin/Native such
|
* (and therefore are missing in [ExternalDependenciesLoader.load]) but are provided by the compiler. For Kotlin/Native such
|
||||||
* libraries are stdlib, endorsed and platform libraries.
|
* libraries are stdlib, endorsed and platform libraries.
|
||||||
*/
|
*/
|
||||||
protected open fun modulesFromDeserializers(deserializers: Collection<IrModuleDeserializer>): Map<ResolvedDependencyId, ResolvedDependency> {
|
protected open fun modulesFromDeserializers(
|
||||||
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.associate { deserializer ->
|
deserializers: Collection<IrModuleDeserializer>,
|
||||||
|
excludedModuleIds: Set<ResolvedDependencyId>
|
||||||
|
): Map<ResolvedDependencyId, ResolvedDependency> {
|
||||||
|
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.mapNotNull { deserializer ->
|
||||||
val moduleId = getUserVisibleModuleId(deserializer)
|
val moduleId = getUserVisibleModuleId(deserializer)
|
||||||
|
if (moduleId in excludedModuleIds) return@mapNotNull null
|
||||||
|
|
||||||
val module = ResolvedDependency(
|
val module = ResolvedDependency(
|
||||||
id = moduleId,
|
id = moduleId,
|
||||||
// TODO: support extracting all the necessary details for non-Native libs: selectedVersion, requestedVersions, artifacts
|
// TODO: support extracting all the necessary details for non-Native libs: selectedVersion, requestedVersions, artifacts
|
||||||
selectedVersion = ResolvedDependencyVersion.EMPTY,
|
selectedVersion = ResolvedDependencyVersion.EMPTY,
|
||||||
// Assumption: As we don't know for sure which modules the source code module depends on directly and which modules
|
// Assumption: As we don't know for sure which modules the source code module depends on directly and which modules
|
||||||
// it depends on transitively, so let's assume it depends on all modules directly.
|
// it depends on transitively, so let's assume it depends on all modules directly.
|
||||||
requestedVersionsByIncomingDependencies = mutableMapOf(ResolvedDependencyId.SOURCE_CODE_MODULE_ID to ResolvedDependencyVersion.EMPTY),
|
requestedVersionsByIncomingDependencies = mutableMapOf(
|
||||||
|
ResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID to ResolvedDependencyVersion.EMPTY
|
||||||
|
),
|
||||||
artifactPaths = mutableSetOf()
|
artifactPaths = mutableSetOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
val outgoingDependencyIds = deserializer.moduleDependencies.map { getUserVisibleModuleId(it) }
|
val outgoingDependencyIds = deserializer.moduleDependencies.map { getUserVisibleModuleId(it) }
|
||||||
|
|
||||||
moduleId to ModuleWithUninitializedDependencies(module, outgoingDependencyIds)
|
moduleId to ModuleWithUninitializedDependencies(module, outgoingDependencyIds)
|
||||||
}
|
}.toMap()
|
||||||
|
|
||||||
// Stamp dependencies.
|
// Stamp dependencies.
|
||||||
return modules.stampDependenciesWithRequestedVersionEqualToSelectedVersion()
|
return modules.stampDependenciesWithRequestedVersionEqualToSelectedVersion()
|
||||||
@@ -91,9 +108,6 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
|||||||
* The result of the merge of [ExternalDependenciesLoader.load] and [modulesFromDeserializers].
|
* The result of the merge of [ExternalDependenciesLoader.load] and [modulesFromDeserializers].
|
||||||
*/
|
*/
|
||||||
protected fun mergedModules(deserializers: Collection<IrModuleDeserializer>): MutableMap<ResolvedDependencyId, ResolvedDependency> {
|
protected fun mergedModules(deserializers: Collection<IrModuleDeserializer>): MutableMap<ResolvedDependencyId, ResolvedDependency> {
|
||||||
// First, load external dependencies.
|
|
||||||
val externalDependencyModules: Collection<ResolvedDependency> = externalDependenciesLoader.load()
|
|
||||||
|
|
||||||
val externalDependencyModulesByNames: Map</* unique name */ String, ResolvedDependency> =
|
val externalDependencyModulesByNames: Map</* unique name */ String, ResolvedDependency> =
|
||||||
mutableMapOf<String, ResolvedDependency>().apply {
|
mutableMapOf<String, ResolvedDependency>().apply {
|
||||||
externalDependencyModules.forEach { externalDependency ->
|
externalDependencyModules.forEach { externalDependency ->
|
||||||
@@ -118,7 +132,10 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
|||||||
val providedModules = mutableListOf<ResolvedDependency>()
|
val providedModules = mutableListOf<ResolvedDependency>()
|
||||||
|
|
||||||
// Next, merge external dependencies with dependencies from deserializers.
|
// Next, merge external dependencies with dependencies from deserializers.
|
||||||
modulesFromDeserializers(deserializers).forEach { (moduleId, module) ->
|
modulesFromDeserializers(
|
||||||
|
deserializers = deserializers,
|
||||||
|
excludedModuleIds = setOf(sourceCodeModuleId)
|
||||||
|
).forEach { (moduleId, module) ->
|
||||||
val externalDependencyModule = findMatchingExternalDependencyModule(moduleId)
|
val externalDependencyModule = findMatchingExternalDependencyModule(moduleId)
|
||||||
if (externalDependencyModule != null) {
|
if (externalDependencyModule != null) {
|
||||||
// Just add missing dependencies to the same module in [mergedModules].
|
// Just add missing dependencies to the same module in [mergedModules].
|
||||||
@@ -146,7 +163,7 @@ open class UserVisibleIrModulesSupport(protected val externalDependenciesLoader:
|
|||||||
// Just keep the module as is. If it has no incoming dependencies, then treat it as
|
// Just keep the module as is. If it has no incoming dependencies, then treat it as
|
||||||
// the first-level dependency module (i.e. the module that only the source code module depends on).
|
// the first-level dependency module (i.e. the module that only the source code module depends on).
|
||||||
if (module.requestedVersionsByIncomingDependencies.isEmpty()) {
|
if (module.requestedVersionsByIncomingDependencies.isEmpty()) {
|
||||||
module.requestedVersionsByIncomingDependencies[ResolvedDependencyId.SOURCE_CODE_MODULE_ID] = module.selectedVersion
|
module.requestedVersionsByIncomingDependencies[sourceCodeModuleId] = module.selectedVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -5,6 +5,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.util
|
package org.jetbrains.kotlin.util
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.utils.ResolvedDependencies
|
||||||
import org.jetbrains.kotlin.utils.ResolvedDependenciesSupport
|
import org.jetbrains.kotlin.utils.ResolvedDependenciesSupport
|
||||||
import org.junit.Assert.assertEquals
|
import org.junit.Assert.assertEquals
|
||||||
import org.junit.Assert.fail
|
import org.junit.Assert.fail
|
||||||
@@ -14,6 +15,7 @@ class ResolvedDependenciesSupportTest {
|
|||||||
@Test
|
@Test
|
||||||
fun success1() {
|
fun success1() {
|
||||||
val originalText = """
|
val originalText = """
|
||||||
|
|0 \
|
||||||
|1 io.ktor:ktor-io,io.ktor:ktor-io-macosx64[1.5.4] #0[1.5.4]
|
|1 io.ktor:ktor-io,io.ktor:ktor-io-macosx64[1.5.4] #0[1.5.4]
|
||||||
|${'\t'}/some/path/ktor-io.klib
|
|${'\t'}/some/path/ktor-io.klib
|
||||||
|${'\t'}/some/path/ktor-io-cinterop-bits.klib
|
|${'\t'}/some/path/ktor-io-cinterop-bits.klib
|
||||||
@@ -28,10 +30,10 @@ class ResolvedDependenciesSupportTest {
|
|||||||
|
|
|
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
|
|
||||||
val deserializedModules = ResolvedDependenciesSupport.deserialize(originalText) { lineNo, line ->
|
val (deserializedModules, sourceCodeModuleId) = ResolvedDependenciesSupport.deserialize(originalText) { lineNo, line ->
|
||||||
fail("Unexpected failure at line $lineNo: $line")
|
fail("Unexpected failure at line $lineNo: $line")
|
||||||
}
|
}
|
||||||
val restoredText = ResolvedDependenciesSupport.serialize(deserializedModules)
|
val restoredText = ResolvedDependenciesSupport.serialize(ResolvedDependencies(deserializedModules, sourceCodeModuleId))
|
||||||
|
|
||||||
assertEquals(originalText, restoredText)
|
assertEquals(originalText, restoredText)
|
||||||
}
|
}
|
||||||
@@ -39,6 +41,7 @@ class ResolvedDependenciesSupportTest {
|
|||||||
@Test
|
@Test
|
||||||
fun success2() {
|
fun success2() {
|
||||||
val originalText = """
|
val originalText = """
|
||||||
|
|0 \
|
||||||
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
||||||
|${'\t'}/some/path/liba.klib
|
|${'\t'}/some/path/liba.klib
|
||||||
|2 org.sample:libb,org.sample:libb-native[1.0] #0[1.0]
|
|2 org.sample:libb,org.sample:libb-native[1.0] #0[1.0]
|
||||||
@@ -46,10 +49,10 @@ class ResolvedDependenciesSupportTest {
|
|||||||
|
|
|
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
|
|
||||||
val deserializedModules = ResolvedDependenciesSupport.deserialize(originalText) { lineNo, line ->
|
val (deserializedModules, sourceCodeModuleId) = ResolvedDependenciesSupport.deserialize(originalText) { lineNo, line ->
|
||||||
fail("Unexpected failure at line $lineNo: $line")
|
fail("Unexpected failure at line $lineNo: $line")
|
||||||
}
|
}
|
||||||
val restoredText = ResolvedDependenciesSupport.serialize(deserializedModules)
|
val restoredText = ResolvedDependenciesSupport.serialize(ResolvedDependencies(deserializedModules, sourceCodeModuleId))
|
||||||
|
|
||||||
assertEquals(originalText, restoredText)
|
assertEquals(originalText, restoredText)
|
||||||
}
|
}
|
||||||
@@ -57,6 +60,7 @@ class ResolvedDependenciesSupportTest {
|
|||||||
@Test
|
@Test
|
||||||
fun success3() {
|
fun success3() {
|
||||||
val originalText = """
|
val originalText = """
|
||||||
|
|0 \
|
||||||
|1 org.jetbrains.kotlin:kotlin-stdlib-common[1.5.0] #2[1.4.32] #3[1.5.0] #4[1.5.0] #5[1.4.32] #6[1.4.32] #7[1.4.32] #8[1.4.32]
|
|1 org.jetbrains.kotlin:kotlin-stdlib-common[1.5.0] #2[1.4.32] #3[1.5.0] #4[1.5.0] #5[1.4.32] #6[1.4.32] #7[1.4.32] #8[1.4.32]
|
||||||
|${'\t'}/some/path/kotlin-stdlib-common-1.5.0.jar
|
|${'\t'}/some/path/kotlin-stdlib-common-1.5.0.jar
|
||||||
|2 io.ktor:ktor-client-core,io.ktor:ktor-client-core-macosx64[1.5.4] #0[1.5.4]
|
|2 io.ktor:ktor-client-core,io.ktor:ktor-client-core-macosx64[1.5.4] #0[1.5.4]
|
||||||
@@ -80,10 +84,29 @@ class ResolvedDependenciesSupportTest {
|
|||||||
|
|
|
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
|
|
||||||
val deserializedModules = ResolvedDependenciesSupport.deserialize(originalText) { lineNo, line ->
|
val (deserializedModules, sourceCodeModuleId) = ResolvedDependenciesSupport.deserialize(originalText) { lineNo, line ->
|
||||||
fail("Unexpected failure at line $lineNo: $line")
|
fail("Unexpected failure at line $lineNo: $line")
|
||||||
}
|
}
|
||||||
val restoredText = ResolvedDependenciesSupport.serialize(deserializedModules)
|
val restoredText = ResolvedDependenciesSupport.serialize(ResolvedDependencies(deserializedModules, sourceCodeModuleId))
|
||||||
|
|
||||||
|
assertEquals(originalText, restoredText)
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun success4() {
|
||||||
|
val originalText = """
|
||||||
|
|0 baz-native,foo,org.sample.bar
|
||||||
|
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
||||||
|
|${'\t'}/some/path/liba.klib
|
||||||
|
|2 org.sample:libb,org.sample:libb-native[1.0] #0[1.0]
|
||||||
|
|${'\t'}/some/path/libb.klib
|
||||||
|
|
|
||||||
|
""".trimMargin()
|
||||||
|
|
||||||
|
val (deserializedModules, sourceCodeModuleId) = ResolvedDependenciesSupport.deserialize(originalText) { lineNo, line ->
|
||||||
|
fail("Unexpected failure at line $lineNo: $line")
|
||||||
|
}
|
||||||
|
val restoredText = ResolvedDependenciesSupport.serialize(ResolvedDependencies(deserializedModules, sourceCodeModuleId))
|
||||||
|
|
||||||
assertEquals(originalText, restoredText)
|
assertEquals(originalText, restoredText)
|
||||||
}
|
}
|
||||||
@@ -92,6 +115,7 @@ class ResolvedDependenciesSupportTest {
|
|||||||
fun failure1() {
|
fun failure1() {
|
||||||
// There is no record with number 42!
|
// There is no record with number 42!
|
||||||
val originalText = """
|
val originalText = """
|
||||||
|
|0 \
|
||||||
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0] #42[42.42]
|
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0] #42[42.42]
|
||||||
|${'\t'}/some/path/liba.klib
|
|${'\t'}/some/path/liba.klib
|
||||||
|2 org.sample:libb,org.sample:libb-native[1.0] #0[1.0]
|
|2 org.sample:libb,org.sample:libb-native[1.0] #0[1.0]
|
||||||
@@ -99,13 +123,19 @@ class ResolvedDependenciesSupportTest {
|
|||||||
|
|
|
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
|
|
||||||
ResolvedDependenciesSupport.deserialize(originalText) { _, _ -> throw MyException() }
|
ResolvedDependenciesSupport.deserialize(originalText) { lineNo, _ ->
|
||||||
|
assertEquals(1, lineNo)
|
||||||
|
throw MyException()
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = MyException::class)
|
@Test(expected = MyException::class)
|
||||||
fun failure2() {
|
fun failure2() {
|
||||||
// Name not specified.
|
// Name not specified.
|
||||||
val originalText = """
|
val originalText = """
|
||||||
|
|0 \
|
||||||
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
||||||
|${'\t'}/some/path/liba.klib
|
|${'\t'}/some/path/liba.klib
|
||||||
|2 [1.0] #0[1.0]
|
|2 [1.0] #0[1.0]
|
||||||
@@ -113,13 +143,58 @@ class ResolvedDependenciesSupportTest {
|
|||||||
|
|
|
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
|
|
||||||
ResolvedDependenciesSupport.deserialize(originalText) { _, _ -> throw MyException() }
|
ResolvedDependenciesSupport.deserialize(originalText) { lineNo, _ ->
|
||||||
|
assertEquals(3, lineNo)
|
||||||
|
throw MyException()
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
@Test(expected = MyException::class)
|
@Test(expected = MyException::class)
|
||||||
fun failure3() {
|
fun failure3() {
|
||||||
// Version not specified.
|
// Version not specified.
|
||||||
val originalText = """
|
val originalText = """
|
||||||
|
|0 \
|
||||||
|
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
||||||
|
|${'\t'}/some/path/liba.klib
|
||||||
|
|2 org.sample:libb,org.sample:libb-native #0[1.0]
|
||||||
|
|${'\t'}/some/path/libb.klib
|
||||||
|
|
|
||||||
|
""".trimMargin()
|
||||||
|
|
||||||
|
ResolvedDependenciesSupport.deserialize(originalText) { lineNo, _ ->
|
||||||
|
assertEquals(3, lineNo)
|
||||||
|
throw MyException()
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = MyException::class)
|
||||||
|
fun failure4() {
|
||||||
|
// Source code module ID not specified.
|
||||||
|
val originalText = """
|
||||||
|
|0
|
||||||
|
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
||||||
|
|${'\t'}/some/path/liba.klib
|
||||||
|
|2 org.sample:libb,org.sample:libb-native #0[1.0]
|
||||||
|
|${'\t'}/some/path/libb.klib
|
||||||
|
|
|
||||||
|
""".trimMargin()
|
||||||
|
|
||||||
|
ResolvedDependenciesSupport.deserialize(originalText) { lineNo, _ ->
|
||||||
|
assertEquals(0, lineNo)
|
||||||
|
throw MyException()
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test(expected = MyException::class)
|
||||||
|
fun failure5() {
|
||||||
|
// Source code module ID not specified.
|
||||||
|
val originalText = """
|
||||||
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
|1 org.sample:liba,org.sample:liba-native[2.0] #0[2.0] #2[1.0]
|
||||||
|${'\t'}/some/path/liba.klib
|
|${'\t'}/some/path/liba.klib
|
||||||
|2 org.sample:libb,org.sample:libb-native #0[1.0]
|
|2 org.sample:libb,org.sample:libb-native #0[1.0]
|
||||||
@@ -127,7 +202,12 @@ class ResolvedDependenciesSupportTest {
|
|||||||
|
|
|
|
||||||
""".trimMargin()
|
""".trimMargin()
|
||||||
|
|
||||||
ResolvedDependenciesSupport.deserialize(originalText) { _, _ -> throw MyException() }
|
ResolvedDependenciesSupport.deserialize(originalText) { lineNo, _ ->
|
||||||
|
assertEquals(0, lineNo)
|
||||||
|
throw MyException()
|
||||||
|
}
|
||||||
|
|
||||||
|
fail()
|
||||||
}
|
}
|
||||||
|
|
||||||
private class MyException : Exception()
|
private class MyException : Exception()
|
||||||
|
|||||||
@@ -47,7 +47,7 @@ class ResolvedDependencyIdTest {
|
|||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun toStringImplementation() {
|
fun toStringImplementation() {
|
||||||
assertEquals("/", ResolvedDependencyId.SOURCE_CODE_MODULE_ID.toString())
|
assertEquals("/", ResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID.toString())
|
||||||
assertEquals("foo", ResolvedDependencyId("foo").toString())
|
assertEquals("foo", ResolvedDependencyId("foo").toString())
|
||||||
assertEquals("bar (foo)", ResolvedDependencyId("foo", "bar").toString())
|
assertEquals("bar (foo)", ResolvedDependencyId("foo", "bar").toString())
|
||||||
assertEquals("bar (baz, foo)", ResolvedDependencyId("foo", "bar", "baz").toString())
|
assertEquals("bar (baz, foo)", ResolvedDependencyId("foo", "bar", "baz").toString())
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ class ResolvedDependencyId private constructor(val uniqueNames: Set<String>) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val SOURCE_CODE_MODULE_ID = ResolvedDependencyId("/")
|
val DEFAULT_SOURCE_CODE_MODULE_ID = ResolvedDependencyId("/")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,8 +58,8 @@ class ResolvedDependencyId private constructor(val uniqueNames: Set<String>) {
|
|||||||
* - [requestedVersionsByIncomingDependencies] the mapping between ID of the dependee module (i.e. the module that depends on this module)
|
* - [requestedVersionsByIncomingDependencies] the mapping between ID of the dependee module (i.e. the module that depends on this module)
|
||||||
* and the version (requested version) that the dependee module requires from this module. The requested version can be different
|
* and the version (requested version) that the dependee module requires from this module. The requested version can be different
|
||||||
* for different dependee modules, which is absolutely legal. The [selectedVersion] is always equal to one of the requested versions
|
* for different dependee modules, which is absolutely legal. The [selectedVersion] is always equal to one of the requested versions
|
||||||
* (the one that wins among others, which is typically handled inside of the build system). If the module is the top-level module,
|
* (the one that wins among others, which is typically handled inside the build system). If the module is the top-level module,
|
||||||
* then it has [ResolvedDependencyId.SOURCE_CODE_MODULE_ID] in the mapping.
|
* then it has [ResolvedDependencies.sourceCodeModuleId] in the mapping.
|
||||||
* - [artifactPaths] absolute paths to every artifact represented by this module
|
* - [artifactPaths] absolute paths to every artifact represented by this module
|
||||||
*/
|
*/
|
||||||
class ResolvedDependency(
|
class ResolvedDependency(
|
||||||
@@ -75,14 +75,27 @@ class ResolvedDependency(
|
|||||||
override fun toString() = moduleIdWithVersion
|
override fun toString() = moduleIdWithVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class ResolvedDependencies(
|
||||||
|
val modules: Collection<ResolvedDependency>,
|
||||||
|
val sourceCodeModuleId: ResolvedDependencyId
|
||||||
|
) {
|
||||||
|
companion object {
|
||||||
|
val EMPTY = ResolvedDependencies(emptyList(), ResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
object ResolvedDependenciesSupport {
|
object ResolvedDependenciesSupport {
|
||||||
fun serialize(modules: Collection<ResolvedDependency>): String {
|
fun serialize(dependencies: ResolvedDependencies): String {
|
||||||
val moduleIdToIndex = mutableMapOf(ResolvedDependencyId.SOURCE_CODE_MODULE_ID to 0).apply {
|
val moduleIdToIndex = mutableMapOf(dependencies.sourceCodeModuleId to 0).apply {
|
||||||
modules.forEachIndexed { index, module -> this[module.id] = index + 1 }
|
dependencies.modules.forEachIndexed { index, module -> this[module.id] = index + 1 }
|
||||||
}
|
}
|
||||||
|
|
||||||
return buildString {
|
return buildString {
|
||||||
modules.forEach { module ->
|
append("0 ")
|
||||||
|
dependencies.sourceCodeModuleId.uniqueNames.joinTo(this, separator = ",")
|
||||||
|
append('\n')
|
||||||
|
|
||||||
|
dependencies.modules.forEach { module ->
|
||||||
val moduleIndex = moduleIdToIndex.getValue(module.id)
|
val moduleIndex = moduleIdToIndex.getValue(module.id)
|
||||||
append(moduleIndex.toString()).append(' ')
|
append(moduleIndex.toString()).append(' ')
|
||||||
module.id.uniqueNames.joinTo(this, separator = ",")
|
module.id.uniqueNames.joinTo(this, separator = ",")
|
||||||
@@ -100,17 +113,18 @@ object ResolvedDependenciesSupport {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fun deserialize(source: String, onMalformedLine: (lineNo: Int, line: String) -> Unit): Collection<ResolvedDependency> {
|
fun deserialize(source: String, onMalformedLine: (lineNo: Int, line: String) -> Unit): ResolvedDependencies {
|
||||||
val moduleIndexToId: MutableMap<Int, ResolvedDependencyId> = mutableMapOf(0 to ResolvedDependencyId.SOURCE_CODE_MODULE_ID)
|
val moduleIndexToId: MutableMap<Int, ResolvedDependencyId> = mutableMapOf()
|
||||||
val requestedVersionsByIncomingDependenciesIndices: MutableMap<ResolvedDependencyId, Map<Int, ResolvedDependencyVersion>> =
|
val requestedVersionsByIncomingDependenciesIndices: MutableMap<ResolvedDependencyId, Map<Int, ResolvedDependencyVersion>> =
|
||||||
mutableMapOf()
|
mutableMapOf()
|
||||||
|
|
||||||
|
var sourceCodeModuleId: ResolvedDependencyId? = null
|
||||||
val modules = mutableListOf<ResolvedDependency>()
|
val modules = mutableListOf<ResolvedDependency>()
|
||||||
|
|
||||||
source.lines().forEachIndexed { lineNo, line ->
|
source.lines().forEachIndexed { lineNo, line ->
|
||||||
fun malformedLine(): Collection<ResolvedDependency> {
|
fun malformedLine(): ResolvedDependencies {
|
||||||
onMalformedLine(lineNo, line)
|
onMalformedLine(lineNo, line)
|
||||||
return emptyList()
|
return ResolvedDependencies.EMPTY
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
when {
|
||||||
@@ -123,7 +137,13 @@ object ResolvedDependenciesSupport {
|
|||||||
else
|
else
|
||||||
return malformedLine()
|
return malformedLine()
|
||||||
}
|
}
|
||||||
|
line[0] == '0' -> {
|
||||||
|
val result = SOURCE_CODE_MODULE_REGEX.matchEntire(line) ?: return malformedLine()
|
||||||
|
sourceCodeModuleId = ResolvedDependencyId(result.groupValues[1].split(','))
|
||||||
|
}
|
||||||
else -> {
|
else -> {
|
||||||
|
if (sourceCodeModuleId == null) return malformedLine()
|
||||||
|
|
||||||
val result = DEPENDENCY_MODULE_REGEX.matchEntire(line) ?: return malformedLine()
|
val result = DEPENDENCY_MODULE_REGEX.matchEntire(line) ?: return malformedLine()
|
||||||
val moduleIndex = result.groupValues[1].toInt()
|
val moduleIndex = result.groupValues[1].toInt()
|
||||||
val moduleId = ResolvedDependencyId(result.groupValues[2].split(','))
|
val moduleId = ResolvedDependencyId(result.groupValues[2].split(','))
|
||||||
@@ -156,14 +176,18 @@ object ResolvedDependenciesSupport {
|
|||||||
// Stamp incoming dependencies & requested versions.
|
// Stamp incoming dependencies & requested versions.
|
||||||
modules.forEach { module ->
|
modules.forEach { module ->
|
||||||
requestedVersionsByIncomingDependenciesIndices[module.id]?.forEach { (incomingDependencyIndex, requestedVersion) ->
|
requestedVersionsByIncomingDependenciesIndices[module.id]?.forEach { (incomingDependencyIndex, requestedVersion) ->
|
||||||
val incomingDependencyId = moduleIndexToId.getValue(incomingDependencyIndex)
|
val incomingDependencyId = if (incomingDependencyIndex == 0)
|
||||||
|
sourceCodeModuleId!!
|
||||||
|
else
|
||||||
|
moduleIndexToId.getValue(incomingDependencyIndex)
|
||||||
module.requestedVersionsByIncomingDependencies[incomingDependencyId] = requestedVersion
|
module.requestedVersionsByIncomingDependencies[incomingDependencyId] = requestedVersion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return modules
|
return ResolvedDependencies(modules, sourceCodeModuleId!!)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private val SOURCE_CODE_MODULE_REGEX = Regex("^0 ([^\\[]+)$")
|
||||||
private val DEPENDENCY_MODULE_REGEX = Regex("^(\\d+) ([^\\[]+)\\[([^]]+)](.*)?$")
|
private val DEPENDENCY_MODULE_REGEX = Regex("^(\\d+) ([^\\[]+)\\[([^]]+)](.*)?$")
|
||||||
private val REQUESTED_VERSION_BY_INCOMING_DEPENDENCY_REGEX = Regex("^#(\\d+)\\[(.*)]$")
|
private val REQUESTED_VERSION_BY_INCOMING_DEPENDENCY_REGEX = Regex("^#(\\d+)\\[(.*)]$")
|
||||||
}
|
}
|
||||||
|
|||||||
+12
-5
@@ -26,7 +26,10 @@ class KonanUserVisibleIrModulesSupport(
|
|||||||
return compressedModules(deserializers)
|
return compressedModules(deserializers)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun modulesFromDeserializers(deserializers: Collection<IrModuleDeserializer>): Map<ResolvedDependencyId, ResolvedDependency> {
|
override fun modulesFromDeserializers(
|
||||||
|
deserializers: Collection<IrModuleDeserializer>,
|
||||||
|
excludedModuleIds: Set<ResolvedDependencyId>
|
||||||
|
): Map<ResolvedDependencyId, ResolvedDependency> {
|
||||||
val moduleToCompilerVersion: MutableMap<ResolvedDependencyId, ResolvedDependencyVersion> = mutableMapOf()
|
val moduleToCompilerVersion: MutableMap<ResolvedDependencyId, ResolvedDependencyVersion> = mutableMapOf()
|
||||||
val kotlinNativeBundledLibraries: MutableSet<ResolvedDependencyId> = mutableSetOf()
|
val kotlinNativeBundledLibraries: MutableSet<ResolvedDependencyId> = mutableSetOf()
|
||||||
|
|
||||||
@@ -34,6 +37,9 @@ class KonanUserVisibleIrModulesSupport(
|
|||||||
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.mapNotNull { deserializer ->
|
val modules: Map<ResolvedDependencyId, ModuleWithUninitializedDependencies> = deserializers.mapNotNull { deserializer ->
|
||||||
val library: KotlinLibrary = deserializer.kotlinLibrary ?: return@mapNotNull null
|
val library: KotlinLibrary = deserializer.kotlinLibrary ?: return@mapNotNull null
|
||||||
|
|
||||||
|
val moduleId = getUserVisibleModuleId(deserializer)
|
||||||
|
if (moduleId in excludedModuleIds) return@mapNotNull null
|
||||||
|
|
||||||
val compilerVersion: ResolvedDependencyVersion = library.compilerVersion
|
val compilerVersion: ResolvedDependencyVersion = library.compilerVersion
|
||||||
val isDefaultLibrary = library.isDefaultLibrary
|
val isDefaultLibrary = library.isDefaultLibrary
|
||||||
|
|
||||||
@@ -41,7 +47,6 @@ class KonanUserVisibleIrModulesSupport(
|
|||||||
// Note: Empty string means missing (unknown) version.
|
// Note: Empty string means missing (unknown) version.
|
||||||
val libraryVersion: ResolvedDependencyVersion = if (isDefaultLibrary) compilerVersion else ResolvedDependencyVersion.EMPTY
|
val libraryVersion: ResolvedDependencyVersion = if (isDefaultLibrary) compilerVersion else ResolvedDependencyVersion.EMPTY
|
||||||
|
|
||||||
val moduleId = getUserVisibleModuleId(deserializer)
|
|
||||||
val module = ResolvedDependency(
|
val module = ResolvedDependency(
|
||||||
id = moduleId,
|
id = moduleId,
|
||||||
selectedVersion = libraryVersion,
|
selectedVersion = libraryVersion,
|
||||||
@@ -54,7 +59,9 @@ class KonanUserVisibleIrModulesSupport(
|
|||||||
|
|
||||||
// Don't rely on dependencies in IrModuleDeserializer. In Kotlin/Native each module depends on all other modules,
|
// Don't rely on dependencies in IrModuleDeserializer. In Kotlin/Native each module depends on all other modules,
|
||||||
// and this contradicts with the real module dependencies as written in KLIB manifest files.
|
// and this contradicts with the real module dependencies as written in KLIB manifest files.
|
||||||
val outgoingDependencyIds = library.unresolvedDependencies.map { it.moduleId }
|
val outgoingDependencyIds = library.unresolvedDependencies.mapNotNull { unresolvedDependency ->
|
||||||
|
unresolvedDependency.moduleId.takeIf { it !in excludedModuleIds }
|
||||||
|
}
|
||||||
|
|
||||||
moduleId to ModuleWithUninitializedDependencies(module, outgoingDependencyIds)
|
moduleId to ModuleWithUninitializedDependencies(module, outgoingDependencyIds)
|
||||||
}.toMap()
|
}.toMap()
|
||||||
@@ -87,7 +94,7 @@ class KonanUserVisibleIrModulesSupport(
|
|||||||
|
|
||||||
for ((moduleId, module) in compressedModules) {
|
for ((moduleId, module) in compressedModules) {
|
||||||
if (moduleId.isKonanPlatformLibrary) {
|
if (moduleId.isKonanPlatformLibrary) {
|
||||||
if (ResolvedDependencyId.SOURCE_CODE_MODULE_ID !in module.requestedVersionsByIncomingDependencies) {
|
if (sourceCodeModuleId !in module.requestedVersionsByIncomingDependencies) {
|
||||||
continue
|
continue
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -116,7 +123,7 @@ class KonanUserVisibleIrModulesSupport(
|
|||||||
val compressedModule = ResolvedDependency(
|
val compressedModule = ResolvedDependency(
|
||||||
id = compressedModuleId,
|
id = compressedModuleId,
|
||||||
selectedVersion = platformLibrariesVersion!!,
|
selectedVersion = platformLibrariesVersion!!,
|
||||||
requestedVersionsByIncomingDependencies = mutableMapOf(ResolvedDependencyId.SOURCE_CODE_MODULE_ID to platformLibrariesVersion),
|
requestedVersionsByIncomingDependencies = mutableMapOf(sourceCodeModuleId to platformLibrariesVersion),
|
||||||
artifactPaths = mutableSetOf()
|
artifactPaths = mutableSetOf()
|
||||||
)
|
)
|
||||||
|
|
||||||
|
|||||||
+2
@@ -31,6 +31,7 @@ class NativeExternalDependenciesIT : BaseGradleIT() {
|
|||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"""
|
"""
|
||||||
|
|0 native-external-dependencies
|
||||||
|1 io.ktor:ktor-io,io.ktor:ktor-io-$MASKED_TARGET_NAME[1.5.4] #0[1.5.4]
|
|1 io.ktor:ktor-io,io.ktor:ktor-io-$MASKED_TARGET_NAME[1.5.4] #0[1.5.4]
|
||||||
|${'\t'}/some/path/ktor-io.klib
|
|${'\t'}/some/path/ktor-io.klib
|
||||||
|${'\t'}/some/path/ktor-io-cinterop-bits.klib
|
|${'\t'}/some/path/ktor-io-cinterop-bits.klib
|
||||||
@@ -55,6 +56,7 @@ class NativeExternalDependenciesIT : BaseGradleIT() {
|
|||||||
|
|
||||||
assertEquals(
|
assertEquals(
|
||||||
"""
|
"""
|
||||||
|
|0 native-external-dependencies
|
||||||
|1 io.ktor:ktor-io,io.ktor:ktor-io-$MASKED_TARGET_NAME[1.5.4] #0[1.5.4]
|
|1 io.ktor:ktor-io,io.ktor:ktor-io-$MASKED_TARGET_NAME[1.5.4] #0[1.5.4]
|
||||||
|${'\t'}/some/path/ktor-io.klib
|
|${'\t'}/some/path/ktor-io.klib
|
||||||
|${'\t'}/some/path/ktor-io-cinterop-bits.klib
|
|${'\t'}/some/path/ktor-io-cinterop-bits.klib
|
||||||
|
|||||||
+170
-81
@@ -10,8 +10,9 @@ import org.jetbrains.kotlin.gradle.GradleVersionRequired
|
|||||||
import org.jetbrains.kotlin.gradle.native.NativeExternalDependenciesIT.Companion.MASKED_TARGET_NAME
|
import org.jetbrains.kotlin.gradle.native.NativeExternalDependenciesIT.Companion.MASKED_TARGET_NAME
|
||||||
import org.jetbrains.kotlin.gradle.native.NativeExternalDependenciesIT.Companion.findKotlinNativeTargetName
|
import org.jetbrains.kotlin.gradle.native.NativeExternalDependenciesIT.Companion.findKotlinNativeTargetName
|
||||||
import org.jetbrains.kotlin.gradle.native.NativeExternalDependenciesIT.Companion.findParameterInOutput
|
import org.jetbrains.kotlin.gradle.native.NativeExternalDependenciesIT.Companion.findParameterInOutput
|
||||||
|
import org.jetbrains.kotlin.konan.library.KONAN_PLATFORM_LIBS_NAME_PREFIX
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.junit.Assume
|
import org.junit.Assume.assumeFalse
|
||||||
import org.junit.Assume.assumeTrue
|
import org.junit.Assume.assumeTrue
|
||||||
import org.junit.Test
|
import org.junit.Test
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -23,84 +24,16 @@ class NativeIrLinkerIssuesIT : BaseGradleIT() {
|
|||||||
override val defaultGradleVersion: GradleVersionRequired
|
override val defaultGradleVersion: GradleVersionRequired
|
||||||
get() = GradleVersionRequired.FOR_MPP_SUPPORT
|
get() = GradleVersionRequired.FOR_MPP_SUPPORT
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `declaration that is gone (KT-41378)`() {
|
|
||||||
val repo = setupLocalRepo()
|
|
||||||
|
|
||||||
buildAndPublishLibrary("native-ir-linker-issues-gone-declaration", "liba-v1.0", repo)
|
|
||||||
buildAndPublishLibrary("native-ir-linker-issues-gone-declaration", "liba-v2.0", repo)
|
|
||||||
buildAndPublishLibrary("native-ir-linker-issues-gone-declaration", "libb", repo)
|
|
||||||
|
|
||||||
buildApplicationAndFail(
|
|
||||||
directory = "native-ir-linker-issues-gone-declaration",
|
|
||||||
projectName = "app",
|
|
||||||
localRepo = repo
|
|
||||||
) { kotlinNativeCompilerVersion ->
|
|
||||||
"""
|
|
||||||
|e: Module "org.sample:libb (org.sample:libb-native)" has a reference to symbol sample.liba/C|null[0]. Neither the module itself nor its dependencies contain such declaration.
|
|
||||||
|
|
|
||||||
|This could happen if the required dependency is missing in the project. Or if there is a dependency of "org.sample:libb (org.sample:libb-native)" that has a different version in the project than the version that "org.sample:libb (org.sample:libb-native): 1.0" was initially compiled with. Please check that the project configuration is correct and has consistent versions of all required dependencies.
|
|
||||||
|
|
|
||||||
|The list of "org.sample:libb (org.sample:libb-native): 1.0" dependencies that may lead to conflicts:
|
|
||||||
|1. "org.sample:liba (org.sample:liba-native): 2.0" (was initially compiled with "org.sample:liba (org.sample:liba-native): 1.0")
|
|
||||||
|
|
|
||||||
|Project dependencies:
|
|
||||||
|├─── org.sample:liba (org.sample:liba-native): 2.0
|
|
||||||
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
|
||||||
|└─── org.sample:libb (org.sample:libb-native): 1.0
|
|
||||||
| ^^^ This module requires symbol sample.liba/C|null[0].
|
|
||||||
| ├─── org.sample:liba (org.sample:liba-native): 1.0 -> 2.0 (*)
|
|
||||||
| └─── stdlib: $kotlinNativeCompilerVersion
|
|
||||||
|
|
|
||||||
|(*) - dependencies omitted (listed previously)
|
|
||||||
""".trimMargin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
|
||||||
fun `symbol type mismatch (KT-47285)`() {
|
|
||||||
val repo = setupLocalRepo()
|
|
||||||
|
|
||||||
buildAndPublishLibrary("native-ir-linker-issues-symbol-mismatch", "liba-v1.0", repo)
|
|
||||||
buildAndPublishLibrary("native-ir-linker-issues-symbol-mismatch", "liba-v2.0", repo)
|
|
||||||
buildAndPublishLibrary("native-ir-linker-issues-symbol-mismatch", "libb", repo)
|
|
||||||
|
|
||||||
buildApplicationAndFail(
|
|
||||||
directory = "native-ir-linker-issues-symbol-mismatch",
|
|
||||||
projectName = "app",
|
|
||||||
localRepo = repo
|
|
||||||
) { kotlinNativeCompilerVersion ->
|
|
||||||
"""
|
|
||||||
|e: The symbol of unexpected type encountered during IR deserialization: IrClassPublicSymbolImpl, sample.liba/B|null[0]. IrTypeAliasSymbol is expected.
|
|
||||||
|
|
|
||||||
|This could happen if there are two libraries, where one library was compiled against the different version of the other library than the one currently used in the project. Please check that the project configuration is correct and has consistent versions of dependencies.
|
|
||||||
|
|
|
||||||
|The list of libraries that depend on "org.sample:liba (org.sample:liba-native)" and may lead to conflicts:
|
|
||||||
|1. "org.sample:libb (org.sample:libb-native): 1.0" (was compiled against "org.sample:liba (org.sample:liba-native): 1.0" but "org.sample:liba (org.sample:liba-native): 2.0" is used in the project)
|
|
||||||
|
|
|
||||||
|Project dependencies:
|
|
||||||
|├─── org.sample:liba (org.sample:liba-native): 2.0
|
|
||||||
|│ ^^^ This module contains symbol sample.liba/B|null[0] that is the cause of the conflict.
|
|
||||||
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
|
||||||
|└─── org.sample:libb (org.sample:libb-native): 1.0
|
|
||||||
| ├─── org.sample:liba (org.sample:liba-native): 1.0 -> 2.0 (*)
|
|
||||||
| │ ^^^ This module contains symbol sample.liba/B|null[0] that is the cause of the conflict.
|
|
||||||
| └─── stdlib: $kotlinNativeCompilerVersion
|
|
||||||
|
|
|
||||||
|(*) - dependencies omitted (listed previously)
|
|
||||||
""".trimMargin()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `ktor 1_5_4 and coroutines 1_5_0-RC-native-mt (KT-46697)`() {
|
fun `ktor 1_5_4 and coroutines 1_5_0-RC-native-mt (KT-46697)`() {
|
||||||
// Run this test only on macOS.
|
// Run this test only on macOS.
|
||||||
assumeTrue(HostManager.hostIsMac)
|
assumeTrue(HostManager.hostIsMac)
|
||||||
|
|
||||||
buildApplicationAndFail(
|
buildApplicationAndFail(
|
||||||
directory = null,
|
directoryPrefix = null,
|
||||||
projectName = "native-ir-linker-issues-ktor-and-coroutines",
|
projectName = "native-ir-linker-issues-ktor-and-coroutines",
|
||||||
localRepo = null
|
localRepo = null,
|
||||||
|
useCache = true
|
||||||
) { kotlinNativeCompilerVersion ->
|
) { kotlinNativeCompilerVersion ->
|
||||||
"""
|
"""
|
||||||
|e: The symbol of unexpected type encountered during IR deserialization: IrClassPublicSymbolImpl, kotlinx.coroutines/CancellationException|null[0]. IrTypeAliasSymbol is expected.
|
|e: The symbol of unexpected type encountered during IR deserialization: IrClassPublicSymbolImpl, kotlinx.coroutines/CancellationException|null[0]. IrTypeAliasSymbol is expected.
|
||||||
@@ -173,13 +106,154 @@ class NativeIrLinkerIssuesIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildApplicationAndFail(
|
@Test
|
||||||
directory: String?,
|
fun `declaration that is gone (KT-41378) - with cache`() {
|
||||||
projectName: String,
|
// Don't run it on Windows. Caches are not supported there yet.
|
||||||
localRepo: File?,
|
assumeFalse(HostManager.hostIsMingw)
|
||||||
|
|
||||||
|
buildConflictingLibrariesAndApplication(
|
||||||
|
directoryPrefix = "native-ir-linker-issues-gone-declaration",
|
||||||
|
useCache = true
|
||||||
|
) { kotlinNativeCompilerVersion ->
|
||||||
|
"""
|
||||||
|
|e: Module "org.sample:libb (org.sample:libb-native)" has a reference to symbol sample.liba/C|null[0]. Neither the module itself nor its dependencies contain such declaration.
|
||||||
|
|
|
||||||
|
|This could happen if the required dependency is missing in the project. Or if there is a dependency of "org.sample:libb (org.sample:libb-native)" that has a different version in the project than the version that "org.sample:libb (org.sample:libb-native): 1.0" was initially compiled with. Please check that the project configuration is correct and has consistent versions of all required dependencies.
|
||||||
|
|
|
||||||
|
|The list of "org.sample:libb (org.sample:libb-native): 1.0" dependencies that may lead to conflicts:
|
||||||
|
|1. "org.sample:liba (org.sample:liba-native): 2.0" (was initially compiled with "org.sample:liba (org.sample:liba-native): 1.0")
|
||||||
|
|
|
||||||
|
|Project dependencies:
|
||||||
|
|├─── org.sample:liba (org.sample:liba-native): 2.0
|
||||||
|
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|└─── org.sample:libb (org.sample:libb-native): 1.0
|
||||||
|
| ^^^ This module requires symbol sample.liba/C|null[0].
|
||||||
|
| ├─── org.sample:liba (org.sample:liba-native): 1.0 -> 2.0 (*)
|
||||||
|
| └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|
|
||||||
|
|(*) - dependencies omitted (listed previously)
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `declaration that is gone (KT-41378) - without cache`() {
|
||||||
|
buildConflictingLibrariesAndApplication(
|
||||||
|
directoryPrefix = "native-ir-linker-issues-gone-declaration",
|
||||||
|
useCache = false
|
||||||
|
) { kotlinNativeCompilerVersion ->
|
||||||
|
"""
|
||||||
|
|e: Module "org.sample:libb (org.sample:libb-native)" has a reference to symbol sample.liba/C|null[0]. Neither the module itself nor its dependencies contain such declaration.
|
||||||
|
|
|
||||||
|
|This could happen if the required dependency is missing in the project. Or if there is a dependency of "org.sample:libb (org.sample:libb-native)" that has a different version in the project than the version that "org.sample:libb (org.sample:libb-native): 1.0" was initially compiled with. Please check that the project configuration is correct and has consistent versions of all required dependencies.
|
||||||
|
|
|
||||||
|
|The list of "org.sample:libb (org.sample:libb-native): 1.0" dependencies that may lead to conflicts:
|
||||||
|
|1. "org.sample:liba (org.sample:liba-native): 2.0" (was initially compiled with "org.sample:liba (org.sample:liba-native): 1.0")
|
||||||
|
|
|
||||||
|
|Project dependencies:
|
||||||
|
|├─── org.sample:liba (org.sample:liba-native): 2.0
|
||||||
|
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|├─── org.sample:libb (org.sample:libb-native): 1.0
|
||||||
|
|│ ^^^ This module requires symbol sample.liba/C|null[0].
|
||||||
|
|│ ├─── org.sample:liba (org.sample:liba-native): 1.0 -> 2.0 (*)
|
||||||
|
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|└─── org.jetbrains.kotlin.native.platform.* (NNN libraries): $kotlinNativeCompilerVersion
|
||||||
|
| └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|
|
||||||
|
|(*) - dependencies omitted (listed previously)
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `symbol type mismatch (KT-47285) - with cache`() {
|
||||||
|
// Don't run it on Windows. Caches are not supported there yet.
|
||||||
|
assumeFalse(HostManager.hostIsMingw)
|
||||||
|
|
||||||
|
buildConflictingLibrariesAndApplication(
|
||||||
|
directoryPrefix = "native-ir-linker-issues-symbol-mismatch",
|
||||||
|
useCache = true
|
||||||
|
) { kotlinNativeCompilerVersion ->
|
||||||
|
"""
|
||||||
|
|e: The symbol of unexpected type encountered during IR deserialization: IrClassPublicSymbolImpl, sample.liba/B|null[0]. IrTypeAliasSymbol is expected.
|
||||||
|
|
|
||||||
|
|This could happen if there are two libraries, where one library was compiled against the different version of the other library than the one currently used in the project. Please check that the project configuration is correct and has consistent versions of dependencies.
|
||||||
|
|
|
||||||
|
|The list of libraries that depend on "org.sample:liba (org.sample:liba-native)" and may lead to conflicts:
|
||||||
|
|1. "org.sample:libb (org.sample:libb-native): 1.0" (was compiled against "org.sample:liba (org.sample:liba-native): 1.0" but "org.sample:liba (org.sample:liba-native): 2.0" is used in the project)
|
||||||
|
|
|
||||||
|
|Project dependencies:
|
||||||
|
|├─── org.sample:liba (org.sample:liba-native): 2.0
|
||||||
|
|│ ^^^ This module contains symbol sample.liba/B|null[0] that is the cause of the conflict.
|
||||||
|
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|└─── org.sample:libb (org.sample:libb-native): 1.0
|
||||||
|
| ├─── org.sample:liba (org.sample:liba-native): 1.0 -> 2.0 (*)
|
||||||
|
| │ ^^^ This module contains symbol sample.liba/B|null[0] that is the cause of the conflict.
|
||||||
|
| └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|
|
||||||
|
|(*) - dependencies omitted (listed previously)
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `symbol type mismatch (KT-47285) - without cache`() {
|
||||||
|
buildConflictingLibrariesAndApplication(
|
||||||
|
directoryPrefix = "native-ir-linker-issues-symbol-mismatch",
|
||||||
|
useCache = false
|
||||||
|
) { kotlinNativeCompilerVersion ->
|
||||||
|
"""
|
||||||
|
|e: The symbol of unexpected type encountered during IR deserialization: IrTypeAliasPublicSymbolImpl, sample.liba/B|null[0]. IrClassifierSymbol is expected.
|
||||||
|
|
|
||||||
|
|This could happen if there are two libraries, where one library was compiled against the different version of the other library than the one currently used in the project. Please check that the project configuration is correct and has consistent versions of dependencies.
|
||||||
|
|
|
||||||
|
|The list of libraries that depend on "org.sample:liba (org.sample:liba-native)" and may lead to conflicts:
|
||||||
|
|1. "org.sample:libb (org.sample:libb-native): 1.0" (was compiled against "org.sample:liba (org.sample:liba-native): 1.0" but "org.sample:liba (org.sample:liba-native): 2.0" is used in the project)
|
||||||
|
|
|
||||||
|
|Project dependencies:
|
||||||
|
|├─── org.sample:liba (org.sample:liba-native): 2.0
|
||||||
|
|│ ^^^ This module contains symbol sample.liba/B|null[0] that is the cause of the conflict.
|
||||||
|
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|├─── org.sample:libb (org.sample:libb-native): 1.0
|
||||||
|
|│ ├─── org.sample:liba (org.sample:liba-native): 1.0 -> 2.0 (*)
|
||||||
|
|│ │ ^^^ This module contains symbol sample.liba/B|null[0] that is the cause of the conflict.
|
||||||
|
|│ └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|└─── org.jetbrains.kotlin.native.platform.* (NNN libraries): $kotlinNativeCompilerVersion
|
||||||
|
| └─── stdlib: $kotlinNativeCompilerVersion
|
||||||
|
|
|
||||||
|
|(*) - dependencies omitted (listed previously)
|
||||||
|
""".trimMargin()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildConflictingLibrariesAndApplication(
|
||||||
|
directoryPrefix: String,
|
||||||
|
useCache: Boolean,
|
||||||
expectedErrorMessage: (compilerVersion: String) -> String
|
expectedErrorMessage: (compilerVersion: String) -> String
|
||||||
) {
|
) {
|
||||||
prepareProject(directory, projectName, localRepo) {
|
val repo = setupLocalRepo()
|
||||||
|
|
||||||
|
buildAndPublishLibrary(directoryPrefix = directoryPrefix, projectName = "liba-v1.0", localRepo = repo)
|
||||||
|
buildAndPublishLibrary(directoryPrefix = directoryPrefix, projectName = "liba-v2.0", localRepo = repo)
|
||||||
|
buildAndPublishLibrary(directoryPrefix = directoryPrefix, projectName = "libb", localRepo = repo)
|
||||||
|
|
||||||
|
buildApplicationAndFail(
|
||||||
|
directoryPrefix = directoryPrefix,
|
||||||
|
projectName = "app",
|
||||||
|
localRepo = repo,
|
||||||
|
useCache = useCache,
|
||||||
|
expectedErrorMessage = expectedErrorMessage
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun buildApplicationAndFail(
|
||||||
|
directoryPrefix: String?,
|
||||||
|
projectName: String,
|
||||||
|
localRepo: File?,
|
||||||
|
useCache: Boolean,
|
||||||
|
expectedErrorMessage: (compilerVersion: String) -> String
|
||||||
|
) {
|
||||||
|
prepareProject(directoryPrefix, projectName, localRepo, useCache) {
|
||||||
build("linkDebugExecutableNative") {
|
build("linkDebugExecutableNative") {
|
||||||
assertFailed()
|
assertFailed()
|
||||||
|
|
||||||
@@ -192,6 +266,16 @@ class NativeIrLinkerIssuesIT : BaseGradleIT() {
|
|||||||
val errorMessage = ERROR_LINE_REGEX.findAll(getOutputForTask("linkDebugExecutableNative"))
|
val errorMessage = ERROR_LINE_REGEX.findAll(getOutputForTask("linkDebugExecutableNative"))
|
||||||
.map { matchResult -> matchResult.groupValues[1] }
|
.map { matchResult -> matchResult.groupValues[1] }
|
||||||
.map { line -> line.replace(kotlinNativeTargetName, MASKED_TARGET_NAME) }
|
.map { line -> line.replace(kotlinNativeTargetName, MASKED_TARGET_NAME) }
|
||||||
|
.map { line ->
|
||||||
|
line.replace(COMPRESSED_PLATFORM_LIBS_REGEX) { result ->
|
||||||
|
val rangeWithPlatformLibrariesCount = result.groups[1]!!.range
|
||||||
|
buildString {
|
||||||
|
append(line.substring(0, rangeWithPlatformLibrariesCount.first))
|
||||||
|
append("NNN")
|
||||||
|
append(line.substring(rangeWithPlatformLibrariesCount.last + 1))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
.joinToString("\n")
|
.joinToString("\n")
|
||||||
|
|
||||||
assertEquals(expectedErrorMessage(kotlinNativeCompilerVersion), errorMessage)
|
assertEquals(expectedErrorMessage(kotlinNativeCompilerVersion), errorMessage)
|
||||||
@@ -199,8 +283,8 @@ class NativeIrLinkerIssuesIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun buildAndPublishLibrary(directory: String, projectName: String, localRepo: File) {
|
private fun buildAndPublishLibrary(directoryPrefix: String, projectName: String, localRepo: File) {
|
||||||
prepareProject(directory, projectName, localRepo) {
|
prepareProject(directoryPrefix, projectName, localRepo, useCache = true) {
|
||||||
build("publish") {
|
build("publish") {
|
||||||
assertSuccessful()
|
assertSuccessful()
|
||||||
}
|
}
|
||||||
@@ -208,12 +292,13 @@ class NativeIrLinkerIssuesIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private fun prepareProject(
|
private fun prepareProject(
|
||||||
directory: String?,
|
directoryPrefix: String?,
|
||||||
projectName: String,
|
projectName: String,
|
||||||
localRepo: File?,
|
localRepo: File?,
|
||||||
|
useCache: Boolean,
|
||||||
block: Project.() -> Unit
|
block: Project.() -> Unit
|
||||||
) {
|
) {
|
||||||
with(transformNativeTestProjectWithPluginDsl(directoryPrefix = directory, projectName = projectName)) {
|
with(transformNativeTestProjectWithPluginDsl(directoryPrefix = directoryPrefix, projectName = projectName)) {
|
||||||
if (localRepo != null) {
|
if (localRepo != null) {
|
||||||
val localRepoUri = localRepo.absoluteFile.toURI().toString()
|
val localRepoUri = localRepo.absoluteFile.toURI().toString()
|
||||||
gradleBuildScript().apply {
|
gradleBuildScript().apply {
|
||||||
@@ -221,12 +306,16 @@ class NativeIrLinkerIssuesIT : BaseGradleIT() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
gradleProperties().appendText("\nkotlin.native.cacheKind=${if (useCache) "static" else "none"}\n")
|
||||||
|
|
||||||
block()
|
block()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
private companion object {
|
||||||
private val ERROR_LINE_REGEX = "(?m)^.*\\[ERROR] \\[\\S+] (.*)$".toRegex()
|
private val ERROR_LINE_REGEX = "(?m)^.*\\[ERROR] \\[\\S+] (.*)$".toRegex()
|
||||||
|
private val COMPRESSED_PLATFORM_LIBS_REGEX =
|
||||||
|
".*${KONAN_PLATFORM_LIBS_NAME_PREFIX.replace(".", "\\.")}\\* \\((\\d+) libraries\\).*".toRegex()
|
||||||
|
|
||||||
private fun setupLocalRepo(): File = Files.createTempDirectory("localRepo").toAbsolutePath().toFile()
|
private fun setupLocalRepo(): File = Files.createTempDirectory("localRepo").toAbsolutePath().toFile()
|
||||||
|
|
||||||
|
|||||||
+30
-20
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
||||||
import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
|
import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
|
||||||
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
|
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
|
import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData
|
||||||
@@ -49,6 +50,7 @@ import org.jetbrains.kotlin.library.*
|
|||||||
import org.jetbrains.kotlin.project.model.LanguageSettings
|
import org.jetbrains.kotlin.project.model.LanguageSettings
|
||||||
import org.jetbrains.kotlin.utils.ResolvedDependency as KResolvedDependency
|
import org.jetbrains.kotlin.utils.ResolvedDependency as KResolvedDependency
|
||||||
import org.jetbrains.kotlin.utils.ResolvedDependencyId as KResolvedDependencyId
|
import org.jetbrains.kotlin.utils.ResolvedDependencyId as KResolvedDependencyId
|
||||||
|
import org.jetbrains.kotlin.utils.ResolvedDependencies as KResolvedDependencies
|
||||||
import org.jetbrains.kotlin.utils.ResolvedDependenciesSupport as KResolvedDependenciesSupport
|
import org.jetbrains.kotlin.utils.ResolvedDependenciesSupport as KResolvedDependenciesSupport
|
||||||
import org.jetbrains.kotlin.utils.ResolvedDependencyArtifactPath as KResolvedDependencyArtifactPath
|
import org.jetbrains.kotlin.utils.ResolvedDependencyArtifactPath as KResolvedDependencyArtifactPath
|
||||||
import org.jetbrains.kotlin.utils.ResolvedDependencyVersion as KResolvedDependencyVersion
|
import org.jetbrains.kotlin.utils.ResolvedDependencyVersion as KResolvedDependencyVersion
|
||||||
@@ -610,7 +612,7 @@ constructor(
|
|||||||
override fun buildCompilerArgs(): List<String> = mutableListOf<String>().apply {
|
override fun buildCompilerArgs(): List<String> = mutableListOf<String>().apply {
|
||||||
addAll(super.buildCompilerArgs())
|
addAll(super.buildCompilerArgs())
|
||||||
|
|
||||||
val externalDependenciesArgs = ExternalDependenciesBuilder(project, binary).buildCompilerArgs()
|
val externalDependenciesArgs = ExternalDependenciesBuilder(project, compilation).buildCompilerArgs()
|
||||||
addAll(externalDependenciesArgs)
|
addAll(externalDependenciesArgs)
|
||||||
|
|
||||||
addAll(CacheBuilder(project, binary, konanTarget, externalDependenciesArgs).buildCompilerArgs())
|
addAll(CacheBuilder(project, binary, konanTarget, externalDependenciesArgs).buildCompilerArgs())
|
||||||
@@ -689,13 +691,21 @@ constructor(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class ExternalDependenciesBuilder(val project: Project, val binary: NativeBinary) {
|
private class ExternalDependenciesBuilder(
|
||||||
private val compilation: KotlinNativeCompilation
|
val project: Project,
|
||||||
get() = binary.compilation
|
val compilation: KotlinCompilation<*>,
|
||||||
|
intermediateLibraryName: String?
|
||||||
|
) {
|
||||||
|
constructor(project: Project, compilation: KotlinNativeCompilation) : this(
|
||||||
|
project, compilation, compilation.compileKotlinTask.moduleName
|
||||||
|
)
|
||||||
|
|
||||||
private val compileDependencyConfiguration: Configuration
|
private val compileDependencyConfiguration: Configuration
|
||||||
get() = project.configurations.getByName(compilation.compileDependencyConfigurationName)
|
get() = project.configurations.getByName(compilation.compileDependencyConfigurationName)
|
||||||
|
|
||||||
|
private val sourceCodeModuleId: KResolvedDependencyId =
|
||||||
|
intermediateLibraryName?.let { KResolvedDependencyId(it) } ?: KResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID
|
||||||
|
|
||||||
fun buildCompilerArgs(): List<String> {
|
fun buildCompilerArgs(): List<String> {
|
||||||
val konanVersion = Distribution(project.konanHome).compilerVersion?.let(CompilerVersion.Companion::fromString)
|
val konanVersion = Distribution(project.konanHome).compilerVersion?.let(CompilerVersion.Companion::fromString)
|
||||||
?: project.konanVersion
|
?: project.konanVersion
|
||||||
@@ -771,7 +781,7 @@ private class ExternalDependenciesBuilder(val project: Project, val binary: Nati
|
|||||||
}
|
}
|
||||||
|
|
||||||
compileDependencyConfiguration.incoming.resolutionResult.root.dependencies.forEach { dependencyResult ->
|
compileDependencyConfiguration.incoming.resolutionResult.root.dependencies.forEach { dependencyResult ->
|
||||||
processModule(dependencyResult, incomingDependencyId = KResolvedDependencyId.SOURCE_CODE_MODULE_ID)
|
processModule(dependencyResult, incomingDependencyId = sourceCodeModuleId)
|
||||||
}
|
}
|
||||||
|
|
||||||
if (moduleIdsToMerge.isEmpty())
|
if (moduleIdsToMerge.isEmpty())
|
||||||
@@ -821,6 +831,15 @@ private class ExternalDependenciesBuilder(val project: Project, val binary: Nati
|
|||||||
return mergedModules.values
|
return mergedModules.values
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun writeDependenciesFile(dependencies: Collection<KResolvedDependency>, deleteOnExit: Boolean): File? {
|
||||||
|
if (dependencies.isEmpty()) return null
|
||||||
|
|
||||||
|
val dependenciesFile = Files.createTempFile("kotlin-native-external-dependencies", ".deps").toAbsolutePath().toFile()
|
||||||
|
if (deleteOnExit) dependenciesFile.deleteOnExit()
|
||||||
|
dependenciesFile.writeText(KResolvedDependenciesSupport.serialize(KResolvedDependencies(dependencies, sourceCodeModuleId)))
|
||||||
|
return dependenciesFile
|
||||||
|
}
|
||||||
|
|
||||||
private val ModuleComponentIdentifier.uniqueName: String
|
private val ModuleComponentIdentifier.uniqueName: String
|
||||||
get() = "$group:$module"
|
get() = "$group:$module"
|
||||||
|
|
||||||
@@ -828,27 +847,18 @@ private class ExternalDependenciesBuilder(val project: Project, val binary: Nati
|
|||||||
@Suppress("unused") // Used for tests only. Accessed via reflection.
|
@Suppress("unused") // Used for tests only. Accessed via reflection.
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
fun buildExternalDependenciesFileForTests(project: Project): File? {
|
fun buildExternalDependenciesFileForTests(project: Project): File? {
|
||||||
val executable = project.tasks.asSequence()
|
val compilation = project.tasks.asSequence()
|
||||||
.filterIsInstance<KotlinNativeLink>()
|
.filterIsInstance<KotlinNativeLink>()
|
||||||
.map { it.binary }
|
.map { it.binary }
|
||||||
.filterIsInstance<Executable>() // Not TestExecutable or any other kind of NativeBinary. Strictly Executable!
|
.filterIsInstance<Executable>() // Not TestExecutable or any other kind of NativeBinary. Strictly Executable!
|
||||||
.firstOrNull()
|
.firstOrNull()
|
||||||
|
?.compilation
|
||||||
?: return null
|
?: return null
|
||||||
|
|
||||||
val dependencies = ExternalDependenciesBuilder(project, executable)
|
return with(ExternalDependenciesBuilder(project, compilation)) {
|
||||||
.buildDependencies()
|
val dependencies = buildDependencies().sortedBy { it.id.toString() }
|
||||||
.sortedBy { it.id.toString() }
|
writeDependenciesFile(dependencies, deleteOnExit = false)
|
||||||
|
}
|
||||||
return writeDependenciesFile(dependencies, deleteOnExit = false)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun writeDependenciesFile(dependencies: Collection<KResolvedDependency>, deleteOnExit: Boolean): File? {
|
|
||||||
if (dependencies.isEmpty()) return null
|
|
||||||
|
|
||||||
val dependenciesFile = Files.createTempFile("kotlin-native-external-dependencies", ".deps").toAbsolutePath().toFile()
|
|
||||||
if (deleteOnExit) dependenciesFile.deleteOnExit()
|
|
||||||
dependenciesFile.writeText(KResolvedDependenciesSupport.serialize(dependencies))
|
|
||||||
return dependenciesFile
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user