[Native][tests] Support static cache as a separate compilation and dependency type
^KT-50775
This commit is contained in:
+155
-41
@@ -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<A : TestCompilationArtifact> {
|
||||
abstract val result: TestCompilationResult<out A>
|
||||
}
|
||||
|
||||
internal abstract class BaseCompilation<A : TestCompilationArtifact>(
|
||||
internal abstract class BasicCompilation<A : TestCompilationArtifact>(
|
||||
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<TestModule>,
|
||||
private val dependencies: Collection<TestCompilationDependency<*>>,
|
||||
private val expectedArtifact: A
|
||||
protected val dependencies: Iterable<TestCompilationDependency<*>>,
|
||||
protected val expectedArtifact: A
|
||||
) : TestCompilation<A>() {
|
||||
protected abstract val sourceModules: Collection<TestModule>
|
||||
protected abstract val freeCompilerArgs: TestCompilerArgs
|
||||
|
||||
// Runs the compiler and memorizes the result on property access.
|
||||
final override val result: TestCompilationResult<out A> by lazy {
|
||||
val failures = dependencies.collectFailures()
|
||||
@@ -45,38 +43,37 @@ internal abstract class BaseCompilation<A : TestCompilationArtifact>(
|
||||
}
|
||||
|
||||
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<out A> {
|
||||
doBeforeCompile()
|
||||
|
||||
val compilerArgs = buildArgs {
|
||||
applyCommonArgs()
|
||||
applySpecificCompilerArgs()
|
||||
applySpecificArgs(this)
|
||||
applyDependencies(this)
|
||||
applyFreeArgs()
|
||||
applySources()
|
||||
}
|
||||
|
||||
@@ -110,7 +107,7 @@ internal abstract class BaseCompilation<A : TestCompilationArtifact>(
|
||||
}
|
||||
|
||||
companion object {
|
||||
private fun Collection<TestCompilationDependency<*>>.collectFailures() = flatMapToSet { dependency ->
|
||||
private fun Iterable<TestCompilationDependency<*>>.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<A : TestCompilationArtifact>(
|
||||
}
|
||||
}
|
||||
|
||||
private inline fun <reified A : TestCompilationArtifact, reified T : TestCompilationDependencyType<A>> Collection<TestCompilationDependency<*>>.collectArtifacts() =
|
||||
mapNotNull { dependency -> if (dependency.type is T) dependency.artifact as A else null }
|
||||
@JvmStatic
|
||||
protected inline fun <reified A : TestCompilationArtifact, reified T : TestCompilationDependencyType<A>> Iterable<TestCompilationDependency<*>>.collectArtifacts(): List<A> {
|
||||
val concreteDependencyType = T::class.objectInstance
|
||||
val dependencyTypeMatcher: (TestCompilationDependencyType<*>) -> Boolean = if (concreteDependencyType != null) {
|
||||
{ it == concreteDependencyType }
|
||||
} else {
|
||||
{ it.canYield(A::class.java) }
|
||||
}
|
||||
|
||||
private val Collection<TestCompilationDependency<*>>.libraries get() = collectArtifacts<KLIB, Library>()
|
||||
private val Collection<TestCompilationDependency<*>>.friends get() = collectArtifacts<KLIB, FriendLibrary>()
|
||||
private val Collection<TestCompilationDependency<*>>.includedLibraries get() = collectArtifacts<KLIB, IncludedLibrary>()
|
||||
return mapNotNull { dependency -> if (dependencyTypeMatcher(dependency.type)) dependency.artifact as A else null }
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
protected val Iterable<TestCompilationDependency<*>>.cachedLibraries
|
||||
get() = collectArtifacts<KLIBStaticCache, LibraryStaticCache>()
|
||||
|
||||
private fun getLogFile(expectedArtifactFile: File): File = expectedArtifactFile.resolveSibling(expectedArtifactFile.name + ".log")
|
||||
}
|
||||
}
|
||||
|
||||
internal abstract class SourceBasedCompilation<A : TestCompilationArtifact>(
|
||||
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<TestModule>,
|
||||
dependencies: Iterable<TestCompilationDependency<*>>,
|
||||
expectedArtifact: A
|
||||
) : BasicCompilation<A>(
|
||||
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<TestCompilationDependency<*>>.libraries get() = collectArtifacts<KLIB, Library>()
|
||||
private val Iterable<TestCompilationDependency<*>>.friends get() = collectArtifacts<KLIB, FriendLibrary>()
|
||||
private val Iterable<TestCompilationDependency<*>>.includedLibraries get() = collectArtifacts<KLIB, IncludedLibrary>()
|
||||
}
|
||||
}
|
||||
|
||||
internal class LibraryCompilation(
|
||||
settings: Settings,
|
||||
freeCompilerArgs: TestCompilerArgs,
|
||||
sourceModules: Collection<TestModule>,
|
||||
dependencies: Collection<TestCompilationDependency<*>>,
|
||||
dependencies: Iterable<TestCompilationDependency<*>>,
|
||||
expectedArtifact: KLIB
|
||||
) : BaseCompilation<KLIB>(
|
||||
) : SourceBasedCompilation<KLIB>(
|
||||
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<TestModule>,
|
||||
private val extras: Extras,
|
||||
dependencies: Collection<TestCompilationDependency<*>>,
|
||||
dependencies: Iterable<TestCompilationDependency<*>>,
|
||||
expectedArtifact: Executable
|
||||
) : BaseCompilation<Executable>(
|
||||
) : SourceBasedCompilation<Executable>(
|
||||
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<WithStaticCache>()?.rootCacheDir?.let { rootCacheDir -> add("-Xcache-directory=$rootCacheDir") }
|
||||
add(dependencies.cachedLibraries) { (libraryCacheDir, _) -> "-Xcache-directory=${libraryCacheDir.path}" }
|
||||
}
|
||||
}
|
||||
|
||||
internal class StaticCacheCompilation(
|
||||
settings: Settings,
|
||||
dependencies: Iterable<TestCompilationDependency<*>>,
|
||||
expectedArtifact: KLIBStaticCache
|
||||
) : BasicCompilation<KLIBStaticCache>(
|
||||
targets = settings.get(),
|
||||
classLoader = settings.get(),
|
||||
optimizationMode = settings.get(),
|
||||
dependencies = dependencies,
|
||||
expectedArtifact = expectedArtifact
|
||||
) {
|
||||
override val sourceModules get() = emptyList<TestModule>()
|
||||
override val freeCompilerArgs get() = TestCompilerArgs.EMPTY
|
||||
|
||||
private val cacheDir = expectedArtifact.file
|
||||
|
||||
private val cacheKind: WithStaticCache = run {
|
||||
val cacheKind = settings.get<CacheKind>()
|
||||
cacheKind.safeAs<WithStaticCache>() ?: 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<TestCompilationDependency<*>>.libraryToCache: KLIB
|
||||
get() {
|
||||
val libraries = collectArtifacts<KLIB, TestCompilationDependencyType<KLIB>>()
|
||||
return libraries.singleOrNull() ?: fail {
|
||||
"Only one library is expected as input for ${StaticCacheCompilation::class.java}, found: $libraries"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+1
@@ -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
|
||||
}
|
||||
|
||||
+13
-7
@@ -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<A : TestCompilationArtifact> {
|
||||
object Library : TestCompilationDependencyType<TestCompilationArtifact.KLIB>
|
||||
object FriendLibrary : TestCompilationDependencyType<TestCompilationArtifact.KLIB>
|
||||
object IncludedLibrary : TestCompilationDependencyType<TestCompilationArtifact.KLIB>
|
||||
internal sealed class TestCompilationDependencyType<A : TestCompilationArtifact>(private val artifactClass: Class<A>) {
|
||||
fun canYield(artifactClass: Class<out TestCompilationArtifact>): Boolean = this.artifactClass.isAssignableFrom(artifactClass)
|
||||
|
||||
object Library : TestCompilationDependencyType<KLIB>(KLIB::class.java)
|
||||
object FriendLibrary : TestCompilationDependencyType<KLIB>(KLIB::class.java)
|
||||
object IncludedLibrary : TestCompilationDependencyType<KLIB>(KLIB::class.java)
|
||||
|
||||
object LibraryStaticCache : TestCompilationDependencyType<KLIBStaticCache>(KLIBStaticCache::class.java)
|
||||
}
|
||||
|
||||
internal sealed interface TestCompilationDependency<A : TestCompilationArtifact> {
|
||||
@@ -33,6 +39,6 @@ internal class CompiledDependency<A : TestCompilationArtifact>(
|
||||
}
|
||||
|
||||
internal class ExistingLibraryDependency(
|
||||
override val artifact: TestCompilationArtifact.KLIB,
|
||||
override val type: TestCompilationDependencyType<TestCompilationArtifact.KLIB>
|
||||
) : TestCompilationDependency<TestCompilationArtifact.KLIB>
|
||||
override val artifact: KLIB,
|
||||
override val type: TestCompilationDependencyType<KLIB>
|
||||
) : TestCompilationDependency<KLIB>
|
||||
|
||||
+131
-79
@@ -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<KlibCacheKey, TestCompilation<KLIB>>()
|
||||
private val cachedKlibCompilations = ThreadSafeCache<KlibCacheKey, KlibCompilations>()
|
||||
private val cachedExecutableCompilations = ThreadSafeCache<ExecutableCacheKey, TestCompilation<Executable>>()
|
||||
|
||||
private data class KlibCacheKey(val sourceModules: Set<TestModule>, val freeCompilerArgs: TestCompilerArgs)
|
||||
private data class ExecutableCacheKey(val sourceModules: Set<TestModule>)
|
||||
|
||||
// A pair of compilations for a KLIB itself and for its static cache that are created together.
|
||||
private data class KlibCompilations(val klib: TestCompilation<KLIB>, val staticCache: TestCompilation<KLIBStaticCache>?)
|
||||
|
||||
private data class SourceBasedCompilationDependencies(
|
||||
val klibDependencies: List<CompiledDependency<KLIB>>,
|
||||
val staticCacheDependencies: List<CompiledDependency<KLIBStaticCache>>
|
||||
) {
|
||||
fun all(): Iterable<CompiledDependency<*>> = (klibDependencies.asSequence() + staticCacheDependencies).asIterable()
|
||||
|
||||
fun staticCacheDependenciesWith(klib: CompiledDependency<KLIB>): Iterable<CompiledDependency<*>> =
|
||||
(staticCacheDependencies.asSequence() + klib).asIterable()
|
||||
}
|
||||
|
||||
fun testCasesToExecutable(testCases: Collection<TestCase>, settings: Settings): TestCompilation<Executable> {
|
||||
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<KLIB> {
|
||||
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<CacheKind>() 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 <T : TestCompilationDependencyType<KLIB>> TestModule.asKlibDependency(
|
||||
private fun collectDependencies(
|
||||
sourceModules: Set<TestModule>,
|
||||
freeCompilerArgs: TestCompilerArgs,
|
||||
settings: Settings,
|
||||
type: T
|
||||
) = CompiledDependency(moduleToKlib(this, freeCompilerArgs, settings), type)
|
||||
settings: Settings
|
||||
): SourceBasedCompilationDependencies {
|
||||
val klibDependencies = mutableListOf<CompiledDependency<KLIB>>()
|
||||
val staticCacheDependencies = mutableListOf<CompiledDependency<KLIBStaticCache>>()
|
||||
|
||||
private fun Settings.artifactFileForExecutable(modules: Set<TestModule.Exclusive>) = when (modules.size) {
|
||||
1 -> artifactFileForExecutable(modules.first())
|
||||
else -> multiModuleArtifactFile(modules, get<KotlinNativeTargets>().testTarget.family.exeSuffix)
|
||||
}
|
||||
|
||||
private fun Settings.artifactFileForExecutable(module: TestModule.Exclusive) =
|
||||
singleModuleArtifactFile(module, get<KotlinNativeTargets>().testTarget.family.exeSuffix)
|
||||
|
||||
private fun Settings.artifactFileForKlib(module: TestModule, freeCompilerArgs: TestCompilerArgs) = when (module) {
|
||||
is TestModule.Exclusive -> singleModuleArtifactFile(module, "klib")
|
||||
is TestModule.Shared -> get<Binaries>().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<TestModule>, extension: String): File {
|
||||
var filesCount = 0
|
||||
var hash = 0
|
||||
val uniquePackageNames = hashSetOf<PackageName>()
|
||||
|
||||
modules.forEach { module ->
|
||||
module.files.forEach { file ->
|
||||
filesCount++
|
||||
hash = hash * 31 + file.hashCode()
|
||||
fun <T : TestCompilationDependencyType<KLIB>> Set<TestModule>.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<Binaries>().testBinariesDir
|
||||
val outputDir = if (packageName != null) baseDir.resolve(packageName.compressedPackageName) else baseDir
|
||||
companion object {
|
||||
private fun Set<TestModule>.allDependencies() = if (size == 1) first().allDependencies else flatMapToSet { it.allDependencies }
|
||||
private fun Set<TestModule>.allFriends() = if (size == 1) first().allFriends else flatMapToSet { it.allFriends }
|
||||
|
||||
outputDir.mkdirs()
|
||||
private fun <T : TestCompilationDependencyType<KLIB>> TestCompilation<KLIB>.asKlibDependency(type: T): CompiledDependency<KLIB> =
|
||||
CompiledDependency(this, type)
|
||||
|
||||
return outputDir
|
||||
private fun TestCompilation<KLIBStaticCache>.asStaticCacheDependency(): CompiledDependency<KLIBStaticCache> =
|
||||
CompiledDependency(this, LibraryStaticCache)
|
||||
|
||||
private fun Settings.artifactFileForExecutable(modules: Set<TestModule.Exclusive>) = when (modules.size) {
|
||||
1 -> artifactFileForExecutable(modules.first())
|
||||
else -> multiModuleArtifactFile(modules, get<KotlinNativeTargets>().testTarget.family.exeSuffix)
|
||||
}
|
||||
|
||||
private fun Settings.artifactFileForExecutable(module: TestModule.Exclusive) =
|
||||
singleModuleArtifactFile(module, get<KotlinNativeTargets>().testTarget.family.exeSuffix)
|
||||
|
||||
private fun Settings.artifactFileForKlib(module: TestModule, freeCompilerArgs: TestCompilerArgs) = when (module) {
|
||||
is TestModule.Exclusive -> singleModuleArtifactFile(module, "klib")
|
||||
is TestModule.Shared -> get<Binaries>().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<TestModule>, extension: String): File {
|
||||
var filesCount = 0
|
||||
var hash = 0
|
||||
val uniquePackageNames = hashSetOf<PackageName>()
|
||||
|
||||
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<Binaries>().testBinariesDir
|
||||
val outputDir = if (packageName != null) baseDir.resolve(packageName.compressedPackageName) else baseDir
|
||||
|
||||
outputDir.mkdirs()
|
||||
|
||||
return outputDir
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-3
@@ -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<WithStaticCache>()?.rootCacheDir
|
||||
|
||||
private fun computeCacheDirName(testTarget: KonanTarget, cacheKind: String, debuggable: Boolean) =
|
||||
"$testTarget${if (debuggable) "-g" else ""}$cacheKind"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user