Kotlin/Native Windows 本机库开发指南
Ⅰ. Kotlin/Native 简介
Kotlin/Native 是一项将 Kotlin 代码直接编译为本机二进制文件(无需 JVM)的技术。其核心优势在于:
- 高效执行:基于 LLVM 后端,生成针对特定平台优化的机器码。
- 无缝互操作:可以轻松调用 C/C++ 等系统原生库。
- 跨平台支持:最初为 iOS 设计,现已扩展至 Windows, Linux, macOS, Android 等多个平台。
Ⅱ. Windows 平台本机库概览
在 Windows 系统中,代码库主要有以下几种形式,了解它们的区别对于开发至关重要。
| 文件类型 | 扩展名 | 功能 | 类比 |
|---|---|---|---|
| 动态链接库 | .dll |
在程序运行时按需加载,可被多个程序共享。 | Linux .so |
| 静态链接库 | .lib |
在编译链接阶段,其代码被完整复制到最终的可执行文件中。 | Linux .a |
| 导入库 | .lib |
同样是 .lib 文件,但它仅包含符号引用,用于告诉链接器去哪里找对应的 .dll。 |
- |
💡
.lib文件的“双重身份”Windows 下的
.lib文件存在歧义:
- 静态库 (Static Library):包含完整的二进制代码(
.obj文件的集合),由cl.exe(MSVC) 或ar(MinGW) 生成,文件体积较大。- 导入库 (Import Library):仅包含一个指向
.dll的符号列表和元数据,本身不含任何可执行代码。它在链接时使用,文件体积非常小 (通常只有几 KB)。
Ⅲ. 实战:创建并使用 Kotlin/Native 动态库
本节将完整演示如何使用 Kotlin/Native 创建一个 .dll 动态库,并再创建一个 Kotlin/Native 程序来调用它。
📦 环境准备
- Gradle 项目: 建议使用官方提供的 KMP 模板项目
git clone https://github.com/Kotlin/kmp-native-wizard.git- Visual Studio Build Tools: 用于生成导入库
.lib文件。它比完整的 Visual Studio 更轻量。
- 下载地址 (选择 Tools for Visual Studio -> Build Tools for Visual Studio)。
第 1 阶段:创建 Kotlin/Native 动态库 (.dll)
步骤 1: 配置 Gradle 构建脚本
在 build.gradle.kts 文件中,声明我们的目标平台为 mingwX64,并配置生成一个动态库。
// build.gradle.kts
kotlin {
// 仅针对 Windows MinGW 64位平台
mingwX64("native") { // "native" 是一个自定义的目标名称
binaries {
// 配置生成一个名为 "mordecai" 的动态库 (mordecai.dll)
sharedLib {
baseName = "mordecai"
}
}
}
}
步骤 2: 编写要导出的 Kotlin 代码
创建一个 Kotlin 文件,并使用 @CName 注解来导出一个函数,使其能被 C/C++ 调用。
// src/nativeMain/kotlin/Mordecai.kt
import kotlin.experimental.ExperimentalNativeApi
// @CName 将此函数导出为 C 语言符号 "sayHelloFromKotlinNative"
@CName("sayHelloFromKotlinNative")
fun sayHello() {
println("Hello, this message is from Kotlin/Native!")
}
步骤 3: 编译生成动态库
执行 Gradle 任务来编译项目。
# 执行此命令
./gradlew linkNativeDebugShared # 或 linkNativeReleaseShared
# 编译成功后,产物会出现在以下目录:
# build/bin/native/debugShared/mordecai.dll
# build/bin/native/debugShared/mordecai.def
# build/bin/native/debugShared/mordecai_api.h
产物说明:
mordecai.dll: 核心的动态库文件。mordecai.def: 模块定义文件,描述了 DLL 导出的函数。mordecai_api.h: C/C++ 头文件,包含了导出函数的声明。
第 2 阶段:在 Kotlin/Native 程序中调用动态库
现在,我们将创建一个可执行文件 (.exe) 来调用刚刚生成的 .dll。
步骤 4: 生成导入库 (.lib)
为了让链接器能够识别 .dll 中的函数,我们需要从 .def 文件生成一个导入库 .lib。
打开
x64 Native Tools Command Prompt for VS 2022(通过开始菜单搜索)。进入 DLL 所在的目录。
cd path\to\your\project\build\bin\native\debugShared执行
lib.exe命令生成导入库。# /def: 指定定义文件 # /out: 指定输出的导入库文件名 # /machine:x64 必须指定目标平台为 x64,否则可能因架构不匹配而链接失败 lib /def:mordecai.def /out:mordecai.lib /machine:x64
执行完毕后,当前目录下会生成 mordecai.lib 文件。
步骤 5: 组织 C 互操作文件
为了让 Kotlin/Native 的 C 互操作工具 (cinterop) 能够找到库文件和头文件,我们需要将它们组织到项目中。
在
src/目录下创建以下结构:src/ └── nativeInterop/ └── cinterop/ ├── include/ # 存放头文件 │ └── mordecai_api.h └── libs/ # 存放库文件 ├── mordecai.dll └── mordecai.lib拷贝文件:
- 将步骤 3 生成的
mordecai_api.h拷贝到include/目录。 - 将步骤 3 生成的
mordecai.dll和步骤 4 生成的mordecai.lib拷贝到libs/目录。
- 将步骤 3 生成的
步骤 6: 配置 C 互操作 (cinterop)
回到 build.gradle.kts,添加 cinterop 配置,告诉 Kotlin 如何与我们的 C 库进行交互。同时,添加一个 executable 配置来生成 .exe 文件。
// build.gradle.kts
kotlin {
mingwX64("native") {
// ... sharedLib 配置保留 ...
// 新增 executable 配置,用于生成 .exe 文件
binaries {
sharedLib { baseName = "mordecai" } // 可以保留
executable {
// entryPoint 的默认值就是 "main",可以省略
}
}
compilations.getByName("main") {
cinterops {
// 创建一个名为 "mordecai" 的 cinterop 配置
val mordecai by creating {
// 指定 .def 文件,cinterop 会据此生成 Kotlin 绑定
defFile(project.file("src/nativeInterop/cinterop/mordecai.def"))
// 添加头文件搜索路径
includeDirs("src/nativeInterop/cinterop/include")
}
}
}
}
}
同时,创建 src/nativeInterop/cinterop/mordecai.def 文件,用于指导 cinterop 工具。
# src/nativeInterop/cinterop/mordecai.def
# 生成的 Kotlin 代码将位于此包下
package = com.mordecai.kn.tools
# 需要解析的头文件
headers = mordecai_api.h
# 链接器选项
# -L: 指定库文件的搜索路径
# -l: 指定要链接的库名 (mordecai.lib -> -lmordecai)
linkerOpts.mingw_x64 = -Lsrc/nativeInterop/cinterop/libs -lmordecai
配置完成后,同步 Gradle 项目 (Sync Project with Gradle Files),cinterop 会自动运行并生成 Kotlin 绑定代码。
步骤 7: 编写主程序并运行
现在可以编写 main 函数来调用库中的 sayHelloFromKotlinNative 函数了。
// src/nativeMain/kotlin/Main.kt
import com.mordecai.kn.tools.sayHelloFromKotlinNative
fun main() {
println("Calling the function from our DLL...")
sayHelloFromKotlinNative()
println("Call finished.")
}
执行 Gradle 任务来运行程序。
./gradlew runDebugExecutableMingwX64
⚠️ 运行时错误?
第一次运行时,你可能会遇到一个错误,提示找不到
mordecai.dll。这是因为.exe在运行时需要在其所在目录或系统路径中找到它依赖的.dll文件。解决方案:将
src/nativeInterop/cinterop/libs/mordecai.dll文件手动复制到可执行文件的输出目录build/bin/native/debugExecutable/下,然后再次运行命令即可成功。
Ⅳ. 简化流程:使用静态库
如果不想处理 .dll 运行时依赖的问题,可以选择静态链接。这会将库代码直接编译进最终的 .exe 文件中,使其成为一个独立的单文件程序,但会增加可执行文件的体积。
配置 Gradle 生成静态库:
在build.gradle.kts的binaries块中,添加staticLib配置。kotlin { mingwX64("native") { binaries { // 生成静态库 mordecai.a (MinGW 默认) 或 mordecai.lib (MSVC) staticLib { baseName = "mordecai" } executable() // 保持可执行文件配置 } // ... cinterop 配置保持不变 ... } }编译生成静态库:
./gradlew linkNativeDebugStatic # 或 linkNativeReleaseStatic这会在
build/bin/native/debugStatic/目录下生成libmordecai.a文件。组织并链接:
- 将
libmordecai.a和mordecai_api.h拷贝到src/nativeInterop/cinterop/下对应的libs和include目录。 mordecai.def文件中的linkerOpts配置保持不变,链接器会自动识别并使用.a文件。- 同步 Gradle 项目。
- 将
直接运行:
./gradlew runDebugExecutableMingwX64由于所有代码都已链接进
.exe,这次无需再手动拷贝任何文件,程序可以直接运行。
Ⅴ. 总结
本文详细介绍了在 Windows 平台上使用 Kotlin/Native 创建和消费原生库的两种主要方式:
- 动态链接:通过
.dll和导入库.lib实现。优点是代码共享、模块化更新;缺点是需要处理运行时依赖。 - 静态链接:通过静态库
.a或.lib实现。优点是部署简单、单文件分发;缺点是可执行文件体积较大。
掌握这两种技术,可以让你无缝地将 Kotlin/Native 集成到现有的 C/C++ 项目中,或者为其他语言提供高性能的 Kotlin 库。
⭐ 参考源码与自动化插件
本文所有流程的实现代码,以及一个可以自动拷贝依赖文件的 Gradle 插件,都可以在以下仓库找到:
https://github.com/crowforkotlin/mordecai-kn-mingw-example



