Skip to content

KMP 源码增量编译

KMP 的 Android 目标不仅包含当前修改的 Kotlin 文件,还可能依赖 common、Android 平台和中间 source set 中的 expect / actual 声明。Jugg 从 Gradle 同步结果恢复这些关系,在增量编译时补齐必要源码,而不是把目录结构当作编译模型。

expect / actual 关系不等于目录配对

同名文件、同名声明或 commonMain / androidMain 目录只能提供线索,不能完整描述 Kotlin 编译关系。例如项目可能使用 sharedMain 等中间 source set,也可能在普通 Android 模块中创建同名目录。

因此,Jugg 不根据文件名或目录名猜测互补源码。只有 Gradle 模型确认某个 source set 参与当前 Android 编译时,它才会进入对应的增量编译上下文。

Gradle 编译模型确定 Android 目标

Gradle 同步会提供 Android 目标对应的 Kotlin 编译、公共源码目录以及 source set fragment 依赖关系。Jugg 使用这些信息回答三个问题:

  • 当前文件是否属于 KMP 的 Android 编译目标;
  • 哪些公共、平台或中间 source set 与它共同参与编译;
  • 本轮 Kotlin 编译需要使用哪些目标参数和依赖。

项目新增 target、调整 source set 层级或修改 Kotlin 编译参数后,需要先同步 Gradle,让这些关系进入新的编译基线。

互补源码如何进入同一轮编译

每次成功的项目编译都会记录能够确认的源码互补关系。后续只修改其中一侧时,Jugg 会把另一侧的必要源码补入本轮输入:

text
本轮修改的 KMP 源码
  → 定位所属 Android 编译目标
  → 从已确认关系中补齐 common、platform 或中间 source set 源码
  → 使用同一套 Kotlin 编译参数完成编译

如果互补信息缺失或存在歧义,Jugg 采用 Best-effort:保留当前能够确认的源码输入,不按名称强行配对。这样可以避免把不相关文件加入编译;如果必要源码确实无法恢复,本轮会保留真实编译错误,提示使用 Gradle 刷新基线。

过期 Kotlin 输出为什么会干扰编译

Kotlin 1.9 场景可能把上一轮 expect / actual 相关输出重新加入增量分析。如果这些输出与本轮源码同时出现,编译器可能把同一声明识别两次,产生重复声明或错误的符号解析。

Jugg 会依据源码与历史输出的映射,在本轮编译输入中隔离可能冲突的旧输出。正式 Gradle 基线文件不会被移动或删除;处理只影响当前 Jugg 编译过程。

只有成功编译才推进互补关系

互补关系来自最近一次成功的项目编译。失败编译中的输入可能不完整,不能成为下一轮的可靠依据。因此,Jugg 只在 Kotlin 编译成功后更新关系记录;失败时保留原有基线和最终异常。

使用边界

  • 首次启用 KMP、变更 target 或重组 source set 后,先执行 Gradle 同步和完整 Gradle 编译。
  • 普通 Android 模块中的目录名不会自动触发 KMP 处理。
  • 删除源码可能需要清理历史输出和重新计算关系,应使用 Gradle 编译。
  • 遇到无法补齐的 expect / actual、fragment 或符号解析错误时,使用 Gradle 编译刷新项目模型和输出基线。

相关页面