基于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动态库

相关推荐
AC赳赳老秦1 小时前
公开音频转写信息提取:OpenClaw 处理发布会与听证会文本并提取核心决策信息
大数据·开发语言·汇编·数据库·人工智能·deepseek·openclaw
@yanyu6662 小时前
C编译器安装与第一个C程序
c语言·开发语言
落魄实习生2 小时前
Agent Scope Java 2.x 系列【2】 ReActAgent
java·开发语言
智鸟科技GemeOpen开发者智能设备2 小时前
智能插座二次开发如何接入Home Assistant,从零开始完整工程实现(Python+React)
开发语言·python·物联网·react.js·智能家居
疯狂成瘾者2 小时前
海康 Artemis 接口对接
开发语言·lua
2601_962218612 小时前
C++中decltype关键字的实现
开发语言·c++
hqyjzsb2 小时前
法律 Prompt 干货:搭建合同审查提示词要包含哪些要素
开发语言·人工智能·python·职场和发展·数据分析·prompt·业界资讯
孙启超2 小时前
【AI开发之Rust】第 19 课:UniFFI 导出核心能力
开发语言·后端·rust
2601_966949653 小时前
股票池发生变化后,如何高效更新行情数据?从全量刷新到增量同步
开发语言·python·数据分析·pandas·量化交易·股票数据·quantdash
繁华的地方不一定留下你的脚印3 小时前
C++ std::variant 与 std::visit:安全保存多种类型,写清每个处理分支
开发语言·c++