From 33ca8b528c00fec3d2368df5aa4a61a01ba50467 Mon Sep 17 00:00:00 2001 From: Dmitriy Dolovov Date: Mon, 24 Jan 2022 12:12:02 +0300 Subject: [PATCH] [Native][tests] Support static cache as a separate compilation and dependency type ^KT-50775 --- .../support/compilation/TestCompilation.kt | 196 ++++++++++++---- .../compilation/TestCompilationArtifact.kt | 1 + .../compilation/TestCompilationDependency.kt | 20 +- .../compilation/TestCompilationFactory.kt | 210 +++++++++++------- .../support/settings/TestProcessSettings.kt | 3 - 5 files changed, 300 insertions(+), 130 deletions(-) diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt index 7c2caa9b0b0..e36d343a1b1 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilation.kt @@ -8,33 +8,31 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.compilation import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.konan.blackboxtest.support.* import org.jetbrains.kotlin.konan.blackboxtest.support.TestCase.* -import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.Executable -import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.KLIB +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.* import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationDependencyType.* import org.jetbrains.kotlin.konan.blackboxtest.support.settings.* -import org.jetbrains.kotlin.konan.blackboxtest.support.settings.CacheKind.Companion.rootCacheDir +import org.jetbrains.kotlin.konan.blackboxtest.support.settings.CacheKind.WithStaticCache import org.jetbrains.kotlin.konan.blackboxtest.support.util.ArgsBuilder import org.jetbrains.kotlin.konan.blackboxtest.support.util.buildArgs import org.jetbrains.kotlin.konan.blackboxtest.support.util.flatMapToSet +import org.jetbrains.kotlin.test.services.JUnit5Assertions.fail +import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.io.File internal abstract class TestCompilation { abstract val result: TestCompilationResult } -internal abstract class BaseCompilation( +internal abstract class BasicCompilation( private val targets: KotlinNativeTargets, - private val home: KotlinNativeHome, private val classLoader: KotlinNativeClassLoader, private val optimizationMode: OptimizationMode, - private val memoryModel: MemoryModel, - private val threadStateChecker: ThreadStateChecker, - private val gcType: GCType, - private val freeCompilerArgs: TestCompilerArgs, - private val sourceModules: Collection, - private val dependencies: Collection>, - private val expectedArtifact: A + protected val dependencies: Iterable>, + protected val expectedArtifact: A ) : TestCompilation() { + protected abstract val sourceModules: Collection + protected abstract val freeCompilerArgs: TestCompilerArgs + // Runs the compiler and memorizes the result on property access. final override val result: TestCompilationResult by lazy { val failures = dependencies.collectFailures() @@ -45,38 +43,37 @@ internal abstract class BaseCompilation( } private fun ArgsBuilder.applyCommonArgs() { + add("-target", targets.testTarget.name) + optimizationMode.compilerFlag?.let { compilerFlag -> add(compilerFlag) } add( "-enable-assertions", - "-target", targets.testTarget.name, - "-repo", home.dir.resolve("klib").path, - "-output", expectedArtifact.path, "-Xskip-prerelease-check", "-Xverify-ir", "-Xbinary=runtimeAssertionsMode=panic" ) - optimizationMode.compilerFlag?.let { compilerFlag -> add(compilerFlag) } - memoryModel.compilerFlags?.let { compilerFlags -> add(compilerFlags) } - threadStateChecker.compilerFlag?.let { compilerFlag -> add(compilerFlag) } - gcType.compilerFlag?.let { compilerFlag -> add(compilerFlag) } - - addFlattened(dependencies.libraries) { library -> listOf("-l", library.path) } - dependencies.friends.takeIf(Collection<*>::isNotEmpty)?.let { friends -> - add("-friend-modules", friends.joinToString(File.pathSeparator) { friend -> friend.path }) - } - add(dependencies.includedLibraries) { include -> "-Xinclude=${include.path}" } - add(freeCompilerArgs.compilerArgs) } - protected abstract fun ArgsBuilder.applySpecificCompilerArgs() + protected abstract fun applySpecificArgs(argsBuilder: ArgsBuilder) + protected abstract fun applyDependencies(argsBuilder: ArgsBuilder) + + private fun ArgsBuilder.applyFreeArgs() { + add(freeCompilerArgs.compilerArgs) + } private fun ArgsBuilder.applySources() { addFlattenedTwice(sourceModules, { it.files }) { it.location.path } } + protected open fun doBeforeCompile() = Unit + private fun doCompile(): TestCompilationResult.ImmediateResult { + doBeforeCompile() + val compilerArgs = buildArgs { applyCommonArgs() - applySpecificCompilerArgs() + applySpecificArgs(this) + applyDependencies(this) + applyFreeArgs() applySources() } @@ -110,7 +107,7 @@ internal abstract class BaseCompilation( } companion object { - private fun Collection>.collectFailures() = flatMapToSet { dependency -> + private fun Iterable>.collectFailures() = flatMapToSet { dependency -> when (val result = (dependency as? TestCompilation<*>)?.result) { is TestCompilationResult.Failure -> listOf(result) is TestCompilationResult.DependencyFailures -> result.causes @@ -119,24 +116,77 @@ internal abstract class BaseCompilation( } } - private inline fun > Collection>.collectArtifacts() = - mapNotNull { dependency -> if (dependency.type is T) dependency.artifact as A else null } + @JvmStatic + protected inline fun > Iterable>.collectArtifacts(): List { + val concreteDependencyType = T::class.objectInstance + val dependencyTypeMatcher: (TestCompilationDependencyType<*>) -> Boolean = if (concreteDependencyType != null) { + { it == concreteDependencyType } + } else { + { it.canYield(A::class.java) } + } - private val Collection>.libraries get() = collectArtifacts() - private val Collection>.friends get() = collectArtifacts() - private val Collection>.includedLibraries get() = collectArtifacts() + return mapNotNull { dependency -> if (dependencyTypeMatcher(dependency.type)) dependency.artifact as A else null } + } + + @JvmStatic + protected val Iterable>.cachedLibraries + get() = collectArtifacts() private fun getLogFile(expectedArtifactFile: File): File = expectedArtifactFile.resolveSibling(expectedArtifactFile.name + ".log") } } +internal abstract class SourceBasedCompilation( + targets: KotlinNativeTargets, + private val home: KotlinNativeHome, + classLoader: KotlinNativeClassLoader, + optimizationMode: OptimizationMode, + private val memoryModel: MemoryModel, + private val threadStateChecker: ThreadStateChecker, + private val gcType: GCType, + override val freeCompilerArgs: TestCompilerArgs, + override val sourceModules: Collection, + dependencies: Iterable>, + expectedArtifact: A +) : BasicCompilation( + targets = targets, + classLoader = classLoader, + optimizationMode = optimizationMode, + dependencies = dependencies, + expectedArtifact = expectedArtifact +) { + override fun applySpecificArgs(argsBuilder: ArgsBuilder): Unit = with(argsBuilder) { + add( + "-repo", home.dir.resolve("klib").path, + "-output", expectedArtifact.path + ) + memoryModel.compilerFlags?.let { compilerFlags -> add(compilerFlags) } + threadStateChecker.compilerFlag?.let { compilerFlag -> add(compilerFlag) } + gcType.compilerFlag?.let { compilerFlag -> add(compilerFlag) } + } + + override fun applyDependencies(argsBuilder: ArgsBuilder): Unit = with(argsBuilder) { + addFlattened(dependencies.libraries) { library -> listOf("-l", library.path) } + dependencies.friends.takeIf(Collection<*>::isNotEmpty)?.let { friends -> + add("-friend-modules", friends.joinToString(File.pathSeparator) { friend -> friend.path }) + } + add(dependencies.includedLibraries) { include -> "-Xinclude=${include.path}" } + } + + companion object { + private val Iterable>.libraries get() = collectArtifacts() + private val Iterable>.friends get() = collectArtifacts() + private val Iterable>.includedLibraries get() = collectArtifacts() + } +} + internal class LibraryCompilation( settings: Settings, freeCompilerArgs: TestCompilerArgs, sourceModules: Collection, - dependencies: Collection>, + dependencies: Iterable>, expectedArtifact: KLIB -) : BaseCompilation( +) : SourceBasedCompilation( targets = settings.get(), home = settings.get(), classLoader = settings.get(), @@ -149,8 +199,9 @@ internal class LibraryCompilation( dependencies = dependencies, expectedArtifact = expectedArtifact ) { - override fun ArgsBuilder.applySpecificCompilerArgs() { + override fun applySpecificArgs(argsBuilder: ArgsBuilder) = with(argsBuilder) { add("-produce", "library") + super.applySpecificArgs(argsBuilder) } } @@ -159,9 +210,9 @@ internal class ExecutableCompilation( freeCompilerArgs: TestCompilerArgs, sourceModules: Collection, private val extras: Extras, - dependencies: Collection>, + dependencies: Iterable>, expectedArtifact: Executable -) : BaseCompilation( +) : SourceBasedCompilation( targets = settings.get(), home = settings.get(), classLoader = settings.get(), @@ -176,7 +227,7 @@ internal class ExecutableCompilation( ) { private val cacheKind: CacheKind = settings.get() - override fun ArgsBuilder.applySpecificCompilerArgs() { + override fun applySpecificArgs(argsBuilder: ArgsBuilder): Unit = with(argsBuilder) { add("-produce", "program") when (extras) { is NoTestRunnerExtras -> add("-entry", extras.entryPoint) @@ -189,6 +240,69 @@ internal class ExecutableCompilation( add(testRunnerArg) } } - cacheKind.rootCacheDir?.let { rootCacheDir -> add("-Xcache-directory=$rootCacheDir") } + super.applySpecificArgs(argsBuilder) + } + + override fun applyDependencies(argsBuilder: ArgsBuilder): Unit = with(argsBuilder) { + super.applyDependencies(argsBuilder) + cacheKind.safeAs()?.rootCacheDir?.let { rootCacheDir -> add("-Xcache-directory=$rootCacheDir") } + add(dependencies.cachedLibraries) { (libraryCacheDir, _) -> "-Xcache-directory=${libraryCacheDir.path}" } + } +} + +internal class StaticCacheCompilation( + settings: Settings, + dependencies: Iterable>, + expectedArtifact: KLIBStaticCache +) : BasicCompilation( + targets = settings.get(), + classLoader = settings.get(), + optimizationMode = settings.get(), + dependencies = dependencies, + expectedArtifact = expectedArtifact +) { + override val sourceModules get() = emptyList() + override val freeCompilerArgs get() = TestCompilerArgs.EMPTY + + private val cacheDir = expectedArtifact.file + + private val cacheKind: WithStaticCache = run { + val cacheKind = settings.get() + cacheKind.safeAs() ?: fail { + "${WithStaticCache::class.java} is expected as the current cache kind in ${StaticCacheCompilation::class.java}, found: $cacheKind" + } + } + + override fun doBeforeCompile() { + cacheDir.mkdirs() // Make sure the directory to hold the cache exists. + } + + override fun applySpecificArgs(argsBuilder: ArgsBuilder): Unit = with(argsBuilder) { + add("-produce", "static_cache") + // TODO: additional cache flags: konanProperties.resolvablePropertyList("additionalCacheFlags", target.visibleName) + add( + "-Xadd-cache=${dependencies.libraryToCache.path}", + "-Xcache-directory=${cacheDir.path}" + ) + cacheKind.rootCacheDir?.let { rootCacheDir -> add("-Xcache-directory=$rootCacheDir") } + } + + override fun applyDependencies(argsBuilder: ArgsBuilder): Unit = with(argsBuilder) { + addFlattened(dependencies.cachedLibraries) { (libraryCacheDir, library) -> + listOf( + "-l", library.path, + "-Xcache-directory=${libraryCacheDir.path}" + ) + } + } + + companion object { + private val Iterable>.libraryToCache: KLIB + get() { + val libraries = collectArtifacts>() + return libraries.singleOrNull() ?: fail { + "Only one library is expected as input for ${StaticCacheCompilation::class.java}, found: $libraries" + } + } } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationArtifact.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationArtifact.kt index 12e312fbcc9..e0d74cabb44 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationArtifact.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationArtifact.kt @@ -12,5 +12,6 @@ internal sealed interface TestCompilationArtifact { val path: String get() = file.path data class KLIB(override val file: File) : TestCompilationArtifact + data class KLIBStaticCache(override val file: File, val klib: KLIB) : TestCompilationArtifact data class Executable(override val file: File) : TestCompilationArtifact } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationDependency.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationDependency.kt index 903ecbbb4ec..90c3231e811 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationDependency.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationDependency.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.compilation +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.KLIB +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.KLIBStaticCache import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess /** @@ -14,10 +16,14 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilati * [FriendLibrary] - similarly but friend modules (-friend-modules). * [IncludedLibrary] - similarly but included modules (-Xinclude). */ -internal sealed interface TestCompilationDependencyType { - object Library : TestCompilationDependencyType - object FriendLibrary : TestCompilationDependencyType - object IncludedLibrary : TestCompilationDependencyType +internal sealed class TestCompilationDependencyType(private val artifactClass: Class) { + fun canYield(artifactClass: Class): Boolean = this.artifactClass.isAssignableFrom(artifactClass) + + object Library : TestCompilationDependencyType(KLIB::class.java) + object FriendLibrary : TestCompilationDependencyType(KLIB::class.java) + object IncludedLibrary : TestCompilationDependencyType(KLIB::class.java) + + object LibraryStaticCache : TestCompilationDependencyType(KLIBStaticCache::class.java) } internal sealed interface TestCompilationDependency { @@ -33,6 +39,6 @@ internal class CompiledDependency( } internal class ExistingLibraryDependency( - override val artifact: TestCompilationArtifact.KLIB, - override val type: TestCompilationDependencyType -) : TestCompilationDependency + override val artifact: KLIB, + override val type: TestCompilationDependencyType +) : TestCompilationDependency diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationFactory.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationFactory.kt index 2ad7d36efec..dd520a9cbc3 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationFactory.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/compilation/TestCompilationFactory.kt @@ -11,23 +11,37 @@ import org.jetbrains.kotlin.konan.blackboxtest.support.TestCompilerArgs import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule.Companion.allDependencies import org.jetbrains.kotlin.konan.blackboxtest.support.TestModule.Companion.allFriends -import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.Executable -import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.KLIB -import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationDependencyType.FriendLibrary -import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationDependencyType.Library +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.* +import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationDependencyType.* import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Binaries +import org.jetbrains.kotlin.konan.blackboxtest.support.settings.CacheKind +import org.jetbrains.kotlin.konan.blackboxtest.support.settings.CacheKind.WithStaticCache import org.jetbrains.kotlin.konan.blackboxtest.support.settings.KotlinNativeTargets import org.jetbrains.kotlin.konan.blackboxtest.support.settings.Settings import org.jetbrains.kotlin.konan.blackboxtest.support.util.* +import org.jetbrains.kotlin.utils.addIfNotNull import java.io.File internal class TestCompilationFactory { - private val cachedKlibCompilations = ThreadSafeCache>() + private val cachedKlibCompilations = ThreadSafeCache() private val cachedExecutableCompilations = ThreadSafeCache>() private data class KlibCacheKey(val sourceModules: Set, val freeCompilerArgs: TestCompilerArgs) private data class ExecutableCacheKey(val sourceModules: Set) + // A pair of compilations for a KLIB itself and for its static cache that are created together. + private data class KlibCompilations(val klib: TestCompilation, val staticCache: TestCompilation?) + + private data class SourceBasedCompilationDependencies( + val klibDependencies: List>, + val staticCacheDependencies: List> + ) { + fun all(): Iterable> = (klibDependencies.asSequence() + staticCacheDependencies).asIterable() + + fun staticCacheDependenciesWith(klib: CompiledDependency): Iterable> = + (staticCacheDependencies.asSequence() + klib).asIterable() + } + fun testCasesToExecutable(testCases: Collection, settings: Settings): TestCompilation { val rootModules = testCases.flatMapToSet { testCase -> testCase.rootModules } val cacheKey = ExecutableCacheKey(rootModules) @@ -38,11 +52,8 @@ internal class TestCompilationFactory { // Long pass. val freeCompilerArgs = rootModules.first().testCase.freeCompilerArgs // Should be identical inside the same test case group. val extras = testCases.first().extras // Should be identical inside the same test case group. - val dependencies = buildList { - rootModules.flatMapToSet { it.allDependencies }.mapTo(this) { it.asKlibDependency(freeCompilerArgs, settings, Library) } - rootModules.flatMapToSet { it.allFriends }.mapTo(this) { it.asKlibDependency(freeCompilerArgs, settings, FriendLibrary) } - } - val expectedArtifact = Executable(settings.artifactFileForExecutable(rootModules)) + val dependencies = collectDependencies(rootModules, freeCompilerArgs, settings).all() + val executableArtifact = Executable(settings.artifactFileForExecutable(rootModules)) return cachedExecutableCompilations.computeIfAbsent(cacheKey) { ExecutableCompilation( @@ -51,12 +62,12 @@ internal class TestCompilationFactory { sourceModules = rootModules, extras = extras, dependencies = dependencies, - expectedArtifact = expectedArtifact + expectedArtifact = executableArtifact ) } } - private fun moduleToKlib(sourceModule: TestModule, freeCompilerArgs: TestCompilerArgs, settings: Settings): TestCompilation { + private fun moduleToKlib(sourceModule: TestModule, freeCompilerArgs: TestCompilerArgs, settings: Settings): KlibCompilations { val sourceModules = setOf(sourceModule) val cacheKey = KlibCacheKey(sourceModules, freeCompilerArgs) @@ -64,90 +75,131 @@ internal class TestCompilationFactory { cachedKlibCompilations[cacheKey]?.let { return it } // Long pass. - val dependencies = buildList { - sourceModule.allDependencies.mapTo(this) { it.asKlibDependency(freeCompilerArgs, settings, Library) } - sourceModule.allFriends.mapTo(this) { it.asKlibDependency(freeCompilerArgs, settings, FriendLibrary) } - } - val expectedArtifact = KLIB(settings.artifactFileForKlib(sourceModule, freeCompilerArgs)) + val dependencies = collectDependencies(sourceModules, freeCompilerArgs, settings) + val klibArtifact = KLIB(settings.artifactFileForKlib(sourceModule, freeCompilerArgs)) + + val staticCacheArtifact: KLIBStaticCache? = if (settings.get() is WithStaticCache) + KLIBStaticCache(file = klibArtifact.artifactFileForStaticCache(), klib = klibArtifact) + else + null // No artifact means no static cache should be compiled. return cachedKlibCompilations.computeIfAbsent(cacheKey) { - LibraryCompilation( + val klibCompilation = LibraryCompilation( settings = settings, freeCompilerArgs = freeCompilerArgs, sourceModules = sourceModules, - dependencies = dependencies, - expectedArtifact = expectedArtifact + dependencies = dependencies.klibDependencies, + expectedArtifact = klibArtifact ) + + val staticCacheCompilation: StaticCacheCompilation? = if (staticCacheArtifact != null) { + StaticCacheCompilation( + settings = settings, + dependencies = dependencies.staticCacheDependenciesWith(klibCompilation.asKlibDependency(type = /* does not matter in fact*/ Library)), + expectedArtifact = staticCacheArtifact + ) + } else + null + + KlibCompilations(klibCompilation, staticCacheCompilation) } } - private fun > TestModule.asKlibDependency( + private fun collectDependencies( + sourceModules: Set, freeCompilerArgs: TestCompilerArgs, - settings: Settings, - type: T - ) = CompiledDependency(moduleToKlib(this, freeCompilerArgs, settings), type) + settings: Settings + ): SourceBasedCompilationDependencies { + val klibDependencies = mutableListOf>() + val staticCacheDependencies = mutableListOf>() - private fun Settings.artifactFileForExecutable(modules: Set) = when (modules.size) { - 1 -> artifactFileForExecutable(modules.first()) - else -> multiModuleArtifactFile(modules, get().testTarget.family.exeSuffix) - } - - private fun Settings.artifactFileForExecutable(module: TestModule.Exclusive) = - singleModuleArtifactFile(module, get().testTarget.family.exeSuffix) - - private fun Settings.artifactFileForKlib(module: TestModule, freeCompilerArgs: TestCompilerArgs) = when (module) { - is TestModule.Exclusive -> singleModuleArtifactFile(module, "klib") - is TestModule.Shared -> get().sharedBinariesDir.resolve("${module.name}-${prettyHash(freeCompilerArgs.hashCode())}.klib") - } - - private fun Settings.singleModuleArtifactFile(module: TestModule.Exclusive, extension: String): File { - val artifactFileName = buildString { - append(module.testCase.nominalPackageName.compressedPackageName).append('.') - if (extension == "klib") append(module.name).append('.') - append(extension) - } - return artifactDirForPackageName(module.testCase.nominalPackageName).resolve(artifactFileName) - } - - private fun Settings.multiModuleArtifactFile(modules: Collection, extension: String): File { - var filesCount = 0 - var hash = 0 - val uniquePackageNames = hashSetOf() - - modules.forEach { module -> - module.files.forEach { file -> - filesCount++ - hash = hash * 31 + file.hashCode() + fun > Set.collectDependencies(type: T) = + forEach { dependencyModule: TestModule -> + val klibCompilations = moduleToKlib(dependencyModule, freeCompilerArgs, settings) + klibDependencies += klibCompilations.klib.asKlibDependency(type) + staticCacheDependencies.addIfNotNull(klibCompilations.staticCache?.asStaticCacheDependency()) } - if (module is TestModule.Exclusive) - uniquePackageNames += module.testCase.nominalPackageName - } + sourceModules.allDependencies().collectDependencies(Library) + sourceModules.allFriends().collectDependencies(FriendLibrary) - val commonPackageName = uniquePackageNames.findCommonPackageName() - - val artifactFileName = buildString { - val prefix = filesCount.toString() - repeat(4 - prefix.length) { append('0') } - append(prefix).append('-') - - if (!commonPackageName.isEmpty()) - append(commonPackageName.compressedPackageName).append('-') - - append(prettyHash(hash)) - - append('.').append(extension) - } - - return artifactDirForPackageName(commonPackageName).resolve(artifactFileName) + return SourceBasedCompilationDependencies(klibDependencies, staticCacheDependencies) } - private fun Settings.artifactDirForPackageName(packageName: PackageName?): File { - val baseDir = get().testBinariesDir - val outputDir = if (packageName != null) baseDir.resolve(packageName.compressedPackageName) else baseDir + companion object { + private fun Set.allDependencies() = if (size == 1) first().allDependencies else flatMapToSet { it.allDependencies } + private fun Set.allFriends() = if (size == 1) first().allFriends else flatMapToSet { it.allFriends } - outputDir.mkdirs() + private fun > TestCompilation.asKlibDependency(type: T): CompiledDependency = + CompiledDependency(this, type) - return outputDir + private fun TestCompilation.asStaticCacheDependency(): CompiledDependency = + CompiledDependency(this, LibraryStaticCache) + + private fun Settings.artifactFileForExecutable(modules: Set) = when (modules.size) { + 1 -> artifactFileForExecutable(modules.first()) + else -> multiModuleArtifactFile(modules, get().testTarget.family.exeSuffix) + } + + private fun Settings.artifactFileForExecutable(module: TestModule.Exclusive) = + singleModuleArtifactFile(module, get().testTarget.family.exeSuffix) + + private fun Settings.artifactFileForKlib(module: TestModule, freeCompilerArgs: TestCompilerArgs) = when (module) { + is TestModule.Exclusive -> singleModuleArtifactFile(module, "klib") + is TestModule.Shared -> get().sharedBinariesDir.resolve("${module.name}-${prettyHash(freeCompilerArgs.hashCode())}.klib") + } + + private fun KLIB.artifactFileForStaticCache() = file.resolveSibling("${file.name}-cache") + + private fun Settings.singleModuleArtifactFile(module: TestModule.Exclusive, extension: String): File { + val artifactFileName = buildString { + append(module.testCase.nominalPackageName.compressedPackageName).append('.') + if (extension == "klib") append(module.name).append('.') + append(extension) + } + return artifactDirForPackageName(module.testCase.nominalPackageName).resolve(artifactFileName) + } + + private fun Settings.multiModuleArtifactFile(modules: Collection, extension: String): File { + var filesCount = 0 + var hash = 0 + val uniquePackageNames = hashSetOf() + + modules.forEach { module -> + module.files.forEach { file -> + filesCount++ + hash = hash * 31 + file.hashCode() + } + + if (module is TestModule.Exclusive) + uniquePackageNames += module.testCase.nominalPackageName + } + + val commonPackageName = uniquePackageNames.findCommonPackageName() + + val artifactFileName = buildString { + val prefix = filesCount.toString() + repeat(4 - prefix.length) { append('0') } + append(prefix).append('-') + + if (!commonPackageName.isEmpty()) + append(commonPackageName.compressedPackageName).append('-') + + append(prettyHash(hash)) + + append('.').append(extension) + } + + return artifactDirForPackageName(commonPackageName).resolve(artifactFileName) + } + + private fun Settings.artifactDirForPackageName(packageName: PackageName?): File { + val baseDir = get().testBinariesDir + val outputDir = if (packageName != null) baseDir.resolve(packageName.compressedPackageName) else baseDir + + outputDir.mkdirs() + + return outputDir + } } } diff --git a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt index cc24fa02e57..ea41db6a9a7 100644 --- a/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt +++ b/native/native.tests/tests/org/jetbrains/kotlin/konan/blackboxtest/support/settings/TestProcessSettings.kt @@ -6,7 +6,6 @@ package org.jetbrains.kotlin.konan.blackboxtest.support.settings import org.jetbrains.kotlin.konan.target.KonanTarget -import org.jetbrains.kotlin.utils.addToStdlib.safeAs import java.io.File import kotlin.time.Duration @@ -124,8 +123,6 @@ internal sealed interface CacheKind { } companion object { - val CacheKind.rootCacheDir: File? get() = safeAs()?.rootCacheDir - private fun computeCacheDirName(testTarget: KonanTarget, cacheKind: String, debuggable: Boolean) = "$testTarget${if (debuggable) "-g" else ""}$cacheKind" }