Skip to content

头文件与定义文件

源:Definition File

定义文件(.def)是 cinterop 工具的配置文件,告诉编译器如何生成 C 库的 Kotlin 绑定。掌握定义文件的编写是 C 互操作的关键技能。

定义文件基础

###文件格式

.def 文件采用类似 properties 的格式:

properties
# 基本结构
headers = header1.h header2.h
package = com.example.mylib
compilerOpts = -I/usr/local/include
linkerOpts = -L/usr/local/lib -lmylib

必需属性

headers

指定需要生成绑定的 C 头文件:

properties
# 单个头文件
headers = sqlite3.h

# 多个头文件(空格分隔)
headers = stdio.h stdlib.h unistd.h

# 系统头文件和自定义头文件
headers = sys/socket.h mylib.h

package

生成的 Kotlin 代码的包名:

properties
package = com.example.nativelib

# 或使用简短名称
package = mylib

可选属性

headerFilter

指定哪些声明应该被导出(支持 glob 模式):

properties
# 只导出 mylib.h 中的声明
headers = mylib.h other.h
headerFilter = mylib.h

# 使用通配符
headerFilter = mylib/*.h

# 多个过滤器
headerFilter = mylib.h utils.h

TIP

headerFilter 可以避免导出不需要的系统头文件声明,减小生成的 klib 大小。

compilerOpts

传递给 C 编译器的选项:

properties
# 指定头文件搜索路径
compilerOpts = -I/usr/local/include

# 多个选项
compilerOpts = -I/usr/local/include -I./include -DDEBUG

# 宏定义
compilerOpts = -DVERSION=2 -DENABLE_LOGGING

常用编译选项:

选项说明示例
-I<path>添加头文件搜索路径-I/usr/local/include
-D<macro>定义宏-DDEBUG
-D<macro>=<value>定义带值的宏-DVERSION=2
-std=<standard>指定 C 标准-std=c99

linkerOpts

传递给链接器的选项:

properties
# 链接库
linkerOpts = -lsqlite3

# 指定库搜索路径
linkerOpts = -L/usr/local/lib -lmylib

# 多个库
linkerOpts = -lssl -lcrypto -lpthread

常用链接选项:

选项说明示例
-l<name>链接库(自动添加 lib 前缀和后缀)-lsqlite3libsqlite3.so
-L<path>添加库搜索路径-L/usr/local/lib
-framework <name>macOS/iOS Framework-framework UIKit

平台特定配置

条件属性

根据不同平台使用不同配置:

properties
headers = mylib.h
package = mylib

# macOS 配置
compilerOpts.osx = -I/usr/local/include
linkerOpts.osx = -L/usr/local/lib -lmylib

# Linux 配置
compilerOpts.linux = -I/usr/include
linkerOpts.linux = -lmylib -lpthread -ldl

# Windows 配置
compilerOpts.mingw = -I/mingw64/include
linkerOpts.mingw = -lmylib -lws2_32

支持的平台后缀:

后缀平台
.osx .macosmacOS
.linuxLinux
.mingwWindows (MinGW)
.iosiOS (所有架构)
.iosArm64iOS ARM64 设备
.iosX64iOS x64 模拟器
.iosSimulatorArm64iOS ARM64 模拟器
.androidAndroid NDK

平台检测示例

properties
# sqlite.def
headers = sqlite3.h
headerFilter = sqlite3.h
package = sqlite

# macOS
linkerOpts.osx = -lsqlite3

# Linux
linkerOpts.linux = -lsqlite3 -ldl -lpthread

# Windows
linkerOpts.mingw = -lsqlite3

# Android
linkerOpts.android = -lsqlite3
properties
# openssl.def
headers = openssl/ssl.h openssl/crypto.h
headerFilter = openssl/*.h
package = openssl

compilerOpts.osx = -I/usr/local/opt/openssl/include
linkerOpts.osx = -L/usr/local/opt/openssl/lib -lssl -lcrypto

compilerOpts.linux = -I/usr/include/openssl
linkerOpts.linux = -lssl -lcrypto

高级特性

excludeDependendentModules

排除依赖模块的传递导入:

properties
headers = mylib.h
package = mylib
excludeDependentModules = true

staticLibraries

直接链接静态库:

properties
headers = mylib.h
package = mylib
staticLibraries = libmylib.a

# 或指定路径
staticLibraries = /usr/local/lib/libmylib.a

libraryPaths

指定库文件搜索路径(替代 -L):

properties
headers = mylib.h
package = mylib
libraryPaths = /usr/local/lib /opt/lib

modules

模块化导入(Clang modules):

properties
# 使用模块而非头文件
modules = UIKit Foundation
package = platform.uikit

WARNING

modules 选项仅在支持 Clang modules 的平台可用(如 macOS、iOS)。

实战示例

libcurl 定义文件

properties
# libcurl.def
headers = curl/curl.h
headerFilter = curl/*.h
package = libcurl

# 编译选项
compilerOpts = -I/usr/include/curl
compilerOpts.osx = -I/usr/local/opt/curl/include

# 链接选项
linkerOpts = -lcurl
linkerOpts.osx = -L/usr/local/opt/curl/lib -lcurl
linkerOpts.linux = -lcurl
linkerOpts.mingw = -lcurl -lws2_32

zlib 压缩库

properties
# zlib.def
headers = zlib.h
package = zlib

# 所有平台都使用系统 zlib
linkerOpts = -lz

OpenGL 定义文件

properties
# opengl.def
# macOS 使用 OpenGL Framework
headers.osx = OpenGL/gl.h
modules.osx = OpenGL
package.osx = platform.opengl

# Linux 使用 GL 库
headers.linux = GL/gl.h
linkerOpts.linux = -lGL
package.linux = opengl

自定义 C 库

properties
# mylib.def
headers = mylib.h internal.h
headerFilter = mylib.h  # 只导出 public API

package = com.example.mylib

# 开发环境配置
compilerOpts = -I./include -DDEBUG
linkerOpts = -L./build/lib -lmylib

# Release 配置(通过 Gradle 覆盖)
compilerOpts.release = -I./include -DNDEBUG

Gradle 集成

基础配置

kotlin
// build.gradle.kts
kotlin {
    linuxX64 {
        compilations.getByName("main") {
            cinterops {
                val libcurl by creating {
                    // 指定 def 文件
                    defFile(project.file("src/nativeInterop/cinterop/libcurl.def"))
                }
            }
        }
    }
}

覆盖 def 文件配置

kotlin
kotlin {
    linuxX64 {
        compilations.getByName("main") {
            cinterops {
                val mylib by creating {
                    defFile(project.file("src/nativeInterop/cinterop/mylib.def"))
                    
                    // 覆盖包名
                    packageName("com.example.custom")
                    
                    // 添加额外的编译选项
                    compilerOpts("-I/custom/path", "-DEXTRA_FLAG")
                    
                    // 添加额外的链接选项
                    linkerOpts("-L/custom/lib", "-lextra")
                    
                    // 设置头文件目录
                    includeDirs.allHeaders("/usr/local/include")
                }
            }
        }
    }
}

多目标配置

kotlin
kotlin {
    listOf(
        iosX64(),
        iosArm64(),
        iosSimulatorArm64()
    ).forEach { target ->
        target.compilations.getByName("main") {
            cinterops {
                val mylib by creating {
                    defFile(project.file("src/nativeInterop/cinterop/mylib.def"))
                    
                    // iOS 特定配置
                    when (target.name) {
                        "iosArm64" -> {
                            // 真机配置
                            compilerOpts("-arch", "arm64")
                        }
                        else -> {
                            // 模拟器配置
                        }
                    }
                }
            }
        }
    }
}

调试技巧

查看生成的代码

编译后查看生成的 Kotlin 绑定:

bash
# 编译 interop
./gradlew :shared:cinteropMylibLinuxX64

# 查看生成的代码
cat build/classes/kotlin/linuxX64/main/cinterop/mylib-cinterop-mylib.klib

启用详细日志

properties
# gradle.properties
kotlin.native.verbose=true

验证头文件路径

bash
# 测试 C 编译器能否找到头文件
clang -I/usr/local/include -c test.c

常见问题

找不到头文件

properties
# 错误信息
error: 'mylib.h' file not found

# 解决方案:添加头文件搜索路径
compilerOpts = -I/path/to/includes

链接错误

properties
# 错误信息
undefined reference to `my_function'

# 解决方案:确保链接了正确的库
linkerOpts = -L/path/to/libs -lmylib

符号冲突

properties
# 多个库有相同符号时
# 使用 headerFilter 只导出需要的声明
headers = lib1.h lib2.h
headerFilter = lib1.h  # 只导出 lib1 的符号

宏未定义

c
// C 头文件需要宏定义
#ifndef VERSION
#error "VERSION not defined"
#endif
properties
# def 文件中定义宏
compilerOpts = -DVERSION=2

最佳实践

组织定义文件

project/
├── src/
│   └── nativeInterop/
│       └── cinterop/
│           ├── sqlite.def      # 系统库
│           ├── curl.def
│           └── mylib.def       # 自定义库

使用 headerFilter

properties
# 总是使用 headerFilter 避免导出不必要的符号
headers = stdio.h mylib.h
headerFilter = mylib.h  # 只导出 mylib.h

平台特定最小化

properties
# 优先使用跨平台配置
headers = mylib.h
linkerOpts = -lmylib

# 仅在必要时添加平台特定配置
linkerOpts.mingw = -lmylib -lws2_32  # Windows 需要额外的库

版本管理

properties
# 在 def 文件中记录库版本
# SQLite 3.40.0
headers = sqlite3.h
package = sqlite

定义文件是 cinterop 的核心配置,掌握其各项属性和高级特性,能够帮助你高效地集成任何 C 库到 Kotlin/Native 项目中。