cinterop 工具详解Beta
源:Interoperability with C - Kotlin/Native
cinterop 是 Kotlin/Native 的核心工具,负责生成 C/Objective-C 库的 Kotlin 绑定。深入理解 cinterop 能够充分利用 Native 生态。
工作原理
处理流程
C 头文件 (.h)
↓
定义文件 (.def) ← 配置项
↓
cinterop 工具
↓
Kotlin 绑定 (.klib)
↓
Kotlin 代码导入使用生成的绑定
cinterop 为 C 声明生成对应的 Kotlin API:
| C 声明 | Kotlin 绑定 |
|---|---|
| 函数 | 顶层函数 |
| 结构体 | CPointed 子类 |
| 枚举 | Kotlin 枚举或常量 |
| 宏常量 | Kotlin 常量 |
| typedef | 类型别名 |
def 文件配置
核心属性
properties
# mylib.def
# 要处理的头文件(空格分隔)
headers = mylib.h utils.h
# 过滤器:只导入匹配的头文件
headerFilter = mylib.h
# 生成的 Kotlin 包名
package = mylib
# 源语言(C 或 Objective-C)
language = Cproperties
# 编译器选项
compilerOpts = -I/usr/include
compilerOpts.linux = -I/usr/include/x86_64-linux-gnu
compilerOpts.osx = -I/usr/local/include
compilerOpts.mingw = -IC:/msys64/mingw64/include
# 链接器选项
linkerOpts = -lm
linkerOpts.linux = -L/usr/lib -lmylib
linkerOpts.osx = -L/usr/local/lib -lmylib
linkerOpts.mingw = -LC:/msys64/mingw64/lib -lmylib高级选项
properties
# mylib.def
# 排除特定函数
excludedFunctions = internal_helper deprecated_api
# 控制枚举生成
strictEnums = Color Mode
nonStrictEnums = ErrorCode
# 禁用字符串自动转换
noStringConversion = get_raw_buffer process_bytes
# 排除头文件
excludeFilter = internal/*.h test/*.h
# 静态库(实验性)
staticLibraries = libstatic.a
libraryPaths = /opt/libs自定义声明
可以在 def 文件中直接添加 C 声明:
properties
# mylib.def
headers = mylib.h
package = mylib
---
// 自定义声明(在 --- 之后)
static inline int square(int x) {
return x * x;
}
#define MY_CONSTANT 42
typedef struct {
int x, y;
} CustomPoint;Gradle 集成
基础配置
kotlin
// build.gradle.kts
kotlin {
linuxX64 {
compilations.getByName("main") {
cinterops {
val mylib by creating {
// 指定 def 文件
defFile(project.file("src/nativeInterop/cinterop/mylib.def"))
// 包名
packageName("mylib")
// 额外的头文件搜索路径
includeDirs.apply {
allHeaders("/usr/include", "/usr/local/include")
}
}
}
}
}
}groovy
// build.gradle
kotlin {
linuxX64 {
compilations.main {
cinterops {
mylib {
defFile file('src/nativeInterop/cinterop/mylib.def')
packageName 'mylib'
includeDirs {
allHeaders '/usr/include', '/usr/local/include'
}
}
}
}
}
}多平台配置
kotlin
// build.gradle.kts
kotlin {
// 定义多个目标
val nativeTargets = listOf(
linuxX64(),
linuxArm64(),
macosX64(),
macosArm64(),
mingwX64()
)
nativeTargets.forEach { target ->
target.compilations.getByName("main") {
cinterops {
val openssl by creating {
defFile("src/nativeInterop/cinterop/openssl.def")
packageName("openssl")
// 平台特定的头文件路径
when (target.name) {
"linuxX64", "linuxArm64" -> {
includeDirs("/usr/include/openssl")
}
"macosX64", "macosArm64" -> {
includeDirs("/usr/local/opt/openssl/include")
}
"mingw X64" -> {
includeDirs("C:/OpenSSL/include")
}
}
}
}
}
}
}类型映射细节
基本类型
cinterop 自动映射 C 基本类型:
kotlin
// C → Kotlin
// char → Byte
// unsigned char → UByte
// short → Short
// unsigned short → UShort
// int → Int
// unsigned int → UInt
// long → Long (平台相关)
// unsigned long → ULong
// long long → Long
// unsigned long long → ULong
// float → Float
// double → Double
// void* → COpaquePointer?函数映射
c
// mylib.h
int add(int a, int b);
void process(const char* data, size_t len);
char* get_string();kotlin
@OptIn(ExperimentalForeignApi::class)
import mylib.*
// int add(int, int)
fun useAdd() {
val result = add(10, 20) // 直接调用
println(result) // 30
}
// void process(const char*, size_t)
fun useProcess() {
"Hello".cstr.use { ptr ->
process(ptr, 5u)
}
}
// char* get_string()
fun useGetString() {
val str = get_string()?.toKString()
println(str)
}结构体映射
c
// C 定义
typedef struct {
int width;
int height;
unsigned char* data;
} Image;
Image* create_image(int w, int h);
void destroy_image(Image* img);kotlin
@OptIn(ExperimentalForeignApi::class)
import kotlinx.cinterop.*
import mylib.*
fun useImage() {
val img = create_image(640, 480)
if (img != null) {
// 访问结构体字段
println("Size: ${img.pointed.width}x${img.pointed.height}")
// 修改字段
img.pointed.data = nativeHeap.allocArray<UByteVar>(640 * 480).reinterpret()
destroy_image(img)
}
}处理复杂场景
回调函数
c
// C 定义
typedef void (*Callback)(int value, void* userdata);
void register_callback(Callback cb, void* userdata);kotlin
@OptIn(ExperimentalForeignApi::class)
import kotlin.native.ref.*
val callback = staticCFunction<Int, COpaquePointer?, Unit> { value, userdata ->
if (userdata != null) {
val handler = userdata.asStableRef<(Int) -> Unit>().get()
handler(value)
}
}
fun setupCallback(handler: (Int) -> Unit) {
val ref = StableRef.create(handler)
register_callback(callback, ref.asCPointer())
}可变参数函数
c
// C 定义
int printf(const char* format, ...);kotlin
// cinterop 不生成可变参数函数的绑定
// 需要手动包装固定参数版本
// 在 def 文件中添加:
// ---
// static inline int my_printf_int(const char* fmt, int value) {
// return printf(fmt, value);
// }宏处理
properties
# mylib.def
---
// 常量宏会自动转换
#define MAX_SIZE 1024
// 函数宏需要转换为 inline 函数
#define SQUARE(x) ((x) * (x))
static inline int square_wrapper(int x) {
return SQUARE(x);
}调试与优化
查看生成的绑定
bash
# 构建后查看生成的 klib
./gradlew linkDebugSharedLinuxX64
# klib 位置
build/classes/kotlin/linuxX64/main/klib/mylib.klib
# 解压查看
unzip mylib.klib -d mylib_contents启用详细日志
kotlin
// build.gradle.kts
kotlin {
targets.withType<KotlinNativeTarget> {
compilations.getByName("main") {
cinterops {
val mylib由 creating {
defFile("mylib.def")
// 启用详细输出
extraOpts("-verbose")
}
}
}
}
}常见问题排查
properties
# ❌ 错误
headers = mylib.h
# 错误:mylib.h: No such file or directory
# ✅ 解决
headers = mylib.h
compilerOpts = -I/path/to/headersproperties
# ❌ 错误
headers = mylib.h
# 链接时:undefined reference to `my_function`
# ✅ 解决
headers = mylib.h
linkerOpts = -L/path/to/lib -lmylibproperties
# ❌ 错误:与系统头文件冲突
# ✅ 解决:使用 headerFilter
headers = mylib.h system.h
headerFilter = mylib.h # 只导入 mylib.h 的符号最佳实践
实践:分层定义文件
src/nativeInterop/cinterop/
├── base.def # 基础库
├── graphics.def # 图形相关
├── network.def # 网络相关
└── platform_linux.def # 平台特定实践:版本管理
properties
# mylib.def
# Library: MyLib
# Version: 2.1.0
# Last updated: 2024-01-01
# Source: https://github.com/example/mylib
headers = mylib.h
package = mylib实践:封装 C API
kotlin
@OptIn(ExperimentalForeignApi::class)
// 不要直接暴露 C API
class ImageProcessor {
private val nativeImage: CPointer<Image>?
init {
nativeImage = create_image(640, 480)
}
fun process() {
// 封装 C调用
}
fun close() {
nativeImage?.let { destroy_image(it) }
}
}cinterop 是连接 Kotlin 与 C 生态的桥梁。合理配置 def 文件、理解类型映射规则,能够高效利用海量 C/C++ 库。