Interop: add minor code improvements
This commit is contained in:
@@ -1,31 +1,29 @@
|
|||||||
#include <pthread.h>
|
|
||||||
#include <jni.h>
|
#include <jni.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <stdio.h>
|
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
|
|
||||||
static JavaVM *vm = NULL;
|
static JavaVM *vm = NULL;
|
||||||
|
|
||||||
|
// Returns the JNI env which can be used by the caller.
|
||||||
|
// If current thread is not attached to JVM, then it gets attached as daemon.
|
||||||
static JNIEnv* getCurrentEnv() {
|
static JNIEnv* getCurrentEnv() {
|
||||||
// printf("%p\n", pthread_self());
|
|
||||||
JNIEnv* env;
|
JNIEnv* env;
|
||||||
assert (vm != NULL);
|
assert (vm != NULL);
|
||||||
jint res = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_1);
|
jint res = (*vm)->GetEnv(vm, (void**)&env, JNI_VERSION_1_1);
|
||||||
if (res != JNI_OK) {
|
if (res != JNI_OK) {
|
||||||
assert(res == JNI_EDETACHED);
|
assert (res == JNI_EDETACHED);
|
||||||
res = (*vm)->AttachCurrentThreadAsDaemon(vm, (void**)&env, NULL);
|
res = (*vm)->AttachCurrentThreadAsDaemon(vm, (void**)&env, NULL);
|
||||||
assert (res == JNI_OK);
|
assert (res == JNI_OK);
|
||||||
}
|
}
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
jint JNI_OnLoad(JavaVM *vm_, void *reserved) {
|
jint JNI_OnLoad(JavaVM *vm_, void *reserved) {
|
||||||
vm = vm_;
|
vm = vm_;
|
||||||
getCurrentEnv();
|
|
||||||
return JNI_VERSION_1_1;
|
return JNI_VERSION_1_1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// The implementation of native callback.
|
||||||
void indexDeclarationNativeCallback(void* arg1, void* arg2) {
|
void indexDeclarationNativeCallback(void* arg1, void* arg2) {
|
||||||
JNIEnv* env = getCurrentEnv();
|
JNIEnv* env = getCurrentEnv();
|
||||||
|
|
||||||
@@ -34,15 +32,15 @@ void indexDeclarationNativeCallback(void* arg1, void* arg2) {
|
|||||||
|
|
||||||
if (cls == NULL) {
|
if (cls == NULL) {
|
||||||
cls = (*env)->FindClass(env, "org/jetbrains/kotlin/native/interop/indexer/indexDeclarationCallback");
|
cls = (*env)->FindClass(env, "org/jetbrains/kotlin/native/interop/indexer/indexDeclarationCallback");
|
||||||
assert(cls != NULL);
|
assert(cls != NULL);
|
||||||
entryFromNative = (*env)->GetStaticMethodID(env, cls, "entryFromNative", "(J)V");
|
entryFromNative = (*env)->GetStaticMethodID(env, cls, "entryFromNative", "(J)V");
|
||||||
assert(entryFromNative != NULL);
|
assert(entryFromNative != NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
(*env)->CallStaticVoidMethod(env, cls, entryFromNative, (jlong) arg2);
|
(*env)->CallStaticVoidMethod(env, cls, entryFromNative, (jlong) arg2);
|
||||||
if ((*env)->ExceptionCheck(env)) {
|
if ((*env)->ExceptionCheck(env)) {
|
||||||
(*env)->ExceptionDescribe(env);
|
(*env)->ExceptionDescribe(env);
|
||||||
assert(0);
|
assert(0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+21
@@ -3,21 +3,39 @@ package org.jetbrains.kotlin.native.interop.indexer
|
|||||||
import clang.CXIdxDeclInfo
|
import clang.CXIdxDeclInfo
|
||||||
import kotlin_native.interop.NativePtr
|
import kotlin_native.interop.NativePtr
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This object helps to create native callbacks with signature `void (CXClientData, const CXIdxDeclInfo *)`.
|
||||||
|
* At any time only one instance of native callback can exist.
|
||||||
|
*/
|
||||||
internal object indexDeclarationCallback {
|
internal object indexDeclarationCallback {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The Kotlin function to be called when native callback is called.
|
||||||
|
*/
|
||||||
private var function: ((CXIdxDeclInfo)->Unit)? = null
|
private var function: ((CXIdxDeclInfo)->Unit)? = null
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Creates instance of native callback with given Kotlin implementation.
|
||||||
|
*
|
||||||
|
* To create another one, this instance must be destroyed using [reset].
|
||||||
|
*/
|
||||||
fun setUp(func: (CXIdxDeclInfo)->Unit): NativePtr {
|
fun setUp(func: (CXIdxDeclInfo)->Unit): NativePtr {
|
||||||
assert (function == null)
|
assert (function == null)
|
||||||
function = func
|
function = func
|
||||||
return nativeCallbackPtr
|
return nativeCallbackPtr
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Destroys the (only) instance of native callback.
|
||||||
|
*/
|
||||||
fun reset() {
|
fun reset() {
|
||||||
assert (function != null)
|
assert (function != null)
|
||||||
function = null
|
function = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function is called from native callback implementation.
|
||||||
|
*/
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
private fun entryFromNative(info: Long) {
|
private fun entryFromNative(info: Long) {
|
||||||
function!!(CXIdxDeclInfo(NativePtr.Companion.byValue(info)!!))
|
function!!(CXIdxDeclInfo(NativePtr.Companion.byValue(info)!!))
|
||||||
@@ -30,5 +48,8 @@ internal object indexDeclarationCallback {
|
|||||||
nativeCallbackPtr = NativePtr.byValue(nativeCallbackPtr())!!
|
nativeCallbackPtr = NativePtr.byValue(nativeCallbackPtr())!!
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the pointer to native callback.
|
||||||
|
*/
|
||||||
private external fun nativeCallbackPtr(): Long
|
private external fun nativeCallbackPtr(): Long
|
||||||
}
|
}
|
||||||
+33
-6
@@ -2,41 +2,68 @@ package org.jetbrains.kotlin.native.interop.indexer
|
|||||||
|
|
||||||
import java.io.File
|
import java.io.File
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Retrieves the definitions from given C header file using given compiler arguments (e.g. defines).
|
||||||
|
*/
|
||||||
fun buildNativeIndex(headerFile: File, args: List<String>): NativeIndex = buildNativeIndexImpl(headerFile, args)
|
fun buildNativeIndex(headerFile: File, args: List<String>): NativeIndex = buildNativeIndexImpl(headerFile, args)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This class describes the IR of definitions from C header file(s).
|
||||||
|
*/
|
||||||
abstract class NativeIndex {
|
abstract class NativeIndex {
|
||||||
abstract val structs: List<StructDecl>
|
abstract val structs: List<StructDecl>
|
||||||
abstract val enums: List<EnumDef>
|
abstract val enums: List<EnumDef>
|
||||||
abstract val functions: List<FunctionDecl>
|
abstract val functions: List<FunctionDecl>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C struct field.
|
||||||
|
*/
|
||||||
|
class Field(val name: String, val type: Type, val offset: Long)
|
||||||
|
|
||||||
class Field(val name: String, val type: Type, val offset: Long) {
|
/**
|
||||||
override fun toString(): String = "$type $name at $offset"
|
* C struct declaration.
|
||||||
}
|
*/
|
||||||
|
|
||||||
abstract class StructDecl(val spelling: String) {
|
abstract class StructDecl(val spelling: String) {
|
||||||
|
|
||||||
abstract val def: StructDef?
|
abstract val def: StructDef?
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C struct definition.
|
||||||
|
*/
|
||||||
abstract class StructDef(val size: Long, val decl: StructDecl) {
|
abstract class StructDef(val size: Long, val decl: StructDecl) {
|
||||||
|
|
||||||
abstract val fields: List<Field>
|
abstract val fields: List<Field>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C enum value.
|
||||||
|
*/
|
||||||
class EnumValue(val name: String, val value: Long)
|
class EnumValue(val name: String, val value: Long)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C enum definition.
|
||||||
|
*/
|
||||||
abstract class EnumDef(val spelling: String, val baseType: PrimitiveType) {
|
abstract class EnumDef(val spelling: String, val baseType: PrimitiveType) {
|
||||||
|
|
||||||
abstract val values: List<EnumValue>
|
abstract val values: List<EnumValue>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C function parameter.
|
||||||
|
*/
|
||||||
class Parameter(val name: String?, val type: Type)
|
class Parameter(val name: String?, val type: Type)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C function declaration.
|
||||||
|
*/
|
||||||
class FunctionDecl(val name: String, val parameters: List<Parameter>, val returnType: Type)
|
class FunctionDecl(val name: String, val parameters: List<Parameter>, val returnType: Type)
|
||||||
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* C type.
|
||||||
|
*/
|
||||||
open class Type
|
open class Type
|
||||||
|
|
||||||
open class PrimitiveType : Type()
|
open class PrimitiveType : Type()
|
||||||
|
|||||||
+102
-14
@@ -9,19 +9,32 @@ class StubGenerator(
|
|||||||
val libName: String,
|
val libName: String,
|
||||||
val excludedFunctions: Set<String>) {
|
val excludedFunctions: Set<String>) {
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The names that should not be used for struct classes to prevent name clashes
|
||||||
|
*/
|
||||||
val forbiddenStructNames = run {
|
val forbiddenStructNames = run {
|
||||||
val functionNames = nativeIndex.functions.map { it.name }
|
val functionNames = nativeIndex.functions.map { it.name }
|
||||||
val fieldNames = nativeIndex.structs.mapNotNull { it.def }.flatMap { it.fields }.map { it.name }
|
val fieldNames = nativeIndex.structs.mapNotNull { it.def }.flatMap { it.fields }.map { it.name }
|
||||||
(functionNames + fieldNames).toSet()
|
(functionNames + fieldNames).toSet()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name to be used for this struct in Kotlin
|
||||||
|
*/
|
||||||
val StructDecl.kotlinName: String
|
val StructDecl.kotlinName: String
|
||||||
get() = if (spelling.startsWith("struct ") || spelling.startsWith("union ")) {
|
get() {
|
||||||
spelling.substringAfter(' ')
|
val strippedCName = if (spelling.startsWith("struct ") || spelling.startsWith("union ")) {
|
||||||
} else {
|
spelling.substringAfter(' ')
|
||||||
spelling
|
} else {
|
||||||
|
spelling
|
||||||
|
}
|
||||||
|
|
||||||
|
return if (strippedCName !in forbiddenStructNames) strippedCName else (strippedCName + "Struct")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The name to be used for this enum in Kotlin
|
||||||
|
*/
|
||||||
val EnumDef.kotlinName: String
|
val EnumDef.kotlinName: String
|
||||||
get() = if (spelling.startsWith("enum ")) {
|
get() = if (spelling.startsWith("enum ")) {
|
||||||
spelling.substringAfter(' ')
|
spelling.substringAfter(' ')
|
||||||
@@ -38,11 +51,10 @@ class StubGenerator(
|
|||||||
|
|
||||||
val functionsToBind = nativeIndex.functions.filter { it.name !in excludedFunctions }
|
val functionsToBind = nativeIndex.functions.filter { it.name !in excludedFunctions }
|
||||||
|
|
||||||
private fun mangleStructName(name: String) = if (name !in forbiddenStructNames) name else (name + "Struct")
|
/**
|
||||||
|
* The output currently used by the generator.
|
||||||
val StructDecl.mangledName: String
|
* Should append line separator after any usage.
|
||||||
get() = mangleStructName(kotlinName)
|
*/
|
||||||
|
|
||||||
private var out: (String) -> Unit = {
|
private var out: (String) -> Unit = {
|
||||||
throw IllegalStateException()
|
throw IllegalStateException()
|
||||||
}
|
}
|
||||||
@@ -70,7 +82,11 @@ class StubGenerator(
|
|||||||
return withOutput({ oldOut(" $it") }, action)
|
return withOutput({ oldOut(" $it") }, action)
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: use libclang to implement:
|
/**
|
||||||
|
* Returns the expression which could be used for this type in C code.
|
||||||
|
*
|
||||||
|
* TODO: use libclang to implement:
|
||||||
|
*/
|
||||||
fun Type.getStringRepresentation(): String {
|
fun Type.getStringRepresentation(): String {
|
||||||
return when (this) {
|
return when (this) {
|
||||||
|
|
||||||
@@ -118,8 +134,18 @@ class StubGenerator(
|
|||||||
else -> throw NotImplementedError()
|
else -> throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes the Kotlin native reference type
|
||||||
|
*
|
||||||
|
* @param typeName the name of the Kotlin native reference type
|
||||||
|
* @param typeExpr such Kotlin expression that `typeExpr(ptr)` constructs the reference of this type
|
||||||
|
* to the value located at `ptr`
|
||||||
|
*/
|
||||||
class NativeRefType(val typeName: String, val typeExpr: String = typeName)
|
class NativeRefType(val typeName: String, val typeExpr: String = typeName)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the Kotlin type which describes the reference to value of given (C) type.
|
||||||
|
*/
|
||||||
fun getKotlinTypeForRefTo(type: Type): NativeRefType = when (type) {
|
fun getKotlinTypeForRefTo(type: Type): NativeRefType = when (type) {
|
||||||
is Int8Type, is UInt8Type -> NativeRefType("Int8Box")
|
is Int8Type, is UInt8Type -> NativeRefType("Int8Box")
|
||||||
is Int16Type, is UInt16Type -> NativeRefType("Int16Box")
|
is Int16Type, is UInt16Type -> NativeRefType("Int16Box")
|
||||||
@@ -127,7 +153,7 @@ class StubGenerator(
|
|||||||
is IntPtrType, is UIntPtrType, // TODO: 64-bit specific
|
is IntPtrType, is UIntPtrType, // TODO: 64-bit specific
|
||||||
is Int64Type, is UInt64Type -> NativeRefType("Int64Box")
|
is Int64Type, is UInt64Type -> NativeRefType("Int64Box")
|
||||||
|
|
||||||
is RecordType -> NativeRefType("${mangleStructName(type.kotlinName)}")
|
is RecordType -> NativeRefType("${type.kotlinName}")
|
||||||
|
|
||||||
is EnumType -> NativeRefType("${type.kotlinName}.ref")
|
is EnumType -> NativeRefType("${type.kotlinName}.ref")
|
||||||
|
|
||||||
@@ -153,27 +179,51 @@ class StubGenerator(
|
|||||||
else -> throw NotImplementedError()
|
else -> throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes how to represent in Kotlin the value to be passed to native code.
|
||||||
|
*
|
||||||
|
* @param kotlinType the name of Kotlin type to be used for this value in Kotlin.
|
||||||
|
* @param kotlinConv the function such that `kotlinConv(name)` converts variable `name` to pass it into JNI stub
|
||||||
|
* @param convFree the function such that `convFree(name)` is the statement that frees the result of conversion
|
||||||
|
* @param kotlinJniBridgeType the name of Kotlin type to be used for this value in JNI stub
|
||||||
|
*/
|
||||||
class OutValueBinding(val kotlinType: String,
|
class OutValueBinding(val kotlinType: String,
|
||||||
val kotlinConv: ((String) -> String)? = null,
|
val kotlinConv: ((String) -> String)? = null,
|
||||||
val convFree: ((String) -> String)? = null,
|
val convFree: ((String) -> String)? = null,
|
||||||
val kotlinJniBridgeType: String = kotlinType)
|
val kotlinJniBridgeType: String = kotlinType)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Describes how to represent in Kotlin the value to be received from native code.
|
||||||
|
*
|
||||||
|
* @param kotlinJniBridgeType the name of Kotlin type to be used for this value in JNI stub
|
||||||
|
* @param conv the function such that `conv(name)` converts variable `name` received from JNI stub to `kotlinType`.
|
||||||
|
* @param kotlinType the name of Kotlin type to be used for this value in Kotlin.
|
||||||
|
*/
|
||||||
class InValueBinding(val kotlinJniBridgeType: String,
|
class InValueBinding(val kotlinJniBridgeType: String,
|
||||||
val conv: ((String) -> String) = { it },
|
val conv: ((String) -> String) = { it },
|
||||||
val kotlinType: String = kotlinJniBridgeType)
|
val kotlinType: String = kotlinJniBridgeType)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs [OutValueBinding] for the value represented by given native reference type in Kotlin.
|
||||||
|
*/
|
||||||
fun outValueRefBinding(refType: NativeRefType) = OutValueBinding(
|
fun outValueRefBinding(refType: NativeRefType) = OutValueBinding(
|
||||||
kotlinType = refType.typeName + "?",
|
kotlinType = refType.typeName + "?",
|
||||||
kotlinConv = { "$it.getNativePtr().asLong()" },
|
kotlinConv = { "$it.getNativePtr().asLong()" },
|
||||||
kotlinJniBridgeType = "Long"
|
kotlinJniBridgeType = "Long"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs [InValueBinding] for the value represented by given native reference type in Kotlin.
|
||||||
|
*/
|
||||||
fun inValueRefBinding(refType: NativeRefType) = InValueBinding(
|
fun inValueRefBinding(refType: NativeRefType) = InValueBinding(
|
||||||
kotlinJniBridgeType = "Long",
|
kotlinJniBridgeType = "Long",
|
||||||
conv = { "NativePtr.byValue($it).asRef(${refType.typeExpr})" },
|
conv = { "NativePtr.byValue($it).asRef(${refType.typeExpr})" },
|
||||||
kotlinType = refType.typeName + "?"
|
kotlinType = refType.typeName + "?"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs [OutValueBinding] for the value of given C type.
|
||||||
|
*/
|
||||||
fun getOutValueBinding(type: Type): OutValueBinding = when (type) {
|
fun getOutValueBinding(type: Type): OutValueBinding = when (type) {
|
||||||
|
|
||||||
is PrimitiveType -> OutValueBinding(type.kotlinType)
|
is PrimitiveType -> OutValueBinding(type.kotlinType)
|
||||||
@@ -218,6 +268,9 @@ class StubGenerator(
|
|||||||
else -> throw NotImplementedError()
|
else -> throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs [InValueBinding] for the value of given C type.
|
||||||
|
*/
|
||||||
fun getInValueBinding(type: Type): InValueBinding = when (type) {
|
fun getInValueBinding(type: Type): InValueBinding = when (type) {
|
||||||
|
|
||||||
is PrimitiveType -> InValueBinding(type.kotlinType)
|
is PrimitiveType -> InValueBinding(type.kotlinType)
|
||||||
@@ -257,7 +310,9 @@ class StubGenerator(
|
|||||||
else -> throw NotImplementedError()
|
else -> throw NotImplementedError()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the definition of Kotlin class representing the reference to given struct.
|
||||||
|
*/
|
||||||
private fun generateKotlinStruct(decl: StructDecl) {
|
private fun generateKotlinStruct(decl: StructDecl) {
|
||||||
val def = decl.def
|
val def = decl.def
|
||||||
if (def == null) {
|
if (def == null) {
|
||||||
@@ -265,7 +320,7 @@ class StubGenerator(
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
val className = decl.mangledName
|
val className = decl.kotlinName
|
||||||
out("class $className(ptr: NativePtr) : NativeStruct(ptr) {")
|
out("class $className(ptr: NativePtr) : NativeStruct(ptr) {")
|
||||||
indent {
|
indent {
|
||||||
out("")
|
out("")
|
||||||
@@ -286,13 +341,19 @@ class StubGenerator(
|
|||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the definition of Kotlin class representing the reference to given forward (incomplete) struct.
|
||||||
|
*/
|
||||||
private fun generateKotlinForwardStruct(s: StructDecl) {
|
private fun generateKotlinForwardStruct(s: StructDecl) {
|
||||||
val className = s.mangledName
|
val className = s.kotlinName
|
||||||
out("class $className(ptr: NativePtr) : NativeRef(ptr) {")
|
out("class $className(ptr: NativePtr) : NativeRef(ptr) {")
|
||||||
out(" companion object : Type<$className>(::$className)")
|
out(" companion object : Type<$className>(::$className)")
|
||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the definition of Kotlin class representing the value of given enum.
|
||||||
|
*/
|
||||||
private fun generateKotlinEnum(e: EnumDef) {
|
private fun generateKotlinEnum(e: EnumDef) {
|
||||||
val baseRefType = getKotlinTypeForRefTo(e.baseType)
|
val baseRefType = getKotlinTypeForRefTo(e.baseType)
|
||||||
|
|
||||||
@@ -318,8 +379,14 @@ class StubGenerator(
|
|||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs [InValueBinding] for return value of Kotlin binding for given C function.
|
||||||
|
*/
|
||||||
private fun retValBinding(func: FunctionDecl) = getInValueBinding(func.returnType)
|
private fun retValBinding(func: FunctionDecl) = getInValueBinding(func.returnType)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Constructs [OutValueBinding]s for parameters of Kotlin binding for given C function.
|
||||||
|
*/
|
||||||
private fun paramBindings(func: FunctionDecl): Array<OutValueBinding> {
|
private fun paramBindings(func: FunctionDecl): Array<OutValueBinding> {
|
||||||
val paramBindings = func.parameters.map { param ->
|
val paramBindings = func.parameters.map { param ->
|
||||||
getOutValueBinding(param.type)
|
getOutValueBinding(param.type)
|
||||||
@@ -340,6 +407,9 @@ class StubGenerator(
|
|||||||
return paramBindings.toTypedArray()
|
return paramBindings.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns names for parameters of Kotlin binding for given C function.
|
||||||
|
*/
|
||||||
private fun paramNames(func: FunctionDecl): Array<String> {
|
private fun paramNames(func: FunctionDecl): Array<String> {
|
||||||
val paramNames = func.parameters.mapIndexed { i: Int, parameter: Parameter ->
|
val paramNames = func.parameters.mapIndexed { i: Int, parameter: Parameter ->
|
||||||
val name = parameter.name
|
val name = parameter.name
|
||||||
@@ -357,6 +427,9 @@ class StubGenerator(
|
|||||||
return paramNames.toTypedArray()
|
return paramNames.toTypedArray()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the definition of Kotlin binding for given C function.
|
||||||
|
*/
|
||||||
private fun generateKotlinBindingMethod(func: FunctionDecl) {
|
private fun generateKotlinBindingMethod(func: FunctionDecl) {
|
||||||
val paramNames = paramNames(func)
|
val paramNames = paramNames(func)
|
||||||
val paramBindings = paramBindings(func)
|
val paramBindings = paramBindings(func)
|
||||||
@@ -395,6 +468,9 @@ class StubGenerator(
|
|||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the definition of Kotlin JNI function used in binding for given C function.
|
||||||
|
*/
|
||||||
private fun generateKotlinExternalMethod(func: FunctionDecl) {
|
private fun generateKotlinExternalMethod(func: FunctionDecl) {
|
||||||
val paramNames = paramNames(func)
|
val paramNames = paramNames(func)
|
||||||
val paramBindings = paramBindings(func)
|
val paramBindings = paramBindings(func)
|
||||||
@@ -407,6 +483,9 @@ class StubGenerator(
|
|||||||
out("external fun ${func.name}($args): ${retValBinding.kotlinJniBridgeType}")
|
out("external fun ${func.name}($args): ${retValBinding.kotlinJniBridgeType}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the contents of file with Kotlin bindings.
|
||||||
|
*/
|
||||||
fun generateKotlinFile() {
|
fun generateKotlinFile() {
|
||||||
if (pkgName != "") {
|
if (pkgName != "") {
|
||||||
out("package $pkgName")
|
out("package $pkgName")
|
||||||
@@ -459,6 +538,9 @@ class StubGenerator(
|
|||||||
out("}")
|
out("}")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Returns the C type to be used for value of given Kotlin type in JNI function implementation.
|
||||||
|
*/
|
||||||
fun getCJniBridgeType(kotlinJniBridgeType: String) = when (kotlinJniBridgeType) {
|
fun getCJniBridgeType(kotlinJniBridgeType: String) = when (kotlinJniBridgeType) {
|
||||||
"Unit" -> "void"
|
"Unit" -> "void"
|
||||||
"Byte" -> "jbyte"
|
"Byte" -> "jbyte"
|
||||||
@@ -468,6 +550,9 @@ class StubGenerator(
|
|||||||
else -> throw NotImplementedError(kotlinJniBridgeType)
|
else -> throw NotImplementedError(kotlinJniBridgeType)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the contents of C source file to be compiled into JNI lib used for Kotlin bindings impl.
|
||||||
|
*/
|
||||||
fun generateCFile(headerFiles: List<String>) {
|
fun generateCFile(headerFiles: List<String>) {
|
||||||
out("#include <stdint.h>")
|
out("#include <stdint.h>")
|
||||||
out("#include <jni.h>")
|
out("#include <jni.h>")
|
||||||
@@ -485,6 +570,9 @@ class StubGenerator(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Produces to [out] the implementation of JNI function used in Kotlin binding for given C function.
|
||||||
|
*/
|
||||||
private fun generateCJniFunction(func: FunctionDecl) {
|
private fun generateCJniFunction(func: FunctionDecl) {
|
||||||
val funcReturnType = func.returnType
|
val funcReturnType = func.returnType
|
||||||
val paramNames = paramNames(func)
|
val paramNames = paramNames(func)
|
||||||
|
|||||||
+5
-3
@@ -22,7 +22,9 @@ class NativeInteropPlugin implements Plugin<Project> {
|
|||||||
interopStubGenerator project(path: ":Interop:StubGenerator")
|
interopStubGenerator project(path: ":Interop:StubGenerator")
|
||||||
}
|
}
|
||||||
|
|
||||||
prj.task("genInteropStubs", type: JavaExec) {
|
def genStubsTaskName = "genInteropStubs"
|
||||||
|
|
||||||
|
prj.task(genStubsTaskName, type: JavaExec) {
|
||||||
classpath = prj.configurations.interopStubGenerator
|
classpath = prj.configurations.interopStubGenerator
|
||||||
main = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
|
main = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
|
||||||
args = [srcDir, generatedSrcDir, nativeLibsDir]
|
args = [srcDir, generatedSrcDir, nativeLibsDir]
|
||||||
@@ -45,12 +47,12 @@ class NativeInteropPlugin implements Plugin<Project> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
prj.tasks.getByName("compileKotlin") {
|
prj.tasks.getByName("compileKotlin") {
|
||||||
dependsOn "genInteropStubs"
|
dependsOn genStubsTaskName
|
||||||
}
|
}
|
||||||
|
|
||||||
// FIXME: choose tasks more wisely
|
// FIXME: choose tasks more wisely
|
||||||
prj.tasks.withType(JavaExec) {
|
prj.tasks.withType(JavaExec) {
|
||||||
if (name != "genInteropStubs") {
|
if (name != genStubsTaskName) {
|
||||||
systemProperties "java.library.path": nativeLibsDir
|
systemProperties "java.library.path": nativeLibsDir
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user