美文网首页
Kotlin Navtive Dynamic Libraries

Kotlin Navtive Dynamic Libraries

作者: 我有的似乎只能是等待等待 | 来源:发表于2018-12-07 17:40 被阅读0次

    上一篇主要说了如果通过编写Kotlin代码编译成各个平台的可执行文件,这一篇介绍如何通过Kotlin Native编译成各平台的动态或者静态库,以供其他语言去调用。当然,Kotlin也可以调用C语言编写的静态库,或者直接引用C语言代码。

    官网地址 kotlin navtive dynamic libraries

    1. 首先让我们编写一个lib.kt文件:

    object Object {
    
        val field = "A"
    
    }
    
    class Clazz {
    
        fun memberFunction(p: Int): Long = 42L
    
    }
    
    fun forIntegers(b: Byte, s: Short, i: Int, l: Long) { }
    
    fun forFloats(f: Float, d: Double) { }
    
    //自己添加的方法
    
    fun add(a: Int, b: Int): Int {
    
        return a + b
    
    }
    
    fun sub(a: Int, b: Int): Int {
    
        return a - b
    
    }
    
    fun strings(str: String) : String? {
    
        return "That is '$str' from C"
    
    }
    
    val globalString = "A global String"
    

    当然这段代码是摘自官网教程,只不过我增加了自己写的add和sub方法。
    然后只需要在lib.kt所在的文件夹下敲入以下命令:

    kotlinc-native lib.kt -produce dynamic -output demo
    

    这样就可生成对应的动态库文件,当然在不同的平台下生成的文件不同,如下:
    The kotlinc-native (with v0.9.2) generates the following files, depending on the host OS:

    1. macOS: demo_api.h and libdemo.dylib
    2. Linux: demo_api.h and libdemo.so
    3. Windows: demo_api.h, demo_symbols.def and demo.dll

    如下图,执行完刚才的命令就可以得到如下的文件,由于我是在linux平台下编译的,所以会生成 demo_api.h的C语言的头文件和一个so动态库。


    生成的文件

    这样就可以在linux平台下面去使用这个动态库,下面是在linux上使用eclipse创建的C语言工程去调用刚才生成的动态库,首先你先要有一个eclipse,这里就不再附赘,这里主要想说一下如何去调用刚才的动态库。

    2. 调用kotlin生成的动态库

    1. 在C Compiler选项下的includes选项下的include paths增加刚才编译好的动态库的文件夹路径:


      添加动态库路径
      动态库所在目录
    2. 这里只是把头文件加入了编译,还需要把so库引用加入,继续设置, 在C Linker 的 Miscellaneous的 Other objects下增加对libdemo.so库的引用:
    so库引用添加

    至此动态库的引用已经添加完毕,我们现在就可以在C代码里调用刚才用kotlin提供的方法了,但是在这个之前,我们还是看一看demo_api.h这个头文件里面都有哪些东西:

    #ifndef KONAN_DEMO_H
    #define KONAN_DEMO_H
    #ifdef __cplusplus
    extern "C" {
    #endif
    #ifdef __cplusplus
    typedef bool            demo_KBoolean;
    #else
    typedef _Bool          demo_KBoolean;
    #endif
    typedef unsigned short    demo_KChar;
    typedef signed char        demo_KByte;
    typedef short              demo_KShort;
    typedef int                demo_KInt;
    typedef long long          demo_KLong;
    typedef unsigned char      demo_KUByte;
    typedef unsigned short    demo_KUShort;
    typedef unsigned int      demo_KUInt;
    typedef unsigned long long demo_KULong;
    typedef float              demo_KFloat;
    typedef double            demo_KDouble;
    typedef void*              demo_KNativePtr;
    struct demo_KType;
    typedef struct demo_KType demo_KType;
    
    typedef struct {
      demo_KNativePtr pinned;
    } demo_kref_Object;
    
    typedef struct {
      demo_KNativePtr pinned;
    } demo_kref_Clazz;
    
    typedef struct {
    
      /* Service functions. */
      void (*DisposeStablePointer)(demo_KNativePtr ptr);
      void (*DisposeString)(const char* string);
      demo_KBoolean (*IsInstance)(demo_KNativePtr ref, const demo_KType* type);
    
      /* User functions. */
    
      struct {
        struct {
          void (*forIntegers)(demo_KByte b, demo_KShort s, demo_KInt i, demo_KLong l);
          void (*forFloats)(demo_KFloat f, demo_KDouble d);
          demo_KInt (*add)(demo_KInt a, demo_KInt b);
          demo_KInt (*sub)(demo_KInt a, demo_KInt b);
          const char* (*strings)(const char* str);
          const char* (*get_globalString)();
    
          struct {
            demo_KType* (*_type)(void);
            demo_kref_Object (*_instance)();
            const char* (*get_field)(demo_kref_Object thiz);
          } Object;
    
          struct {
            demo_KType* (*_type)(void);
            demo_kref_Clazz (*Clazz)();
            demo_KLong (*memberFunction)(demo_kref_Clazz thiz, demo_KInt p);
          } Clazz;
        } root;
      } kotlin;
    } demo_ExportedSymbols;
    extern demo_ExportedSymbols* demo_symbols(void);
    #ifdef __cplusplus
    }  /* extern "C" */
    #endif
    #endif  /* KONAN_DEMO_H */
    

    因为在C语言中没有对象的概念,所以kotlin生成的方法都是以结构体的形式存在的,我们可以看到刚才在生成头文件的时候是以demo开头的,所以头文件里面的命名都是demo开头的,并且C语言也没有包的概念,如果一个函数同名,那就无法区分,所以就以加前缀的方式来区分。

    更具体的分析我们可以查阅官网资料,下面我们来看如果调用这些方法:

    demo_ExportedSymbols* lib = demo_symbols();
    
    //use C and Kotlin/Native strings
    const char* str = "Hello from Native!";
    const char* response = lib->kotlin.root.strings(str);
    printf("in: %s\nout:%s\n", str, response);
    lib->DisposeString(response);
    
    printf("调用kotlin的add 方法 %d\n", lib->kotlin.root.add(2, 1));
    printf("调用kotlin的sub 方法 %d\n", lib->kotlin.root.sub(1, 2));
    

    我们分析头文件可以看出如果我们想要调用刚才kotlin编写的方法,我们必须先创建demo_ExportedSymbols这个结构体,所以我们就先创建出来:

    demo_ExportedSymbols* lib = demo_symbols();
    

    然后我们尝试调用 strings这个方法:

    //use C and Kotlin/Native strings
    const char* str = "Hello from Native!";
    const char* response = lib->kotlin.root.strings(str);
    printf("in: %s\nout:%s\n", str, response);
    lib->DisposeString(response);
    

    当然使用完是要释放掉这个内存的。
    然后我们尝试调用add 和 sub方法:

    printf("调用kotlin的add 方法 %d\n", lib->kotlin.root.add(2, 1));
    printf("调用kotlin的sub 方法 %d\n", lib->kotlin.root.sub(1, 2));
    

    我们看一下运行结果:


    运行结果

    仔细看还会发现在lib.kt里面还定义了类,在C中都会被翻译成结构体。
    以上就是参照官网教程实现的简单的使用kotlin native实现编程成为动态库,供C代码调用的过程。

    相关文章

      网友评论

          本文标题:Kotlin Navtive Dynamic Libraries

          本文链接:https://www.haomeiwen.com/subject/rmcxhqtx.html