Extracted multi-module compiler runner for external tests to a separate kotlin file.

(cherry picked from commit 4fd88e4d33d8f80370b3ba4eee4c64869c1f1734)
This commit is contained in:
Alexander Gorshenev
2021-01-15 00:48:21 +03:00
committed by Vasily Levchenko
parent 58ea71cb0e
commit ec024cee53
2 changed files with 90 additions and 62 deletions
@@ -22,14 +22,13 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.process.ExecResult import org.gradle.process.ExecResult
import org.jetbrains.kotlin.utils.DFS import org.jetbrains.kotlin.utils.DFS
import java.io.File
import java.nio.file.Paths import java.nio.file.Paths
import java.util.function.Function import java.util.function.Function
import java.util.function.UnaryOperator import java.util.function.UnaryOperator
import java.util.regex.Pattern import java.util.regex.Pattern
import java.util.stream.Collectors import java.util.stream.Collectors
class RunExternalTestGroup extends JavaExec { class RunExternalTestGroup extends JavaExec implements CompilerRunner {
def platformManager = project.rootProject.platformManager def platformManager = project.rootProject.platformManager
def target = platformManager.targetManager(project.testTarget).target def target = platformManager.targetManager(project.testTarget).target
def dist = UtilsKt.getKotlinNativeDist(project) def dist = UtilsKt.getKotlinNativeDist(project)
@@ -75,7 +74,8 @@ class RunExternalTestGroup extends JavaExec {
// configuration part at runCompiler. // configuration part at runCompiler.
} }
protected void runCompiler(List<String> filesToCompile, String output, List<String> moreArgs) { @Override
void runCompiler(List<String> filesToCompile, String output, List<String> moreArgs) {
def log = new ByteArrayOutputStream() def log = new ByteArrayOutputStream()
try { try {
classpath = project.fileTree("$dist.canonicalPath/konan/lib/") { classpath = project.fileTree("$dist.canonicalPath/konan/lib/") {
@@ -470,59 +470,6 @@ fun runTest() {
} }
} }
class MultiModuleCompilerInvocations {
String executablePath
Map<String, TestModule> modules
List<String> flags
MultiModuleCompilerInvocations(String executablePath, Map<String, TestModule> modules, List<String> flags) {
this.executablePath = executablePath
this.modules = modules
this.flags = flags
}
def libs = new HashSet<String>()
String moduleToKlibName(String moduleName, Integer version) {
def module = modules[moduleName]
// TODO: cleanup
def versionSuffix = module.hasVersions ? "_version${version}" : ""
return module.hasVersions ? "${executablePath}${versionSuffix}/${moduleName}.klib" : "${executablePath}.${moduleName}.klib"
}
void produceLibrary(TestModule module, Integer moduleVersion, Integer dependencyVersion) {
def klibModulePath = moduleToKlibName(module.name, moduleVersion)
libs.addAll(module.dependencies)
def klibs = module.dependencies.collectMany { ["-l", moduleToKlibName(it, dependencyVersion)] }.toList()
def repos = ["-r", "${executablePath}_version${dependencyVersion}", "-r", project.file(executablePath).parentFile.absolutePath ]
def friends = module.friends ?
module.friends.collectMany {
["-friend-modules", "${executablePath}.${it}.klib"]
}.toList() : []
runCompiler(module.versionFiles(moduleVersion).collect { it.path },
klibModulePath, flags + ["-p", "library"/*, "-module-name", module.name*/] + repos + klibs + friends)
}
void produceProgram(List<TestFile> compileList, Integer version) {
def compileMain = compileList.findAll {
it.module.isDefaultModule() || it.module == TestModule.support
}
compileMain.forEach { f ->
libs.addAll(f.module.dependencies)
}
def friends = compileMain.collectMany { it.module.friends }.toSet()
def repos = ["-r", "${executablePath}_version${version}", "-r", project.file(executablePath).parentFile.absolutePath]
if (!compileMain.empty) {
runCompiler(compileMain.collect { it.path }, executablePath, flags + repos +
libs.collectMany { ["-l", moduleToKlibName(it, version)] }.toList() +
friends.collectMany { ["-friend-modules", "${executablePath}.${it}.klib"] }.toList()
)
}
}
}
@TaskAction @TaskAction
void executeTest() { void executeTest() {
createOutputDirectory() createOutputDirectory()
@@ -573,18 +520,15 @@ fun runTest() {
List<TestModule> orderedModules = DFS.INSTANCE.topologicalOrder(modules.values()) { module -> List<TestModule> orderedModules = DFS.INSTANCE.topologicalOrder(modules.values()) { module ->
module.dependencies.collect { modules[it] }.findAll { it != null } module.dependencies.collect { modules[it] }.findAll { it != null }
} }
def compiler = new MultiModuleCompilerInvocations(executablePath(), modules, flags) def compiler = new MultiModuleCompilerInvocations(this, outputDirectory, executablePath(), modules, flags)
orderedModules.reverse().each { module -> orderedModules.reverse().each { module ->
if (!module.isDefaultModule()) { if (!module.isDefaultModule()) {
compiler.produceLibrary(module, 1, 1) compiler.produceLibrary(module)
if (module.hasVersions) {
compiler.produceLibrary(module, 2, 1)
}
} }
} }
compiler.produceProgram(compileList, 2) compiler.produceProgram(compileList)
} }
} catch (Exception ex) { } catch (Exception ex) {
project.logger.quiet("ERROR: Compilation failed for test suite: $name with exception", ex) project.logger.quiet("ERROR: Compilation failed for test suite: $name with exception", ex)
@@ -0,0 +1,84 @@
package org.jetbrains.kotlin
interface CompilerRunner {
fun runCompiler(filesToCompile: List<String>, output: String, moreArgs: List<String>)
}
// This class knows how to run the compiler for multi-module external tests.
//
// In addition it knows how to deal with multi-versioned modules.
// The versioned modules are used for binary compatibility testing.
// For such modules we produce two klibs:
// `version1/foo.klib` and `version2/foo.klib`.
// For un-versioned modules we still produce just `bar.klib`
// We link all klibs against `version1/foo.klib` and `bar.klib`
// We link the final executable against `version2/foo.klib` and `bar.klib`.
class MultiModuleCompilerInvocations(
val konanTest: CompilerRunner,
val outputDirectory: String,
val executablePath: String,
val modules: Map<String, TestModule>,
val flags: List<String>
) {
val libs = HashSet<String>()
fun moduleToKlibName(moduleName: String, version: Int): String {
val module = modules[moduleName] ?: error("Could not find module $moduleName")
return if (module.hasVersions) {
val versionSuffix = "_version$version"
"$executablePath$versionSuffix/$moduleName.klib"
} else {
"$executablePath.$moduleName.klib"
}
}
private fun produceLibrary(module: TestModule, moduleVersion: Int) {
val klibModulePath = moduleToKlibName(module.name, moduleVersion)
libs.addAll(module.dependencies)
// When producing klibs link them against version 1 of multiversioned klibs.
val dependencyVersion = 1
val klibs = module.dependencies.flatMap { listOf("-l", moduleToKlibName(it, dependencyVersion)) }
val repos = listOf("-r", "${executablePath}_version$dependencyVersion", "-r", outputDirectory)
val friends = module.friends.flatMap {
listOf("-friend-modules", "$executablePath.$it.klib")
}
konanTest.runCompiler(module.versionFiles(moduleVersion).map { it.path },
klibModulePath, flags + listOf("-p", "library") + repos + klibs + friends)
}
fun produceLibrary(module: TestModule) {
if (!module.hasVersions) {
produceLibrary(module, 1)
} else {
produceLibrary(module, 1)
produceLibrary(module, 2)
}
}
fun produceProgram(compileList: List<TestFile>) {
val compileMain = compileList.filter {
it.module.isDefaultModule() || it.module === TestModule.support
}
compileMain.forEach { f ->
libs.addAll(f.module.dependencies)
}
// When producing klibs link them against version 2 of multiversioned klibs.
val dependencyVersion = 2
val friends = compileMain.flatMap { it.module.friends }.toSet()
val repos = listOf("-r", "${executablePath}_version$dependencyVersion", "-r", outputDirectory)
if (compileMain.isNotEmpty()) {
konanTest.runCompiler(compileMain.map { it.path }, executablePath, flags + repos +
libs.flatMap { listOf("-l", moduleToKlibName(it, dependencyVersion)) } +
friends.flatMap { listOf("-friend-modules", "${executablePath}.${it}.klib") }
)
}
}
}