在进行kotlin-native开发时,由于当前版本缺少很多库,所以我们需要使用C/C++进行补充。本文将以linux平台为例,介绍如何在kotlin-native中使用C/C++。
- idea-community
- jdk17
- cmake
- linux
Interoperability with C
Create an app using C Interop and libcurl – tutorial
selcarpa/c_link_demo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
| └── c_link_demo
├── c_link_demo_c
│ ├── CMakeLists.txt
│ ├── library.c
│ └── library.h
└── c_link_demo_kt
├── build.gradle.kts
├── gradle
│ └── wrapper
│ ├── gradle-wrapper.jar
│ └── gradle-wrapper.properties
├── gradle.properties
├── gradlew
├── gradlew.bat
├── settings.gradle.kts
└── src
├── commonMain
│ ├── kotlin
│ │ └── Main.kt
│ └── resources
└── nativeInterop
└── cinterop
└── c_lib_demo.def
|
此处以C库为例
在c_link_demo_c目录下创建library.c和library.h文件,文件分别声明和实现一个hello函数。
library.h
1
2
3
4
5
6
| #ifndef C_LIB_DEMO_LIBRARY_H
#define C_LIB_DEMO_LIBRARY_H
void hello(void);
#endif //C_LIB_DEMO_LIBRARY_H
|
library.c
1
2
3
4
5
6
7
| #include "library.h"
#include <stdio.h>
void hello(void) {
printf("Hello, World!\n");
}
|
创建CMakeLists.txt文件,作用是将C库编译成静态库,内容如下:
1
2
3
4
5
6
| cmake_minimum_required(VERSION 3.27)
project(c_link_demo_c C)
set(CMAKE_C_STANDARD 11)
add_library(c_link_demo_c STATIC library.c)
|
使用idea创建普通的kotlin(gradle)项目,然后打开项目根目录下的build.gradle.kts文件,更改为以下内容:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
| import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
//使用kotlin-multiplatform插件,用以创建native项目
plugins {
kotlin("multiplatform") version "1.9.21"
}
//包名版本号
group = "one.tain"
version = "1.0-SNAPSHOT"
repositories {
mavenCentral()
google()
}
//kotlin插件
kotlin {
//指定main函数入口
fun KotlinNativeTarget.config() {
binaries {
executable {
entryPoint = "main"
}
}
}
//指定平台
linuxX64("linuxX64") {
config()
}
}
|
可以关注到当前创建了一个kotlin-native的项目,进行一次构建后,会发现idea不会识别main目录下的kotlin文件,native项目的默认源码和资源目录是src/nativeMain/kotlin和src/nativeMain/resources,所以我们需要更改一下项目结构。
在项目根目录下创建src/commonMain/kotlin目录,将main目录下的kotlin文件移动到commonMain目录下,在commonMain目录下创建resources目录,删除main目录。
然后可以调试kotlin原生应用。但是此处并没有进行C的交互链接,后续的步骤会进行C交互的补充。
在项目根目录下创建nativeInterop/cinterop/c_lib_demo.def文件,内容如下:
1
2
3
4
5
6
| # 指定头文件的绝对路径
headers = /home/sel/repository/selcarpa/c_link_demo/c_link_demo_c/library.h
# 指定库文件的名称
staticLibraries = libc_link_demo_c.a
# 指定库文件的绝对路径
libraryPaths = /home/sel/repository/selcarpa/c_link_demo/c_link_demo_c/cmake-build-debug
|
在项目根目录下的build.gradle.kts文件中的linuxX64方法下,添加以下内容:
1
2
3
| compilations["main"].cinterops {
@Suppress("LocalVariableName") val c_lib_demo by creating
}
|
点击构建按钮,在idea的External Libraries中可以看到c_lib_demo的库文件已经被加载进来了。
在commonMain目录下的main.kt文件中调用C函数,内容如下:
1
2
3
4
5
6
7
| import c_lib_demo.hello
import kotlinx.cinterop.ExperimentalForeignApi
@OptIn(ExperimentalForeignApi::class)
fun main(args: Array<String>) {
hello()
}
|
输出结果如下:
c_lib_demo.def还有其他的配置方法,例:
1
2
3
4
5
6
| # 指定头文件的名称
headers = library.h
# 指定编译的include行为,从而指定头文件的搜索路径
compilerOpts.linux = -I/home/sel/repository/selcarpa/c_link_demo/c_link_demo_c
# 指定链接的行为,从而指定库文件的搜索路径和库文件的名称
linkerOpts.linux = -L/home/sel/repository/selcarpa/c_link_demo/c_link_demo_c/cmake-build-debug -lc_link_demo_c
|
这种方式更方便地指定不同平台的行为