Skip to content

klib 库格式详解

源:Kotlin/Native Libraries

klib 是 Kotlin/Native 的标准库格式,理解其结构对库开发、依赖管理和问题排查至关重要。

库格式结构

ZIP 文件布局

klib 本质上是一个 ZIP 压缩包,遵循预定义的目录结构:

foo.klib 解包后 → foo/
├── $component_name/           # 组件目录
│   ├── ir/                    # Kotlin IR (中间表示)
│   │   ├── files/             # IR文件
│   │   ├── bodies.knb         # IR 函数体
│   │   ├── declarations.knd   # IR 声明
│   │   ├── signatures.knm     # IR 签名
│   │   └── strings.kns        # 字符串表
│   ├── linkdata/              # 链接元数据(ProtoBuf)
│   │   ├── package_*/         # 按包组织
│   │   └── module             # 模块信息
│   ├── targets/               # 平台特定代码
│   │   ├── macosArm64/
│   │   │   ├── kotlin/        # Kotlin编译为LLVM bitcode
│   │   │   └── native/        # 额外的native对象bitcode
│   │   ├── linuxX64/
│   │   └── mingwX64/
│   ├── resources/             # 通用资源(保留,未使用)
│   └── manifest               # 库描述文件(Java properties格式)

manifest 文件详解

manifest 文件包含库的关键元数据:

properties
# foo.klib/manifest 示例
unique_name=org.example:foo
abi_version=1.9.20
compiler_version=1.9.20
library_version=1.0.0
native_targets=linuxX64 macosArm64 mingwX64
ir_provider=source
字段说明
unique_name库的唯一标识符(Maven坐标格式)
abi_versionABI 版本,用于兼容性检查
compiler_version编译此库的编译器版本
library_version库版本号
native_targets支持的目标平台列表
ir_providerIR提供方式(source/bitcode)

IR 目录结构

IR(Intermediate Representation)是Kotlin编译器的内部表示:

ir/
├── files/
│   ├── 0.knf              # 文件0的IR
│   ├── 1.knf              # 文件1的IR
│   └── ...
├── bodies.knb             # 函数体序列化
├── declarations.knd       # 声明序列化
├── signatures.knm         # 签名信息
├── strings.kns            # 字符串常量表
└── debug.knd              # 调试信息(包含源文件路径)

klib 工具

基础命令

Kotlin/Native 提供 klib 命令行工具用于检查库:

bash
# 查看库基本信息
klib info foo.klib

# 输出示例:
# Kotlin/Native library
# Unique name: org.example:foo
# ABI version: 1.9.20
# Compiler version: 1.9.20
# Library version: 1.0.0
# Targets: linuxX64, macosArm64

高级检查命令

bash
# 导出ABI快照(用于检测ABI兼容性)
klib dump-abi foo.klib

# 输出每个声明的ABI签名
# class org.example.Foo {
#   fun bar(): kotlin.Int
#   val prop: kotlin.String
# }
bash
# 导出IR表示(调试用)
klib dump-ir foo.klib

# 显示Kotlin IR的完整表示
# FILE fqName:org.example file:/path/to/Foo.kt
#   CLASS CLASS name:Foo ...
#     FUN name:bar ...
bash
# 导出所有非私有声明的IR签名
klib dump-ir-signatures foo.klib

# 输出:
# Library declarations:
#   org.example/Foo|null[0]
#   org.example/Foo.bar|bar(){}[0]
# Consumed declarations:
#   kotlin/Any|null[0]
bash
# 导出元数据(调试用)
klib dump-metadata foo.klib -print-signatures true

# 显示Kotlin元数据和对应的IR签名

签名版本控制

bash
# 指定IR签名版本
klib dump-ir-signatures foo.klib -signature-version 2

# 如果不指定,使用库支持的最新版本

创建和使用库

命令行方式

kotlin
// kotlinizer.kt
package kotlinizer

val String.kotlinized
    get() = "Kotlin $this"

fun process(input: String): String {
    return input.kotlinized
}
bash
# -p library 指定输出为库
kotlinc-native kotlinizer.kt -p library -o kotlinizer

# 生成 kotlinizer.klib
ls kotlinizer.klib
bash
klib info kotlinizer.klib

# 输出:
# Kotlin/Native library
# Unique name: kotlinizer
# ...
kotlin
// use.kt
import kotlinizer.*

fun main() {
    println("Hello, ${"world".kotlinized}!")
    println(process("multiplatform"))
}
bash
# -l kotlinizer 链接库
kotlinc-native use.kt -l kotlinizer -o kohello

./kohello.kexe
# 输出:
# Hello, Kotlin world!
# Kotlin multiplatform

Gradle 方式

kotlin
// build.gradle.kts
kotlin {
    linuxX64 {
        binaries {
            // 生成共享库(.so)
            sharedLib {
                baseName = "mylib"
            }
            
            // 生成静态库(.a)
            staticLib {
                baseName = "mylib_static"
            }
        }
    }
    
    // 多平台支持
    macosArm64()
    mingwX64()
    
    sourceSets {
        val commonMain by getting {
            // 通用代码
        }
        
        val linuxX64Main by getting {
            dependencies {
                // 依赖本地klib
                implementation(files("libs/custom.klib"))
            }
        }
    }
}

生成的klib位于:

build/classes/kotlin/linuxX64/main/klib/mylib.klib

库搜索机制

搜索顺序

当使用 -library foo-l foo 时,编译器按以下顺序搜索库:

1. 当前编译目录或绝对路径
   ./foo.klib
   /absolute/path/foo.klib

2. 默认仓库
   ~/.konan/klib/
  
3. 安装目录
   $KOTLIN_NATIVE_HOME/klib/

配置默认仓库

kotlin
// gradle.properties
konan.data.dir=/custom/konan/path
bash
# 自定义konan数据目录
kotlinc-native -Xkonan-data-dir=/custom/konan \
    main.kt -l foo
    
# 通过cinterop
cinterop -Xkonan-data-dir=/custom/konan \
    -def mylib.def

相对路径处理

调试信息路径1.6.0+

默认情况下,klib中的调试信息包含绝对路径

/home/user/project/src/Main.kt

这在不同机器上调试时会有问题。

使用相对路径

bash
# 指定基准路径
kotlinc-native \
    -Xklib-relative-path-base=/home/user/project \
    -Xklib-relative-path-base=/home/user/libs \
    src/Main.kt -p library -o mylib

# 生成的klib中路径变为:
# src/Main.kt  (相对于第一个匹配的基准路径)

Gradle配置:

kotlin
kotlin {
    linuxX64 {
        compilations.all {
            kotlinOptions {
                freeCompilerArgs += listOf(
                    "-Xklib-relative-path-base=${project.rootDir}",
                    "-Xklib-relative-path-base=${project.buildDir}"
                )
            }
        }
    }
}

实战示例

查看stdlib结构

bash
# 找到stdlib的klib
ls $KOTLIN_NATIVE_HOME/klib/common/stdlib

# 解压查看
unzip stdlib.klib -d stdlib_unpacked

# 查看manifest
cat stdlib_unpacked/default/manifest

# 查看IR
klib dump-ir-signatures stdlib.klib | head -20

检查ABI兼容性

bash
# 生成v1.0的ABI快照
klib dump-abi mylib-1.0.klib > mylib-1.0.abi

# 生成v1.1的ABI快照
klib dump-abi mylib-1.1.klib > mylib-1.1.abi

# 对比差异
diff mylib-1.0.abi mylib-1.1.abi

# 如果有差异,说明ABI不兼容(需要主版本号升级)

调试IR问题

kotlin
// 某个函数优化异常时
klib dump-ir mylib.klib | grep "myFunction"

// 查看具体的IR表示,分析优化问题

最佳实践

实践:版本管理

kotlin
// build.gradle.kts
version = "2.1.0"

kotlin {
    targets.withType<KotlinNativeTarget> {
        compilations.all {
            kotlinOptions {
                // 嵌入版本到模块名
                freeCompilerArgs += "-module-name=${project.name}-${project.version}"
            }
        }
    }
}

实践:发布到Maven

kotlin
// build.gradle.kts
plugins {
    `maven-publish`
}

publishing {
    publications {
        create<MavenPublication>("kotlinNative") {
            from(components["kotlin"])
            
            groupId = "org.example"
            artifactId = "mylib"
            version = "1.0.0"
            
            pom {
                name.set("My Kotlin/Native Library")
                description.set("A sample library")
                url.set("https://github.com/example/mylib")
            }
        }
    }
    
    repositories {
        maven {
            url = uri("https://maven.example.org/releases")
        }
    }
}

实践:验证库完整性

bash
#!/bin/bash
# verify-klib.sh

KLIB=$1

echo "=== 验证 $KLIB ==="

# 1. 检查是否为有效ZIP
unzip -t "$KLIB" > /dev/null || {
    echo "错误: 不是有效的ZIP文件"
    exit 1
}

# 2. 检查manifest存在
unzip -l "$KLIB" | grep -q "manifest" || {
    echo "错误: 缺少manifest文件"
    exit 1
}

# 3. 检查IR目录
unzip -l "$KLIB" | grep -q "ir/" || {
    echo "错误: 缺少IR目录"
    exit 1
}

# 4. 使用klib工具验证
klib info "$KLIB" > /dev/null || {
    echo "错误: klib info 失败"
    exit 1
}

echo "✓ 库验证通过"

klib 格式支持跨平台代码共享、增量编译和 ABI 版本控制。理解其内部结构有助于优化构建流程和排查问题。