基于kotlin native的C与kotlin互相调用

本文测试环境为ubuntu,没有使用IDE;从基本层面了解kotlin native环境中,C和kotlin的编译,互相调用。

1. kotlin 动态库

1.1 动态库编译

源码文件libktest.kt:

Kotlin 复制代码
//file name:libktest.kt
@OptIn(kotlin.experimental.ExperimentalNativeApi::class)
@CName("testk")  // 指定 C 函数名
fun testk() {
    println("Hello, Kotlin!")  // 打印并换行
}

执行如下命令:

bash 复制代码
kotlinc-native libktest.kt -produce dynamic -o libktest
bash 复制代码
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ cat libktest.kt 

@OptIn(kotlin.experimental.ExperimentalNativeApi::class)
@CName("testk")  // 指定 C 函数名
fun testk() {
    println("Hello, Kotlin!")  // 打印并换行
}
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ cat build.sh 
#!/bin/bash

kotlinc-native libktest.kt -produce dynamic -o libktest

#执行shell命令
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ./build.sh 

#获取的结果
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ls -lt
总用量 888
-rwxr-xr-x 1 liucx liucx 892544 4月   2 15:14 libktest.so
-rw-r--r-- 1 liucx liucx   4154 4月   2 15:14 libktest_api.h
-rwxr-xr-x 1 liucx liucx     69 4月   2 15:13 build.sh
-rw-r--r-- 1 liucx liucx    163 4月   2 15:13 libktest.kt
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ 

执行shell脚步后获取libktest_api.h和libktest.so,so文件是linux平台可以直接link的调用的的动态库,h文件是生成的头文件

与c代码编译的动态库比较,kotlin的动态库文件比C代码编译的动态库文件大很多,so文件除了包含testk函数外,还额外包含了很多其他信息。看起来是kotlin相关的一些信息,暂时还未研究这些信息,应该是kotlinc-native编译native动态库时做的特别处理。因此看来在客户端瘦身时,这里为考虑点。

1.2 kotlin so文件的动态链接调用

1.2.1 kotlin 代码的动态链接

main.kt主程序代码

Kotlin 复制代码
import ktest.*           // 导入生成的绑定
import kotlinx.cinterop.*

@OptIn(kotlinx.cinterop.ExperimentalForeignApi::class)
fun main() {
    testk()
    //println("3 + 5 = ${add(3, 5)}")          // 调用 C 函数
    //println("sqrt(9.0) = ${sqrtf(9.0f)}")    // 注意类型匹配(Float)
}

创建ktest.def文件,描述需要绑定(binding)的内容, kotlin代码调用native模块的前提条件

bash 复制代码
headers = libktest_api.h
headerFilter = libktest_api.h
package = ktest

compilerOpts.linux = -I.
linkerOpts.linux = -L./ -lktest

关于def文件的配置可以参考:

定义文件 | Kotlin 语言参考文档 中文版

执行如下命令生成绑定:

bash 复制代码
cinterop  -def ktest.def -o ktest.klib

结果如下:

bash 复制代码
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ls -lt
总用量 892
-rw-r--r-- 1 liucx liucx    129 4月   2 15:35 ktest.def
-rwxr-xr-x 1 liucx liucx 892544 4月   2 15:14 libktest.so
-rw-r--r-- 1 liucx liucx   4154 4月   2 15:14 libktest_api.h
-rwxr-xr-x 1 liucx liucx     69 4月   2 15:13 build.sh
-rw-r--r-- 1 liucx liucx    163 4月   2 15:13 libktest.kt
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ cinterop  -def ktest.def -o ktest.klib
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ls -lt
总用量 904
-rw-r--r-- 1 liucx liucx   7694 4月   2 15:35 ktest.klib
drwxr-xr-x 3 liucx liucx   4096 4月   2 15:35 ktest.klib-build
-rw-r--r-- 1 liucx liucx    129 4月   2 15:35 ktest.def
-rwxr-xr-x 1 liucx liucx 892544 4月   2 15:14 libktest.so
-rw-r--r-- 1 liucx liucx   4154 4月   2 15:14 libktest_api.h
-rwxr-xr-x 1 liucx liucx     69 4月   2 15:13 build.sh
-rw-r--r-- 1 liucx liucx    163 4月   2 15:13 libktest.kt
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ 

生成ktest.klib 和ktest.klib-build.

编译main.kt,获取maink程序,终端输出信息如下:

bash 复制代码
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ls -lt
总用量 908
-rw-r--r-- 1 liucx liucx    305 4月   2 15:37 main.kt
-rw-r--r-- 1 liucx liucx   7694 4月   2 15:35 ktest.klib
drwxr-xr-x 3 liucx liucx   4096 4月   2 15:35 ktest.klib-build
-rw-r--r-- 1 liucx liucx    129 4月   2 15:35 ktest.def
-rwxr-xr-x 1 liucx liucx 892544 4月   2 15:14 libktest.so
-rw-r--r-- 1 liucx liucx   4154 4月   2 15:14 libktest_api.h
-rwxr-xr-x 1 liucx liucx     69 4月   2 15:13 build.sh
-rw-r--r-- 1 liucx liucx    163 4月   2 15:13 libktest.kt
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ kotlinc-native main.kt -library ktest.klib  -o maink
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ls -lt
总用量 1384
-rwxr-xr-x 1 liucx liucx 485224 4月   2 15:37 maink.kexe
-rw-r--r-- 1 liucx liucx    305 4月   2 15:37 main.kt
-rw-r--r-- 1 liucx liucx   7694 4月   2 15:35 ktest.klib
drwxr-xr-x 3 liucx liucx   4096 4月   2 15:35 ktest.klib-build
-rw-r--r-- 1 liucx liucx    129 4月   2 15:35 ktest.def
-rwxr-xr-x 1 liucx liucx 892544 4月   2 15:14 libktest.so
-rw-r--r-- 1 liucx liucx   4154 4月   2 15:14 libktest_api.h
-rwxr-xr-x 1 liucx liucx     69 4月   2 15:13 build.sh
-rw-r--r-- 1 liucx liucx    163 4月   2 15:13 libktest.kt

查看执行结果:

bash 复制代码
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ export LD_LIBRARY_PATH=./:$LD_LIBRARY_PATH
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ./maink.kexe 
Hello, Kotlin!

ps:动态库的路径需要手动临时配置下。

至此完成了kotlin调用native动态库的测试。

需要进一步研究的点:

  1. def文件的binding操作具体做了什么,生成文件的作用
  2. kotlin native编译的native可执行程序变大了,那么kotlin的编译过程中注入信息以及这写注入的作用
  3. OptIn的注解作用原理和过程

1.2.2 C 代码的动态链接

bash 复制代码
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ cat main.c 

#include "libktest_api.h"
void main() {
    testk();
}
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ls -lt
总用量 1388
-rw-r--r-- 1 liucx liucx     56 4月   2 15:48 main.c
-rwxr-xr-x 1 liucx liucx 485224 4月   2 15:37 maink.kexe
-rw-r--r-- 1 liucx liucx    305 4月   2 15:37 main.kt
-rw-r--r-- 1 liucx liucx   7694 4月   2 15:35 ktest.klib
drwxr-xr-x 3 liucx liucx   4096 4月   2 15:35 ktest.klib-build
-rw-r--r-- 1 liucx liucx    129 4月   2 15:35 ktest.def
-rwxr-xr-x 1 liucx liucx 892544 4月   2 15:14 libktest.so
-rw-r--r-- 1 liucx liucx   4154 4月   2 15:14 libktest_api.h
-rwxr-xr-x 1 liucx liucx     69 4月   2 15:13 build.sh
-rw-r--r-- 1 liucx liucx    163 4月   2 15:13 libktest.kt
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ gcc main.c -o cmain.exe -L. -lktest -Wl,-rpath=./
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ls -lt
总用量 1400
-rwxr-xr-x 1 liucx liucx   8288 4月   2 15:48 cmain.exe
-rw-r--r-- 1 liucx liucx     56 4月   2 15:48 main.c
-rwxr-xr-x 1 liucx liucx 485224 4月   2 15:37 maink.kexe
-rw-r--r-- 1 liucx liucx    305 4月   2 15:37 main.kt
-rw-r--r-- 1 liucx liucx   7694 4月   2 15:35 ktest.klib
drwxr-xr-x 3 liucx liucx   4096 4月   2 15:35 ktest.klib-build
-rw-r--r-- 1 liucx liucx    129 4月   2 15:35 ktest.def
-rwxr-xr-x 1 liucx liucx 892544 4月   2 15:14 libktest.so
-rw-r--r-- 1 liucx liucx   4154 4月   2 15:14 libktest_api.h
-rwxr-xr-x 1 liucx liucx     69 4月   2 15:13 build.sh
-rw-r--r-- 1 liucx liucx    163 4月   2 15:13 libktest.kt
liucx@liucx-QiTianM428-N000:~/Documents/kotlin_demo/lib_file/k_lib/debug$ ./cmain.exe 
Hello, Kotlin!

main.c为C代码和cmain.exe为编译的可执行程序。

C代码调用kotlin native编译的动态库很方便,直接包含头文件,链接对应动态库即可。

由此看来,kotlin-native本身生成的native动态库,被native使用时很方便,基本和native使用方式一致。需要考虑的是kotlin编写的native动态库主要需要考虑接口设计时的参数传递。

kotlin调用native动态库时,需要额外的处理生成klib形式的中间文件,以供kotlin-native编译kt文件时使用。kotlin-native编译kt需要klib的中间文件, 仅仅用于编译,最终的可执行程序运行时只依赖于so动态库

相关推荐
Python×CATIA工业智造34 分钟前
Frida RPC高级应用:动态模拟执行Android so文件实战指南
开发语言·python·pycharm
我叫小白菜2 小时前
【Java_EE】单例模式、阻塞队列、线程池、定时器
java·开发语言
狐凄2 小时前
Python实例题:基于 Python 的简单聊天机器人
开发语言·python
weixin_446122463 小时前
JAVA内存区域划分
java·开发语言·redis
悦悦子a啊3 小时前
Python之--基本知识
开发语言·前端·python
QuantumStack4 小时前
【C++ 真题】P1104 生日
开发语言·c++·算法
whoarethenext4 小时前
使用 C++/OpenCV 和 MFCC 构建双重认证智能门禁系统
开发语言·c++·opencv·mfcc
代码的奴隶(艾伦·耶格尔)5 小时前
后端快捷代码
java·开发语言
Jay_5155 小时前
C++多态与虚函数详解:从入门到精通
开发语言·c++
路来了5 小时前
Python小工具之PDF合并
开发语言·windows·python