用途
在 Kotlin 多平台桌面构建中,为某个 CPU 架构(如 Windows ARM64)添加目标之前,审计所有携带原生二进制的依赖是否包含该架构的切片。一个缺失的原生切片会导致整个目标在首次使用该功能时失败,而不是在构建时。
主要能力
- 扫描本地 Gradle 缓存或指定运行时类路径中的 jar,列出每个 jar 内的原生库目录(.so、.dll、.dylib)。
- 识别三种原生代码打包形态:所有切片在一个 jar 内按平台目录组织;每个平台一个 jar,架构在 artifact 坐标中;由构建过程暂存到打包器复制的目录。
- 通过对比每个原生依赖的切片列表与目标架构列表,发现缺失的切片。
- 检查 JVM 发行版是否提供目标架构的构建。
- 当发现真实缺口时,建议放弃该目标而非发布已知无法打开数据库的构建,并记录决策以便未来恢复。
使用方式
- 解析运行时类路径:让 Gradle 打印
RuntimeClasspath配置的路径,或直接扫描本地缓存。 - 对每个 jar 执行
unzip -l并提取原生库路径,按目录去重。 - 对比切片列表与目标架构列表,注意不同库的命名约定(如
natives/windows_x64与com/sun/jna/win32-x86)。 - 检查自己暂存的原生库以及 JVM 发行版。
- 每次依赖升级后重新运行审计。
示例命令:
find ~/.gradle/caches/modules-2 -name '*.jar' \
| while read -r jar; do
slices=$(unzip -l "$jar" 2>/dev/null \
| grep -Eio '[^ ]+\.(so|dll|dylib)$' \
| xargs -n1 dirname | sort -u)
[ -n "$slices" ] && printf '\n== %s\n%s\n' "$(basename "$jar")" "$slices"
done
验证示例:
SQLITE=$(find ~/.gradle/caches/modules-2 -name 'sqlite-bundled-jvm-2.7.0.jar' ! -name '*sources*' | head -1)
JNA=$(find ~/.gradle/caches/modules-2 -name 'jna-5.19.1.jar' | head -1)
for j in "$SQLITE" "$JNA"; do
echo "== $(basename "$j") =="; unzip -l "$j" | grep -Eio '[^ ]+\.(so|dll|dylib)$' | xargs -n1 dirname | sort -u
done
适用场景
- 在桌面构建中添加新的 CPU 架构目标之前。
- 依赖升级后,因为切片可能被添加或移除。
- 发布前验证,确保所有原生依赖支持目标架构。
- 检查自己构建暂存的原生库以及 JVM 发行版。
限制
- 没有统一的命名约定,不能依赖固定模式 grep,必须列出并阅读。
- 缺失切片不可见,需要预先知道期望哪些架构,并对比切片列表。
- 审计显而易见的依赖(如渲染器、媒体后端)可能遗漏不显眼的依赖(如数据库驱动)。
- 同一库的预发布版本不一定是修复,需验证确切版本。
- 当缺口真实存在时,建议放弃目标,并记录决策和恢复条件。