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

相关推荐
酷炫码神13 分钟前
C#语法基础
开发语言·c#
ddd...e_bug13 分钟前
GMT之Bash语言使用
开发语言·bash
码农秋16 分钟前
填坑记: 古董项目Apache POI 依赖异常排除
开发语言·tomcat·jsp·poi·依赖冲突
qq_6536444617 分钟前
如何查看打开的 git bash 窗口是否是管理员权限打开
开发语言·windows·git·bash
sadoshi18 分钟前
phpstudy的Apache添加AddType application/x-httpd-php .php .php5配置无效的处理方式
开发语言·php·apache
阑梦清川35 分钟前
关于Go语言的开发环境的搭建
开发语言·后端·golang
言之。40 分钟前
Makefile 在 Go 项目中的实践
开发语言·elasticsearch·golang
Nobkins42 分钟前
2023CCPC河南省赛暨河南邀请赛个人补题ABEFGHK
开发语言·数据结构·c++·算法·图论
南部余额1 小时前
Python 类变量与实例变量完全指南:区别、使用场景及常见陷阱
开发语言·python
珊瑚里的鱼1 小时前
第九讲 | 模板进阶
开发语言·c++·笔记·visualstudio·学习方法·visual studio