Python extension sample. (#1123)
This commit is contained in:
+11
-10
@@ -208,7 +208,7 @@ private class ExportedElement(val kind: ElementKind,
|
|||||||
|
|
||||||
fun makeClassDeclaration(): String {
|
fun makeClassDeclaration(): String {
|
||||||
assert(isClass)
|
assert(isClass)
|
||||||
return "extern \"C\" ${owner.prefix}_KType* $cname();"
|
return "extern \"C\" ${owner.prefix}_KType* $cname(void);"
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun translateArgument(name: String, clazz: ClassDescriptor, direction: Direction,
|
private fun translateArgument(name: String, clazz: ClassDescriptor, direction: Direction,
|
||||||
@@ -366,7 +366,7 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
element.isFunction ->
|
element.isFunction ->
|
||||||
output(element.makeFunctionPointerString(), indent)
|
output(element.makeFunctionPointerString(), indent)
|
||||||
element.isClass ->
|
element.isClass ->
|
||||||
output("${prefix}_KType* (*_type)();", indent)
|
output("${prefix}_KType* (*_type)(void);", indent)
|
||||||
// TODO: handle properties.
|
// TODO: handle properties.
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -455,7 +455,7 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
output("typedef struct {")
|
output("typedef struct {")
|
||||||
output("/* Service functions. */", 1)
|
output("/* Service functions. */", 1)
|
||||||
output("void (*DisposeStablePointer)(${prefix}_KNativePtr ptr);", 1)
|
output("void (*DisposeStablePointer)(${prefix}_KNativePtr ptr);", 1)
|
||||||
output("void (*DisposeString)(char* string);", 1)
|
output("void (*DisposeString)(const char* string);", 1)
|
||||||
output("${prefix}_KBoolean (*IsInstance)(${prefix}_KNativePtr ref, const ${prefix}_KType* type);", 1)
|
output("${prefix}_KBoolean (*IsInstance)(${prefix}_KNativePtr ref, const ${prefix}_KType* type);", 1)
|
||||||
|
|
||||||
output("")
|
output("")
|
||||||
@@ -463,7 +463,7 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
makeScopeDefinitions(top, DefinitionKind.C_HEADER_STRUCT, 1)
|
makeScopeDefinitions(top, DefinitionKind.C_HEADER_STRUCT, 1)
|
||||||
output("} ${prefix}_ExportedSymbols;")
|
output("} ${prefix}_ExportedSymbols;")
|
||||||
|
|
||||||
output("extern ${prefix}_ExportedSymbols* ${prefix}_symbols();")
|
output("extern ${prefix}_ExportedSymbols* ${prefix}_symbols(void);")
|
||||||
output("""
|
output("""
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
} /* extern "C" */
|
} /* extern "C" */
|
||||||
@@ -490,7 +490,7 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
|#define RUNTIME_NOTHROW __attribute__((nothrow))
|
|#define RUNTIME_NOTHROW __attribute__((nothrow))
|
||||||
|#define RUNTIME_USED __attribute__((used))
|
|#define RUNTIME_USED __attribute__((used))
|
||||||
|
|
|
|
||||||
|void SetRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|
|extern "C" {
|
||||||
|void UpdateRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|
|void UpdateRef(KObjHeader**, const KObjHeader*) RUNTIME_NOTHROW;
|
||||||
|KObjHeader* AllocInstance(const KTypeInfo*, KObjHeader**) RUNTIME_NOTHROW;
|
|KObjHeader* AllocInstance(const KTypeInfo*, KObjHeader**) RUNTIME_NOTHROW;
|
||||||
|KObjHeader* DerefStablePointer(void*, KObjHeader**) RUNTIME_NOTHROW;
|
|KObjHeader* DerefStablePointer(void*, KObjHeader**) RUNTIME_NOTHROW;
|
||||||
@@ -502,12 +502,13 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
|KObjHeader* CreateStringFromCString(const char*, KObjHeader**);
|
|KObjHeader* CreateStringFromCString(const char*, KObjHeader**);
|
||||||
|char* CreateCStringFromString(const KObjHeader*);
|
|char* CreateCStringFromString(const KObjHeader*);
|
||||||
|void DisposeCString(char* cstring);
|
|void DisposeCString(char* cstring);
|
||||||
|
|} // extern "C"
|
||||||
|
|
|
|
||||||
|class KObjHolder {
|
|class KObjHolder {
|
||||||
|public:
|
|public:
|
||||||
| KObjHolder() : obj_(nullptr) {}
|
| KObjHolder() : obj_(nullptr) {}
|
||||||
| explicit KObjHolder(const KObjHeader* obj) {
|
| explicit KObjHolder(const KObjHeader* obj) : obj_(nullptr) {
|
||||||
| SetRef(&obj_, obj);
|
| UpdateRef(&obj_, obj);
|
||||||
| }
|
| }
|
||||||
| ~KObjHolder() {
|
| ~KObjHolder() {
|
||||||
| UpdateRef(&obj_, nullptr);
|
| UpdateRef(&obj_, nullptr);
|
||||||
@@ -520,8 +521,8 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
|static void DisposeStablePointerImpl(${prefix}_KNativePtr ptr) {
|
|static void DisposeStablePointerImpl(${prefix}_KNativePtr ptr) {
|
||||||
| DisposeStablePointer(ptr);
|
| DisposeStablePointer(ptr);
|
||||||
|}
|
|}
|
||||||
|static void DisposeStringImpl(char* ptr) {
|
|static void DisposeStringImpl(const char* ptr) {
|
||||||
| DisposeCString(ptr);
|
| DisposeCString((char*)ptr);
|
||||||
|}
|
|}
|
||||||
|static ${prefix}_KBoolean IsInstanceImpl(${prefix}_KNativePtr ref, const ${prefix}_KType* type) {
|
|static ${prefix}_KBoolean IsInstanceImpl(${prefix}_KNativePtr ref, const ${prefix}_KType* type) {
|
||||||
| KObjHolder holder;
|
| KObjHolder holder;
|
||||||
@@ -535,7 +536,7 @@ internal class CAdapterGenerator(val context: Context,
|
|||||||
output(".IsInstance = IsInstanceImpl,", 1)
|
output(".IsInstance = IsInstanceImpl,", 1)
|
||||||
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_STRUCT, 1)
|
makeScopeDefinitions(top, DefinitionKind.C_SOURCE_STRUCT, 1)
|
||||||
output("};")
|
output("};")
|
||||||
output("RUNTIME_USED ${prefix}_ExportedSymbols* ${prefix}_symbols() { return &__konan_symbols;}")
|
output("RUNTIME_USED ${prefix}_ExportedSymbols* ${prefix}_symbols(void) { return &__konan_symbols;}")
|
||||||
outputStreamWriter.close()
|
outputStreamWriter.close()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -0,0 +1,99 @@
|
|||||||
|
# C to Kotlin/Native interoperability example
|
||||||
|
|
||||||
|
This example shows how to use Kotlin/Native programs from other execution environments, such as Python.
|
||||||
|
Python has C native interface, which could be used to organize a bridge with the
|
||||||
|
Kotlin/Native application. File `kotlin_bridge.c` contains translation code between Kotlin and Python
|
||||||
|
lands.
|
||||||
|
|
||||||
|
To build and run the sample do the following:
|
||||||
|
|
||||||
|
* Run `build.sh`, it will ask for superuser password to install Python extension
|
||||||
|
* On macOS copy Kotlin binary to extension's directory and change install name with
|
||||||
|
`install_name_tool` tool, i.e.
|
||||||
|
```
|
||||||
|
sudo cp libserver.dylib /Library/Python/2.7/site-packages/
|
||||||
|
sudo install_name_tool /Library/Python/2.7/site-packages/kotlin_bridge.so \
|
||||||
|
-change libserver.dylib @loader_path/libserver.dylib
|
||||||
|
```
|
||||||
|
|
||||||
|
* run Python code using Kotlin functionality with
|
||||||
|
```
|
||||||
|
python src/main/python/main.py
|
||||||
|
```
|
||||||
|
* it will show you result of using several Kotlin/Native APIs, accepting and returning both objects and
|
||||||
|
primitive types
|
||||||
|
|
||||||
|
The example works as following. Kotlin/Native API is implemented in `Server.kt`, and we run Kotlin/Native compiler
|
||||||
|
with `-produce dynamic` option. Compiler produces two artifacts: `server_api.h` which is C language API
|
||||||
|
to all public functions and classes available in the application. `libserver.dylib` or `libserver.so`
|
||||||
|
shared object contains C bridge to all above APIs.
|
||||||
|
|
||||||
|
This C bridge looks like a C struct, reflecting all scopes in program, with operations available. For example,
|
||||||
|
for class Server
|
||||||
|
```c_cpp
|
||||||
|
class Server(val prefix: String) {
|
||||||
|
fun greet(session: Session) = "$prefix: Hello from Kotlin/Native in ${session}"
|
||||||
|
fun concat(session: Session, a: String, b: String) = "$prefix: $a $b in ${session}"
|
||||||
|
fun add(session: Session, a: Int, b: Int) = a + b + session.number
|
||||||
|
}
|
||||||
|
```
|
||||||
|
following C API is produced
|
||||||
|
```c_cpp
|
||||||
|
typedef struct {
|
||||||
|
server_KNativePtr pinned;
|
||||||
|
} server_kref_demo_Session;
|
||||||
|
typedef struct {
|
||||||
|
server_KNativePtr pinned;
|
||||||
|
} server_kref_demo_Server;
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
/* Service functions. */
|
||||||
|
void (*DisposeStablePointer)(server_KNativePtr ptr);
|
||||||
|
void (*DisposeString)(const char* string);
|
||||||
|
server_KBoolean (*IsInstance)(server_KNativePtr ref, const server_KType* type);
|
||||||
|
|
||||||
|
/* User functions. */
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
struct {
|
||||||
|
server_KType* (*_type)(void);
|
||||||
|
server_kref_demo_Session (*Session)(const char* name, server_KInt number);
|
||||||
|
} Session;
|
||||||
|
struct {
|
||||||
|
server_KType* (*_type)(void);
|
||||||
|
server_kref_demo_Server (*Server)(const char* prefix);
|
||||||
|
const char* (*greet)(server_kref_demo_Server thiz, server_kref_demo_Session session);
|
||||||
|
const char* (*concat)(server_kref_demo_Server thiz, server_kref_demo_Session session, const char* a, const char* b);
|
||||||
|
server_KInt (*add)(server_kref_demo_Server thiz, server_kref_demo_Session session, server_KInt a, server_KInt b);
|
||||||
|
} Server;
|
||||||
|
} demo;
|
||||||
|
} kotlin;
|
||||||
|
} server_ExportedSymbols;
|
||||||
|
extern server_ExportedSymbols* server_symbols(void);
|
||||||
|
```
|
||||||
|
|
||||||
|
So every class instance is represented with a single element structure, encapsulating stable pointer to an instance.
|
||||||
|
Once no longer needed, `DisposeStablePointer()` with that stable pointer shall be called, and if value is not stored
|
||||||
|
somewhere else - it is disposed. For primitive types and `kotlin.String` smart bridges converting to C primitive types
|
||||||
|
or to C strings (which has to be manually freed with `DisposeString()`) are implemented.
|
||||||
|
|
||||||
|
For example, running constructor of class Server taking a string will look like
|
||||||
|
|
||||||
|
server_kref_demo_Server server = server_symbols()->kotlin.demo.Server.Server("the server");
|
||||||
|
|
||||||
|
And disposing no longer needed instance will look like
|
||||||
|
|
||||||
|
server_symbols()->DisposeStablePointer(server.pinned);
|
||||||
|
|
||||||
|
To make code easier readable, macro definitions like
|
||||||
|
|
||||||
|
#define T_(name) server_kref_demo_ ## name
|
||||||
|
#define __ server_symbols()->
|
||||||
|
|
||||||
|
will transform above, overly verbose lines to more readable
|
||||||
|
|
||||||
|
T_(Server) server = __ kotlin.demo.Server.Server("the server");
|
||||||
|
|
||||||
|
`_type()` function will return opaque type pointer, which could be checked with `IsInstance()` operation, like
|
||||||
|
|
||||||
|
__ IsInstance(ref.pinned, __ kotlin.demo.Server._type())
|
||||||
Executable
+10
@@ -0,0 +1,10 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
|
||||||
|
DIR=$(cd "$(dirname "${BASH_SOURCE[0]}" )" && pwd )
|
||||||
|
|
||||||
|
source "$DIR/../konan.sh"
|
||||||
|
|
||||||
|
PYTHON=python
|
||||||
|
|
||||||
|
konanc -p dynamic src/main/kotlin/Server.kt -o server
|
||||||
|
sudo $PYTHON src/main/python/setup.py install
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <Python.h>
|
||||||
|
|
||||||
|
#include "server_api.h"
|
||||||
|
|
||||||
|
#define __ server_symbols()->
|
||||||
|
#define T_(name) server_kref_demo_ ## name
|
||||||
|
|
||||||
|
// Note, that as we cache this in the global, and Kotlin/Native object references
|
||||||
|
// are currently thread local, we make this global a TLS variable.
|
||||||
|
__thread static server_kref_demo_Server server = { 0 };
|
||||||
|
|
||||||
|
static T_(Server) getServer() {
|
||||||
|
if (!server.pinned) {
|
||||||
|
server = __ kotlin.demo.Server.Server("the server");
|
||||||
|
}
|
||||||
|
return server;
|
||||||
|
}
|
||||||
|
|
||||||
|
static server_kref_demo_Session getSession(PyObject* args) {
|
||||||
|
T_(Session) result = { 0 };
|
||||||
|
long long pinned;
|
||||||
|
if (PyArg_ParseTuple(args, "L", &pinned)) {
|
||||||
|
result.pinned = (void*)(uintptr_t)pinned;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject* open_session(PyObject* self, PyObject* args) {
|
||||||
|
PyObject *result = NULL;
|
||||||
|
char* string_arg = NULL;
|
||||||
|
int int_arg = 0;
|
||||||
|
if (PyArg_ParseTuple(args, "is", &int_arg, &string_arg)) {
|
||||||
|
server_kref_demo_Session session = __ kotlin.demo.Session.Session(string_arg, int_arg);
|
||||||
|
result = Py_BuildValue("L", session.pinned);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject* close_session(PyObject* self, PyObject* args) {
|
||||||
|
T_(Session) session = getSession(args);
|
||||||
|
__ DisposeStablePointer(session.pinned);
|
||||||
|
__ DisposeStablePointer(getServer().pinned);
|
||||||
|
server.pinned = 0;
|
||||||
|
return Py_BuildValue("L", 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject* greet_server(PyObject* self, PyObject* args) {
|
||||||
|
T_(Server) server = getServer();
|
||||||
|
T_(Session) session = getSession(args);
|
||||||
|
const char* string = __ kotlin.demo.Server.greet(server, session);
|
||||||
|
PyObject* result = Py_BuildValue("s", string);
|
||||||
|
__ DisposeString(string);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject* concat_server(PyObject* self, PyObject* args) {
|
||||||
|
long long session_arg;
|
||||||
|
char* string_arg1 = NULL;
|
||||||
|
char* string_arg2 = NULL;
|
||||||
|
PyObject* result = NULL;
|
||||||
|
|
||||||
|
if (PyArg_ParseTuple(args, "Lss", &session_arg, &string_arg1, &string_arg2)) {
|
||||||
|
T_(Server) server = getServer();
|
||||||
|
T_(Session) session = { (void*)(uintptr_t)session_arg };
|
||||||
|
const char* string = __ kotlin.demo.Server.concat(server, session, string_arg1, string_arg2);
|
||||||
|
result = Py_BuildValue("s", string);
|
||||||
|
__ DisposeString(string);
|
||||||
|
} else {
|
||||||
|
result = Py_BuildValue("s", NULL);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyObject* add_server(PyObject* self, PyObject* args) {
|
||||||
|
long long session_arg;
|
||||||
|
int int_arg1 = 0;
|
||||||
|
int int_arg2 = 0;
|
||||||
|
PyObject* result = NULL;
|
||||||
|
|
||||||
|
if (PyArg_ParseTuple(args, "Lii", &session_arg, &int_arg1, &int_arg2)) {
|
||||||
|
T_(Server) server = getServer();
|
||||||
|
T_(Session) session = { (void*)(uintptr_t)session_arg };
|
||||||
|
int sum = __ kotlin.demo.Server.add(server, session, int_arg1, int_arg2);
|
||||||
|
result = Py_BuildValue("i", sum);
|
||||||
|
} else {
|
||||||
|
result = Py_BuildValue("i", 0);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static PyMethodDef kotlin_bridge_funcs[] = {
|
||||||
|
{ "open_session", (PyCFunction)open_session, METH_VARARGS, "Opens a session" },
|
||||||
|
{ "close_session", (PyCFunction)close_session, METH_VARARGS, "Closes the session" },
|
||||||
|
{ "greet_server", (PyCFunction)greet_server, METH_VARARGS, "Greeting service" },
|
||||||
|
{ "concat_server", (PyCFunction)concat_server, METH_VARARGS, "Concatenation service" },
|
||||||
|
{ "add_server", (PyCFunction)add_server, METH_VARARGS, "Addition service" },
|
||||||
|
{ NULL }
|
||||||
|
};
|
||||||
|
|
||||||
|
void initkotlin_bridge(void) {
|
||||||
|
Py_InitModule3("kotlin_bridge", kotlin_bridge_funcs, "Kotlin/Native example module");
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package demo
|
||||||
|
|
||||||
|
class Session(val name: String, val number: Int)
|
||||||
|
|
||||||
|
class Server(val prefix: String) {
|
||||||
|
fun greet(session: Session) = "$prefix: Hello from Kotlin/Native in ${session}"
|
||||||
|
fun concat(session: Session, a: String, b: String) = "$prefix: $a $b in ${session}"
|
||||||
|
fun add(session: Session, a: Int, b: Int) = a + b + session.number
|
||||||
|
}
|
||||||
@@ -0,0 +1,32 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
import kotlin_bridge
|
||||||
|
|
||||||
|
session = kotlin_bridge.open_session(239, 'konan')
|
||||||
|
|
||||||
|
message = kotlin_bridge.greet_server(session)
|
||||||
|
print "Greet '%s'" % (message)
|
||||||
|
|
||||||
|
message = kotlin_bridge.concat_server(session, "Coding", "fun")
|
||||||
|
print "Concat '%s'" % (message)
|
||||||
|
|
||||||
|
message = kotlin_bridge.add_server(session, 1, 60)
|
||||||
|
print "Sum '%d'" % (message)
|
||||||
|
|
||||||
|
|
||||||
|
kotlin_bridge.close_session(session)
|
||||||
|
|
||||||
@@ -0,0 +1,44 @@
|
|||||||
|
#!/usr/bin/python
|
||||||
|
#
|
||||||
|
# Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
#
|
||||||
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
# you may not use this file except in compliance with the License.
|
||||||
|
# You may obtain a copy of the License at
|
||||||
|
#
|
||||||
|
# http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
#
|
||||||
|
# Unless required by applicable law or agreed to in writing, software
|
||||||
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
# See the License for the specific language governing permissions and
|
||||||
|
# limitations under the License.
|
||||||
|
#
|
||||||
|
from distutils.core import setup, Extension
|
||||||
|
|
||||||
|
setup(name='kotlin_bridge',
|
||||||
|
version='1.0',
|
||||||
|
maintainer = 'JetBrains',
|
||||||
|
maintainer_email = 'info@jetbrains.com',
|
||||||
|
author = 'JetBrains',
|
||||||
|
author_email = 'info@jetbrains.com',
|
||||||
|
description = 'Kotlin/Native Python bridge',
|
||||||
|
long_description = 'Using Kotlin/Native from Python example',
|
||||||
|
|
||||||
|
# data_files=[("/Library/Python/2.7/site-packages/", ['libserver.dylib'])],
|
||||||
|
|
||||||
|
ext_modules=[
|
||||||
|
Extension('kotlin_bridge',
|
||||||
|
include_dirs = ['.'],
|
||||||
|
libraries = ['server'],
|
||||||
|
library_dirs = ['.'],
|
||||||
|
depends = ['server_api.h'],
|
||||||
|
sources = ['src/main/c/kotlin_bridge.c']
|
||||||
|
)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
|
||||||
|
# On macOS, after install you may want to copy libserver.dylib to Python's extension directory,
|
||||||
|
# and do something like
|
||||||
|
# sudo install_name_tool /Library/Python/2.7/site-packages/kotlin_bridge.so -change libserver.dylib @loader_path/libserver.dylib
|
||||||
|
# This way libserver.dylib could be loaded from extension's directory.
|
||||||
@@ -5,6 +5,7 @@ include ':gtk'
|
|||||||
include ':libcurl'
|
include ':libcurl'
|
||||||
include ':nonBlockingEchoServer'
|
include ':nonBlockingEchoServer'
|
||||||
include ':opengl'
|
include ':opengl'
|
||||||
|
include ':python_extension'
|
||||||
include ':socket'
|
include ':socket'
|
||||||
include ':tetris'
|
include ':tetris'
|
||||||
include ':tensorflow'
|
include ':tensorflow'
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ enum class CompilerOutputKind {
|
|||||||
},
|
},
|
||||||
DYNAMIC {
|
DYNAMIC {
|
||||||
override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}"
|
override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}"
|
||||||
override fun prefix(target: KonanTarget?) = ".${target!!.family.dynamicPrefix}"
|
override fun prefix(target: KonanTarget?) = "${target!!.family.dynamicPrefix}"
|
||||||
},
|
},
|
||||||
FRAMEWORK {
|
FRAMEWORK {
|
||||||
override fun suffix(target: KonanTarget?): String = ".framework"
|
override fun suffix(target: KonanTarget?): String = ".framework"
|
||||||
|
|||||||
Reference in New Issue
Block a user