[K/N] CInterop ExceptionPrettifier
Add a wrapper around cinterop invocation that tracks exceptions. Wrapper has a set of handlers. Each handler checks exception for some pattern and if it matches, throws another exception with a more user-friendly message. The first such case is compilation error due to missing -fmodules flag.
This commit is contained in:
committed by
Space Team
parent
256764f012
commit
233b01f341
+56
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
* 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.native.interop.gen
|
||||
|
||||
import org.jetbrains.kotlin.konan.util.CInteropHints
|
||||
|
||||
class CInteropPrettyException(message: String) : Exception(message)
|
||||
|
||||
/**
|
||||
* Pattern matching machinery for making exceptions from
|
||||
* cinterop nicer.
|
||||
*/
|
||||
sealed interface ExceptionPrettifier {
|
||||
fun matches(throwable: Throwable): Boolean
|
||||
|
||||
fun prettify(throwable: Throwable): CInteropPrettyException
|
||||
}
|
||||
|
||||
/**
|
||||
* Suggests to add `-compiler-option -fmodules` if the exception message hints about it.
|
||||
*/
|
||||
object ClangModulesDisabledPrettifier : ExceptionPrettifier {
|
||||
|
||||
private val supportedPatterns = listOf(
|
||||
"use of '@import' when modules are disabled"
|
||||
)
|
||||
|
||||
override fun matches(throwable: Throwable): Boolean {
|
||||
return supportedPatterns.any { throwable.message?.contains(it) == true }
|
||||
}
|
||||
|
||||
override fun prettify(throwable: Throwable): CInteropPrettyException {
|
||||
return CInteropPrettyException(CInteropHints.fmodulesHint)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Wraps invocation of [action] into exception handler and makes messages of supported exceptions more user-friendly.
|
||||
* Can be optionally [disabled] which is useful when one want to find the root cause of the prettified exception.
|
||||
*/
|
||||
inline fun <T> withExceptionPrettifier(disabled: Boolean = false, action: () -> T): T {
|
||||
if (disabled) {
|
||||
return action()
|
||||
}
|
||||
return try {
|
||||
action()
|
||||
} catch (throwable: Throwable) {
|
||||
val prettifiers = listOf(
|
||||
ClangModulesDisabledPrettifier,
|
||||
)
|
||||
throw prettifiers.firstOrNull { it.matches(throwable) }?.prettify(throwable) ?: throwable
|
||||
}
|
||||
}
|
||||
+4
@@ -33,6 +33,7 @@ const val COMPILE_SOURCES = "Xcompile-source"
|
||||
const val SHORT_MODULE_NAME = "Xshort-module-name"
|
||||
const val FOREIGN_EXCEPTION_MODE = "Xforeign-exception-mode"
|
||||
const val DUMP_BRIDGES = "Xdump-bridges"
|
||||
const val DISABLE_EXCEPTION_PRETTIFIER = "Xdisable-exception-prettifier"
|
||||
|
||||
// TODO: unify camel and snake cases.
|
||||
// Possible solution is to accept both cases
|
||||
@@ -132,6 +133,9 @@ open class CInteropArguments(argParser: ArgParser =
|
||||
|
||||
val dumpBridges by argParser.option(ArgType.Boolean, DUMP_BRIDGES,
|
||||
description = "Dump generated bridges")
|
||||
|
||||
val disableExceptionPrettifier by argParser.option(ArgType.Boolean, DISABLE_EXCEPTION_PRETTIFIER,
|
||||
description = "Don't hide exceptions with user-friendly ones").default(false)
|
||||
}
|
||||
|
||||
class JSInteropArguments(argParser: ArgParser = ArgParser("jsinterop",
|
||||
|
||||
+15
-5
@@ -71,15 +71,21 @@ class Interop {
|
||||
/**
|
||||
* invoked via reflection from new test system: CompilationToolCallKt.invokeCInterop(),
|
||||
* `interop()` has issues to be invoked directly due to NoSuchMethodError, caused by presence of InternalInteropOptions argtype:
|
||||
* java.lang.IllegalArgumentException: argument type mismatch
|
||||
* java.lang.IllegalArgumentException: argument type mismatch.
|
||||
* Also this method simplifies testing of [CInteropPrettyException] by wrapping the result in Any that acts like a "Result" class.
|
||||
* Using "Result" directly might be complicated due to signature mangle and different class loaders.
|
||||
*/
|
||||
fun interopViaReflection(
|
||||
flavor: String, args: Array<String>,
|
||||
runFromDaemon: Boolean,
|
||||
generated: String, natives: String, manifest: String? = null, cstubsName: String? = null
|
||||
): Array<String>? {
|
||||
): Any? {
|
||||
val internalInteropOptions = InternalInteropOptions(generated, natives, manifest, cstubsName)
|
||||
return interop(flavor, args, internalInteropOptions, runFromDaemon)
|
||||
return try {
|
||||
interop(flavor, args, internalInteropOptions, runFromDaemon)
|
||||
} catch (prettyException: CInteropPrettyException) {
|
||||
prettyException
|
||||
}
|
||||
}
|
||||
|
||||
fun interop(
|
||||
@@ -237,8 +243,12 @@ private fun processCLibSafe(flavor: KotlinPlatform, cinteropArguments: CInteropA
|
||||
}
|
||||
}
|
||||
|
||||
private fun processCLib(flavor: KotlinPlatform, cinteropArguments: CInteropArguments,
|
||||
additionalArgs: InternalInteropOptions, runFromDaemon: Boolean): Array<String>? {
|
||||
private fun processCLib(
|
||||
flavor: KotlinPlatform,
|
||||
cinteropArguments: CInteropArguments,
|
||||
additionalArgs: InternalInteropOptions,
|
||||
runFromDaemon: Boolean,
|
||||
): Array<String>? = withExceptionPrettifier(cinteropArguments.disableExceptionPrettifier) {
|
||||
val ktGenRoot = additionalArgs.generated
|
||||
val nativeLibsDir = additionalArgs.natives
|
||||
val defFile = cinteropArguments.def?.let { File(it) }
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* 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.util
|
||||
|
||||
// We store pretty cinterop messages because we want to access them in test infra as well.
|
||||
object CInteropHints {
|
||||
// It would be nice to mark this property as const when `trimIndent` becomes constexpr.
|
||||
val fmodulesHint = """
|
||||
It seems that library is using clang modules. Try adding `-compiler-option -fmodules` to cinterop.
|
||||
For example, in case of cocoapods plugin:
|
||||
|
||||
pod("PodName") {
|
||||
// Add these lines
|
||||
extraOpts += listOf("-compiler-option", "-fmodules")
|
||||
}
|
||||
""".trimIndent()
|
||||
}
|
||||
Reference in New Issue
Block a user