本文測試環境為ubuntu,沒有使用IDE;從基本層面了解kotlin native環境中,C和kotlin的編譯,互相調用。
1. kotlin 動態庫
1.1 動態庫編譯
源碼文件libktest.kt:
//file name:libktest.kt
@OptIn(kotlin.experimental.ExperimentalNativeApi::class)
@CName("testk") // 指定 C 函數名
fun testk() {println("Hello, Kotlin!") // 打印并換行
}
執行如下命令:?
kotlinc-native libktest.kt -produce dynamic -o libktest
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/bashkotlinc-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主程序代碼
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模塊的前提條件
headers = libktest_api.h
headerFilter = libktest_api.h
package = ktestcompilerOpts.linux = -I.
linkerOpts.linux = -L./ -lktest
?關于def文件的配置可以參考:
定義文件 | Kotlin 語言參考文檔 中文版
?執行如下命令生成綁定:
cinterop ?-def ktest.def -o ktest.klib
結果如下:
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程序,終端輸出信息如下:
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
?查看執行結果:
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動態庫的測試。
需要進一步研究的點:
- def文件的binding操作具體做了什么,生成文件的作用
- kotlin native編譯的native可執行程序變大了,那么kotlin的編譯過程中注入信息以及這寫注入的作用
- OptIn的注解作用原理和過程
1.2.2 C 代碼的動態鏈接
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動態庫