[KT-39120] Add "-fmodules" argument support to Cinterop
Merge-request: KT-MR-6921 Merged-by: Vladimir Sukharev <Vladimir.Sukharev@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
10fc86ef92
commit
b883dc5434
+26
-4
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.generators.tests
|
||||
|
||||
import org.jetbrains.kotlin.generators.generateTestGroupSuiteWithJUnit5
|
||||
import org.jetbrains.kotlin.generators.model.annotation
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeBlackBoxTest
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeCodegenBoxTest
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeKlibABITest
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.AbstractNativeKlibBinaryCompatibilityTest
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseExtTestCaseGroupProvider
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.group.UseStandardTestCaseGroupProvider
|
||||
import org.jetbrains.kotlin.test.TargetBackend
|
||||
@@ -59,6 +56,31 @@ fun main() {
|
||||
model("binaryCompatibility/klibEvolution", recursive = false)
|
||||
}
|
||||
}
|
||||
|
||||
// CInterop tests.
|
||||
testGroup("native/native.tests/tests-gen", "native/native.tests/testData") {
|
||||
testClass<AbstractNativeCInteropFModulesTest>(
|
||||
suiteTestClassName = "CInteropFModulesTestGenerated"
|
||||
) {
|
||||
model("CInterop/simple/simpleDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
model("CInterop/framework/frameworkDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
model("CInterop/framework.macros/macrosDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
model("CInterop/builtins/builtinsDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
}
|
||||
testClass<AbstractNativeCInteropNoFModulesTest>(
|
||||
suiteTestClassName = "CInteropNoFModulesTestGenerated"
|
||||
) {
|
||||
model("CInterop/simple/simpleDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
model("CInterop/framework/frameworkDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
model("CInterop/framework.macros/macrosDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
model("CInterop/builtins/builtinsDefs", pattern = "^([^_](.+))$", recursive = false)
|
||||
}
|
||||
testClass<AbstractNativeCInteropKT39120Test>(
|
||||
suiteTestClassName = "CInteropKT39120TestGenerated"
|
||||
) {
|
||||
model("CInterop/KT-39120/defs", pattern = "^([^_](.+))$", recursive = false)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+52
@@ -0,0 +1,52 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.blackboxtest
|
||||
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationResult.Companion.assertSuccess
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.*
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractNativeCInteropBaseTest : AbstractNativeSimpleTest() {
|
||||
private val buildDir: File get() = testRunSettings.get<SimpleTestDirectories>().testBuildDir
|
||||
internal val targets: KotlinNativeTargets get() = testRunSettings.get<KotlinNativeTargets>()
|
||||
internal val kotlinNativeClassLoader: KotlinNativeClassLoader get() = testRunSettings.get<KotlinNativeClassLoader>()
|
||||
|
||||
internal fun TestCase.cinteropToLibrary(): TestCompilationResult.Success<out KLIB> {
|
||||
modules.singleOrNull()
|
||||
val compilation = CInteropCompilation(
|
||||
classLoader = testRunSettings.get(),
|
||||
targets = targets,
|
||||
freeCompilerArgs = freeCompilerArgs,
|
||||
defFile = modules.singleOrNull()!!.files.singleOrNull()!!.location,
|
||||
expectedArtifact = toLibraryArtifact()
|
||||
)
|
||||
return compilation.result.assertSuccess()
|
||||
}
|
||||
|
||||
private fun TestCase.toLibraryArtifact() = KLIB(buildDir.resolve(modules.singleOrNull()!!.name + ".klib"))
|
||||
|
||||
internal fun generateCInteropTestCaseWithSingleDef(defFile: File, extraArgs: List<String>): TestCase {
|
||||
val moduleName: String = defFile.name
|
||||
val module = TestModule.Exclusive(moduleName, emptySet(), emptySet())
|
||||
module.files += TestFile.createCommitted(defFile, module)
|
||||
|
||||
return TestCase(
|
||||
id = TestCaseId.Named(moduleName),
|
||||
kind = TestKind.STANDALONE,
|
||||
modules = setOf(module),
|
||||
freeCompilerArgs = TestCompilerArgs(extraArgs),
|
||||
nominalPackageName = PackageName.EMPTY,
|
||||
checks = TestRunChecks.Default(testRunSettings.get<Timeouts>().executionTimeout),
|
||||
extras = TestCase.WithTestRunnerExtras(TestRunnerType.DEFAULT)
|
||||
).apply {
|
||||
initialize(null, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
+59
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.blackboxtest
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.testFramework.TestDataFile
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||
import org.junit.jupiter.api.Tag
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.*
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assumptions
|
||||
|
||||
@Tag("cinterop")
|
||||
abstract class AbstractNativeCInteropKT39120Test : AbstractNativeCInteropBaseTest() {
|
||||
|
||||
@Synchronized
|
||||
protected fun runTest(@TestDataFile testPath: String) {
|
||||
// KT-39120 is about Objective-C, so this test is for Apple hosts/targets only
|
||||
Assumptions.assumeTrue(targets.hostTarget.family.isAppleFamily && targets.testTarget.family.isAppleFamily)
|
||||
|
||||
val testPathFull = getAbsoluteFile(testPath)
|
||||
val testDataDir = testPathFull.parentFile.parentFile
|
||||
val def1File = testPathFull.resolve("pod1.def")
|
||||
val def2File = testPathFull.resolve("pod2.def")
|
||||
val golden1File = testPathFull.resolve("pod1.contents.gold.txt")
|
||||
val golden2File = testPathFull.resolve("pod2.contents.gold.txt")
|
||||
|
||||
val includeFrameworkArgs = listOf("-compiler-option", "-F${testDataDir.canonicalPath}")
|
||||
|
||||
val test1Case: TestCase = generateCInteropTestCaseWithSingleDef(def1File, includeFrameworkArgs)
|
||||
val klib1: KLIB = test1Case.cinteropToLibrary().resultingArtifact
|
||||
val contents1 = klib1.getContents(kotlinNativeClassLoader.classLoader)
|
||||
|
||||
val expectedFiltered1Output = golden1File.readText()
|
||||
val actualFiltered1Output = filterContentsOutput(contents1, " pod.Version|POD|class Pod")
|
||||
assertEquals(StringUtilRt.convertLineSeparators(expectedFiltered1Output), StringUtilRt.convertLineSeparators(actualFiltered1Output))
|
||||
|
||||
val cinterop2ExtraArgs = listOf("-l", klib1.klibFile.canonicalPath, "-compiler-option", "-fmodules")
|
||||
val test2Case: TestCase = generateCInteropTestCaseWithSingleDef(def2File, includeFrameworkArgs + cinterop2ExtraArgs)
|
||||
val klib2: KLIB = test2Case.cinteropToLibrary().resultingArtifact
|
||||
val contents2 = klib2.getContents(kotlinNativeClassLoader.classLoader)
|
||||
|
||||
val expectedFiltered2Output = golden2File.readText()
|
||||
val actualFiltered2Output = filterContentsOutput(contents2, " pod.Version|POD|class Pod")
|
||||
assertEquals(StringUtilRt.convertLineSeparators(expectedFiltered2Output), StringUtilRt.convertLineSeparators(actualFiltered2Output))
|
||||
}
|
||||
|
||||
private fun filterContentsOutput(contents: String, pattern: String) =
|
||||
contents.split("\n").filter {
|
||||
it.contains(Regex(pattern))
|
||||
}.joinToString(separator = "\n")
|
||||
}
|
||||
+113
@@ -0,0 +1,113 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.blackboxtest
|
||||
|
||||
import com.intellij.openapi.util.text.StringUtilRt
|
||||
import com.intellij.testFramework.TestDataFile
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.runner.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.*
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.util.*
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.test.services.JUnit5Assertions.assertEquals
|
||||
import org.junit.jupiter.api.Assumptions
|
||||
import org.junit.jupiter.api.Tag
|
||||
import java.io.File
|
||||
|
||||
abstract class AbstractNativeCInteropFModulesTest : AbstractNativeCInteropTest() {
|
||||
override val fmodules = true
|
||||
}
|
||||
|
||||
abstract class AbstractNativeCInteropNoFModulesTest : AbstractNativeCInteropTest() {
|
||||
override val fmodules = false
|
||||
}
|
||||
|
||||
@Tag("cinterop")
|
||||
abstract class AbstractNativeCInteropTest : AbstractNativeCInteropBaseTest() {
|
||||
abstract val fmodules: Boolean
|
||||
|
||||
@Synchronized
|
||||
protected fun runTest(@TestDataFile testPath: String) {
|
||||
// FIXME: check the following failures under Android with -fmodules
|
||||
// fatal error: could not build module 'std'
|
||||
Assumptions.assumeFalse(
|
||||
this is AbstractNativeCInteropFModulesTest &&
|
||||
targets.testTarget.family == Family.ANDROID
|
||||
)
|
||||
Assumptions.assumeFalse(!fmodules && testPath.endsWith("FModules/"))
|
||||
|
||||
val testPathFull = getAbsoluteFile(testPath)
|
||||
val testDataDir = testPathFull.parentFile.parentFile
|
||||
val includeFolder = testDataDir.resolve("include")
|
||||
val defFile = testPathFull.resolve("pod1.def")
|
||||
val defContents = defFile.readText().split("\n").map { it.trim() }
|
||||
val defHasObjC = defContents.any { it.endsWith("Objective-C") }
|
||||
Assumptions.assumeFalse(defHasObjC && !targets.testTarget.family.isAppleFamily)
|
||||
|
||||
val defHasHeaders = defContents.any { it.startsWith("headers") }
|
||||
Assumptions.assumeFalse(fmodules && defHasHeaders)
|
||||
|
||||
val goldenFile = if (testDataDir.name == "builtins")
|
||||
getBuiltinsGoldenFile(testPathFull)
|
||||
else
|
||||
getGoldenFile(testPathFull)
|
||||
val fmodulesArgs = if (fmodules) listOf("-compiler-option", "-fmodules") else listOf()
|
||||
val includeArgs = if (testDataDir.name.startsWith("framework"))
|
||||
listOf("-compiler-option", "-F${testDataDir.canonicalPath}")
|
||||
else
|
||||
listOf("-compiler-option", "-I${includeFolder.canonicalPath}")
|
||||
|
||||
val testCase: TestCase = generateCInteropTestCaseWithSingleDef(defFile, includeArgs + fmodulesArgs)
|
||||
val testCompilationResult = testCase.cinteropToLibrary()
|
||||
val klibContents = testCompilationResult.resultingArtifact.getContents(kotlinNativeClassLoader.classLoader)
|
||||
|
||||
val expectedContents = goldenFile.readText()
|
||||
assertEquals(StringUtilRt.convertLineSeparators(expectedContents), StringUtilRt.convertLineSeparators(klibContents)) {
|
||||
"Test failed. CInterop compilation result was: $testCompilationResult"
|
||||
}
|
||||
}
|
||||
|
||||
private fun getGoldenFile(testPathFull: File): File {
|
||||
return testPathFull.resolve("contents.gold.txt")
|
||||
}
|
||||
|
||||
private fun getBuiltinsGoldenFile(testPathFull: File): File {
|
||||
val goldenFilePart = when (targets.testTarget) {
|
||||
KonanTarget.ANDROID_ARM32 -> "ARM32"
|
||||
KonanTarget.ANDROID_ARM64 -> "ARM64"
|
||||
KonanTarget.ANDROID_X64 -> "X64"
|
||||
KonanTarget.ANDROID_X86 -> "CPointerByteVar"
|
||||
KonanTarget.IOS_ARM32 -> "COpaquePointer"
|
||||
KonanTarget.IOS_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.IOS_SIMULATOR_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.IOS_X64 -> "X64"
|
||||
KonanTarget.LINUX_ARM32_HFP -> "ARM32"
|
||||
KonanTarget.LINUX_ARM64 -> "ARM64"
|
||||
KonanTarget.LINUX_MIPS32 -> "COpaquePointer"
|
||||
KonanTarget.LINUX_MIPSEL32 -> "COpaquePointer"
|
||||
KonanTarget.LINUX_X64 -> "X64"
|
||||
KonanTarget.MACOS_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.MACOS_X64 -> "X64"
|
||||
KonanTarget.MINGW_X64 -> "CPointerByteVar"
|
||||
KonanTarget.MINGW_X86 -> "CPointerByteVar"
|
||||
KonanTarget.TVOS_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.TVOS_SIMULATOR_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.TVOS_X64 -> "X64"
|
||||
KonanTarget.WASM32 -> "COpaquePointer"
|
||||
KonanTarget.WATCHOS_ARM32 -> "CPointerByteVar"
|
||||
KonanTarget.WATCHOS_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.WATCHOS_DEVICE_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.WATCHOS_SIMULATOR_ARM64 -> "CPointerByteVar"
|
||||
KonanTarget.WATCHOS_X64 -> "X64"
|
||||
KonanTarget.WATCHOS_X86 -> "CPointerByteVar"
|
||||
is KonanTarget.ZEPHYR -> "COpaquePointer"
|
||||
}
|
||||
return testPathFull.resolve("contents.gold.${goldenFilePart}.txt")
|
||||
}
|
||||
}
|
||||
+27
-11
@@ -83,31 +83,47 @@ internal abstract class LoggedData {
|
||||
|
||||
abstract class CompilerCall : LoggedData()
|
||||
|
||||
class RealCompilerCall(
|
||||
private val parameters: CompilerParameters,
|
||||
class CInteropParameters(
|
||||
private val extraArgs: Array<String>,
|
||||
private val defFile: File,
|
||||
private val environment: JVMEnvironment = JVMEnvironment() // Capture environment.
|
||||
) : LoggedData() {
|
||||
override fun computeText() = buildString {
|
||||
appendArguments("CINTEROP INVOCATION EXTRA ARGUMENTS:", extraArgs.toList())
|
||||
appendLine()
|
||||
appendLine(environment)
|
||||
|
||||
appendLine()
|
||||
appendLine("TEST DEF FILE: ${defFile.canonicalPath}")
|
||||
}
|
||||
}
|
||||
|
||||
class CompilationToolCall(
|
||||
private val toolName: String,
|
||||
private val parameters: LoggedData,
|
||||
private val exitCode: ExitCode,
|
||||
private val compilerOutput: String,
|
||||
private val compilerOutputHasErrors: Boolean,
|
||||
private val toolOutput: String,
|
||||
private val toolOutputHasErrors: Boolean,
|
||||
private val duration: Duration
|
||||
) : CompilerCall() {
|
||||
override fun computeText(): String {
|
||||
val problems = listOfNotNull(
|
||||
"- Non-zero exit code".takeIf { exitCode != ExitCode.OK },
|
||||
"- Errors reported by the compiler".takeIf { compilerOutputHasErrors }
|
||||
"- Errors reported by the $toolName".takeIf { toolOutputHasErrors }
|
||||
)
|
||||
|
||||
return buildString {
|
||||
if (problems.isNotEmpty()) {
|
||||
appendLine("COMPILATION PROBLEMS:")
|
||||
appendLine("$toolName PROBLEMS:")
|
||||
problems.forEach(::appendLine)
|
||||
appendLine()
|
||||
}
|
||||
|
||||
appendLine("COMPILER CALL:")
|
||||
appendLine("$toolName CALL:")
|
||||
appendLine("- Exit code: ${exitCode.code} (${exitCode.name})")
|
||||
appendDuration(duration)
|
||||
appendLine()
|
||||
appendPotentiallyLargeOutput(compilerOutput, "RAW COMPILER OUTPUT", truncateLargeOutput = false)
|
||||
appendPotentiallyLargeOutput(toolOutput, "RAW $toolName OUTPUT", truncateLargeOutput = false)
|
||||
appendLine()
|
||||
appendLine(parameters)
|
||||
}
|
||||
@@ -118,10 +134,10 @@ internal abstract class LoggedData {
|
||||
override fun computeText() = "No compiler call performed for external (given) artifact $artifactFile"
|
||||
}
|
||||
|
||||
class CompilerCallUnexpectedFailure(parameters: CompilerParameters, throwable: Throwable) : UnexpectedFailure(parameters, throwable)
|
||||
class CompilationToolCallUnexpectedFailure(parameters: LoggedData, throwable: Throwable) : UnexpectedFailure(parameters, throwable)
|
||||
|
||||
class TestRunParameters(
|
||||
private val compilerCall: CompilerCall,
|
||||
private val compilationToolCall: CompilerCall,
|
||||
private val testCaseId: TestCaseId?,
|
||||
private val runArgs: Iterable<String>,
|
||||
private val runParameters: List<TestRunParameter>?
|
||||
@@ -151,7 +167,7 @@ internal abstract class LoggedData {
|
||||
appendLine(expectedOutputDataFile)
|
||||
appendLine()
|
||||
}
|
||||
appendLine(compilerCall)
|
||||
appendLine(compilationToolCall)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+56
-8
@@ -10,13 +10,23 @@ import org.jetbrains.kotlin.cli.common.messages.*
|
||||
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
|
||||
import org.jetbrains.kotlin.compilerRunner.processCompilerOutput
|
||||
import org.jetbrains.kotlin.config.Services
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.settings.KotlinNativeTargets
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.PrintStream
|
||||
import kotlin.time.Duration
|
||||
import kotlin.time.ExperimentalTime
|
||||
import kotlin.time.measureTime
|
||||
import org.jetbrains.kotlin.konan.file.File as KonanFile
|
||||
|
||||
internal fun callCompiler(compilerArgs: Array<String>, kotlinNativeClassLoader: ClassLoader): CompilerCallResult {
|
||||
internal data class CompilationToolCallResult(
|
||||
val exitCode: ExitCode,
|
||||
val toolOutput: String,
|
||||
val toolOutputHasErrors: Boolean,
|
||||
val duration: Duration
|
||||
)
|
||||
|
||||
internal fun callCompiler(compilerArgs: Array<String>, kotlinNativeClassLoader: ClassLoader): CompilationToolCallResult {
|
||||
val compilerXmlOutput: ByteArrayOutputStream
|
||||
val exitCode: ExitCode
|
||||
|
||||
@@ -60,12 +70,50 @@ internal fun callCompiler(compilerArgs: Array<String>, kotlinNativeClassLoader:
|
||||
compilerOutput = outputStream.toString(Charsets.UTF_8.name())
|
||||
}
|
||||
|
||||
return CompilerCallResult(exitCode, compilerOutput, messageCollector.hasErrors(), duration)
|
||||
return CompilationToolCallResult(exitCode, compilerOutput, messageCollector.hasErrors(), duration)
|
||||
}
|
||||
|
||||
internal data class CompilerCallResult(
|
||||
val exitCode: ExitCode,
|
||||
val compilerOutput: String,
|
||||
val compilerOutputHasErrors: Boolean,
|
||||
val duration: Duration
|
||||
)
|
||||
internal fun invokeCInterop(
|
||||
kotlinNativeClassLoader: ClassLoader,
|
||||
targets: KotlinNativeTargets,
|
||||
inputDef: File,
|
||||
outputLib: File,
|
||||
extraArgs: Array<String>
|
||||
): CompilationToolCallResult {
|
||||
val args = arrayOf("-o", outputLib.canonicalPath, "-def", inputDef.canonicalPath, "-no-default-libs", "-target", targets.testTarget.name)
|
||||
val buildDir = KonanFile("${outputLib.canonicalPath}-build")
|
||||
val generatedDir = KonanFile(buildDir, "kotlin")
|
||||
val nativesDir = KonanFile(buildDir, "natives")
|
||||
val manifest = KonanFile(buildDir, "manifest.properties")
|
||||
val cstubsName = "cstubs"
|
||||
|
||||
val interopClass = Class.forName("org.jetbrains.kotlin.native.interop.gen.jvm.Interop", true, kotlinNativeClassLoader)
|
||||
val entryPoint = interopClass.declaredMethods.single { it.name == "interopViaReflection" }
|
||||
|
||||
val possibleSubsequentCompilerInvocationArgs: Array<String>?
|
||||
|
||||
@OptIn(ExperimentalTime::class)
|
||||
val duration = measureTime {
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
possibleSubsequentCompilerInvocationArgs = entryPoint.invoke(
|
||||
interopClass.getDeclaredConstructor().newInstance(),
|
||||
"native",
|
||||
args + extraArgs,
|
||||
false,
|
||||
generatedDir.absolutePath, nativesDir.absolutePath, manifest.path, cstubsName // args for InternalInteropOptions()
|
||||
) as? Array<String>?
|
||||
}
|
||||
// In currently tested usecases, cinterop must return no args for the subsequent compiler call
|
||||
return if (possibleSubsequentCompilerInvocationArgs == null) {
|
||||
// TODO There is no technical ability to extract `toolOutput` and `toolOutputHasErrors`
|
||||
// from C-interop tool invocation at the moment. This should be fixed in the future.
|
||||
CompilationToolCallResult(exitCode = ExitCode.OK, toolOutput = "", toolOutputHasErrors = false, duration)
|
||||
} else {
|
||||
CompilationToolCallResult(
|
||||
exitCode = ExitCode.COMPILATION_ERROR,
|
||||
toolOutput = possibleSubsequentCompilerInvocationArgs.joinToString(" "),
|
||||
toolOutputHasErrors = true,
|
||||
duration
|
||||
)
|
||||
}
|
||||
}
|
||||
+52
-6
@@ -88,17 +88,17 @@ internal abstract class BasicCompilation<A : TestCompilationArtifact>(
|
||||
kotlinNativeClassLoader = classLoader.classLoader
|
||||
)
|
||||
|
||||
val loggedCompilerCall =
|
||||
LoggedData.RealCompilerCall(loggedCompilerParameters, exitCode, compilerOutput, compilerOutputHasErrors, duration)
|
||||
val loggedCompilationToolCall =
|
||||
LoggedData.CompilationToolCall("COMPILER", loggedCompilerParameters, exitCode, compilerOutput, compilerOutputHasErrors, duration)
|
||||
|
||||
val result = if (exitCode != ExitCode.OK || compilerOutputHasErrors)
|
||||
TestCompilationResult.CompilerFailure(loggedCompilerCall)
|
||||
TestCompilationResult.CompilationToolFailure(loggedCompilationToolCall)
|
||||
else
|
||||
TestCompilationResult.Success(expectedArtifact, loggedCompilerCall)
|
||||
TestCompilationResult.Success(expectedArtifact, loggedCompilationToolCall)
|
||||
|
||||
loggedCompilerCall to result
|
||||
loggedCompilationToolCall to result
|
||||
} catch (unexpectedThrowable: Throwable) {
|
||||
val loggedFailure = LoggedData.CompilerCallUnexpectedFailure(loggedCompilerParameters, unexpectedThrowable)
|
||||
val loggedFailure = LoggedData.CompilationToolCallUnexpectedFailure(loggedCompilerParameters, unexpectedThrowable)
|
||||
val result = TestCompilationResult.UnexpectedFailure(loggedFailure)
|
||||
|
||||
loggedFailure to result
|
||||
@@ -189,6 +189,52 @@ internal class GivenLibraryCompilation(givenArtifact: KLIB) : TestCompilation<KL
|
||||
override val result = TestCompilationResult.Success(givenArtifact, LoggedData.NoopCompilerCall(givenArtifact.klibFile))
|
||||
}
|
||||
|
||||
internal class CInteropCompilation(
|
||||
targets: KotlinNativeTargets,
|
||||
classLoader: KotlinNativeClassLoader,
|
||||
freeCompilerArgs: TestCompilerArgs,
|
||||
defFile: File,
|
||||
expectedArtifact: KLIB
|
||||
) : TestCompilation<KLIB>() {
|
||||
|
||||
override val result: TestCompilationResult<out KLIB> by lazy {
|
||||
val extraArgsArray = freeCompilerArgs.compilerArgs.toTypedArray()
|
||||
val loggedCInteropParameters = LoggedData.CInteropParameters(extraArgs = extraArgsArray, defFile = defFile)
|
||||
val (loggedCall: LoggedData, immediateResult: TestCompilationResult.ImmediateResult<out KLIB>) = try {
|
||||
val (exitCode, cinteropOutput, cinteropOutputHasErrors, duration) = invokeCInterop(
|
||||
classLoader.classLoader,
|
||||
targets,
|
||||
defFile,
|
||||
expectedArtifact.klibFile,
|
||||
extraArgsArray
|
||||
)
|
||||
|
||||
val loggedInteropCall = LoggedData.CompilationToolCall(
|
||||
toolName = "CINTEROP",
|
||||
parameters = loggedCInteropParameters,
|
||||
exitCode = exitCode,
|
||||
toolOutput = cinteropOutput,
|
||||
toolOutputHasErrors = cinteropOutputHasErrors,
|
||||
duration = duration
|
||||
)
|
||||
val res = if (exitCode != ExitCode.OK || cinteropOutputHasErrors)
|
||||
TestCompilationResult.CompilationToolFailure(loggedInteropCall)
|
||||
else
|
||||
TestCompilationResult.Success(expectedArtifact, loggedInteropCall)
|
||||
|
||||
loggedInteropCall to res
|
||||
} catch (unexpectedThrowable: Throwable) {
|
||||
val loggedFailure = LoggedData.CompilationToolCallUnexpectedFailure(loggedCInteropParameters, unexpectedThrowable)
|
||||
val res = TestCompilationResult.UnexpectedFailure(loggedFailure)
|
||||
|
||||
loggedFailure to res
|
||||
}
|
||||
expectedArtifact.logFile.writeText(loggedCall.toString())
|
||||
|
||||
immediateResult
|
||||
}
|
||||
}
|
||||
|
||||
internal class ExecutableCompilation(
|
||||
settings: Settings,
|
||||
freeCompilerArgs: TestCompilerArgs,
|
||||
|
||||
+3
-3
@@ -18,8 +18,8 @@ internal sealed interface TestCompilationResult<A : TestCompilationArtifact> {
|
||||
data class Success<A : TestCompilationArtifact>(val resultingArtifact: A, override val loggedData: LoggedData.CompilerCall) :
|
||||
ImmediateResult<A>
|
||||
|
||||
data class CompilerFailure(override val loggedData: LoggedData.RealCompilerCall) : Failure
|
||||
data class UnexpectedFailure(override val loggedData: LoggedData.CompilerCallUnexpectedFailure) : Failure
|
||||
data class CompilationToolFailure(override val loggedData: LoggedData.CompilationToolCall) : Failure
|
||||
data class UnexpectedFailure(override val loggedData: LoggedData) : Failure
|
||||
data class DependencyFailures(val causes: Set<Failure>) : TestCompilationResult<Nothing>
|
||||
|
||||
companion object {
|
||||
@@ -31,7 +31,7 @@ internal sealed interface TestCompilationResult<A : TestCompilationArtifact> {
|
||||
|
||||
private fun Failure.describeFailure() = loggedData.withErrorMessage(
|
||||
when (this@describeFailure) {
|
||||
is CompilerFailure -> "Compilation failed."
|
||||
is CompilationToolFailure -> "Compilation failed."
|
||||
is UnexpectedFailure -> "Compilation failed with unexpected exception."
|
||||
}
|
||||
)
|
||||
|
||||
+1
-1
@@ -20,7 +20,7 @@ internal class LocalTestNameExtractor(
|
||||
override val outputFilter get() = TestOutputFilter.NO_FILTERING
|
||||
|
||||
override fun getLoggedParameters() = LoggedData.TestRunParameters(
|
||||
compilerCall = executable.loggedCompilerCall,
|
||||
compilationToolCall = executable.loggedCompilationToolCall,
|
||||
testCaseId = null,
|
||||
runArgs = programArgs,
|
||||
runParameters = null
|
||||
|
||||
+1
-1
@@ -25,7 +25,7 @@ internal class LocalTestRunner(private val testRun: TestRun) : AbstractLocalProc
|
||||
get() = if (testRun.runParameters.has<TestRunParameter.WithTCTestLogger>()) TCTestOutputFilter else TestOutputFilter.NO_FILTERING
|
||||
|
||||
override fun getLoggedParameters() = LoggedData.TestRunParameters(
|
||||
compilerCall = executable.loggedCompilerCall,
|
||||
compilationToolCall = executable.loggedCompilationToolCall,
|
||||
testCaseId = testRun.testCaseId,
|
||||
runArgs = programArgs,
|
||||
runParameters = testRun.runParameters
|
||||
|
||||
+8
-2
@@ -18,7 +18,7 @@ import java.io.IOException
|
||||
|
||||
internal class TestExecutable(
|
||||
val executableFile: File,
|
||||
val loggedCompilerCall: LoggedData.CompilerCall,
|
||||
val loggedCompilationToolCall: LoggedData.CompilerCall,
|
||||
val testNames: Collection<TestName>
|
||||
) {
|
||||
companion object {
|
||||
@@ -43,7 +43,7 @@ internal class TestExecutable(
|
||||
|
||||
return TestExecutable(
|
||||
executableFile = compilationResult.resultingArtifact.executableFile,
|
||||
loggedCompilerCall = compilationResult.loggedData,
|
||||
loggedCompilationToolCall = compilationResult.loggedData,
|
||||
testNames = testNames
|
||||
)
|
||||
}
|
||||
@@ -100,6 +100,12 @@ internal sealed interface TestRunParameter {
|
||||
class WithExpectedOutputData(val expectedOutputDataFile: File) : TestRunParameter {
|
||||
override fun applyTo(programArgs: MutableList<String>) = Unit
|
||||
}
|
||||
|
||||
class WithFreeCommandLineArguments(val args: List<String>) : TestRunParameter {
|
||||
override fun applyTo(programArgs: MutableList<String>) {
|
||||
programArgs += args
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal inline fun <reified T : TestRunParameter> List<TestRunParameter>.has(): Boolean =
|
||||
|
||||
+19
@@ -0,0 +1,19 @@
|
||||
/*
|
||||
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan.blackboxtest.support.util
|
||||
|
||||
import org.jetbrains.kotlin.konan.blackboxtest.support.compilation.TestCompilationArtifact
|
||||
|
||||
internal fun TestCompilationArtifact.KLIB.getContents(kotlinNativeClassLoader: ClassLoader): String {
|
||||
val libraryClass = Class.forName("org.jetbrains.kotlin.cli.klib.Library", true, kotlinNativeClassLoader)
|
||||
val entryPoint = libraryClass.declaredMethods.single { it.name == "contents" }
|
||||
val lib = libraryClass.getDeclaredConstructor(String::class.java, String::class.java, String::class.java)
|
||||
.newInstance(klibFile.canonicalPath, null, "host")
|
||||
|
||||
val output = StringBuilder()
|
||||
entryPoint.invoke(lib, output, false)
|
||||
return output.toString()
|
||||
}
|
||||
Reference in New Issue
Block a user