Gradle拒绝缓存输出目录重叠的任务,因其无法判断文件归属,可能引发覆盖或污染;启用缓存后会校验路径排他性,检测到重叠即禁用相关任务缓存并警告。

Gradle任务输出目录重叠导致缓存失效
当多个任务的 @TaskOutputs 指向同一个目录(比如都写成 build/classes/java/main),Gradle 无法安全复用缓存 —— 因为它无法判断该目录下哪些文件属于哪个任务,一旦缓存命中并还原,可能覆盖或污染其他任务的输出。
为什么Gradle拒绝缓存有重叠输出的任务
Gradle 在启用 org.gradle.caching=true 后,会对每个 @CacheableTask 做输出路径排他性校验。只要检测到两个及以上任务声明了相同或嵌套的输出路径,就会直接禁用这些任务的缓存,并在构建日志中输出警告:
Warning: Task ':app:compileJava' has output overlapping with task ':app:compileKotlin'. Caching disabled.
- 这不是 bug,而是设计上的保守策略:避免因文件覆盖引发构建不一致
- 即使两个任务实际生成的文件名不冲突(如
A.class和B.kt),Gradle 也不做内容级隔离,只看路径声明 - Android Gradle Plugin 8.0+ 对此更严格,连
build/intermediates/javac/和build/intermediates/kotlin-classes/若被手动统一指向同一路径,也会触发同等问题
常见重叠场景与修复方式
典型误配包括自定义编译任务、资源处理任务、或插件未正确隔离输出路径:
- 手动配置
destinationDirectory时硬编码路径,而非使用layout.buildDirectory.dir("xxx") - 在 Kotlin 和 Java 混合项目中,把
KotlinCompile和JavaCompile的destinationDir都设为file("build/classes") - 编写自定义
Copy或Sync任务时,into指向已有任务的输出目录(如into layout.buildDirectory.dir("libs"),而GenerateLibs也输出到此处)
修复原则只有一条:每个 @CacheableTask 的 @OutputDirectory 或 @OutputFile 必须唯一且不可被其他任务声明 —— 即使它们物理上可以共存,也要在 Gradle 的元数据层面保持隔离。
调试缓存是否因重叠被禁用
开启缓存调试后,关键线索藏在日志里:
./gradlew build --configuration-cache --no-daemon --info | grep -i "overlapping\|cache disabled"
- 检查
build/reports/builds/下的 HTML 报告,搜索 “Overlapping outputs” - 运行
./gradlew tasks --all看哪些任务标注了[cached: no],再查其源码中的@Output声明 - 注意:重叠问题不会导致构建失败,但会让本可命中的缓存彻底失效 —— 这类问题最容易被忽略,因为构建仍能成功
真正难排查的是间接重叠:比如一个自定义任务输出到 build/generated/src,而另一个 AGP 内置任务恰好也往这个路径写中间文件,但后者没显式声明 @OutputDirectory —— 此时 Gradle 仍会检测到冲突,只是日志提示更隐晦。











