[KGP] Treat friendPaths as non-incremental Input property
When friendPaths change, internal symbols from other modules become hidden or visible. This might change which functions are called, which types are returned, etc. So we should recompile the affected classes. Gradle doesn't allow Input policy on FileCollection properties, so we introduce friendPathsSet. It allows us to keep the ABI of BaseKotlinCompile unchanged, detect non-incremental configuration changes on Gradle side, and use normal incremental compilation for everything else. ^KT-61918 Fixed Merge-request: KT-MR-12372 Merged-by: Evgenii Mazhukin <evgenii.mazhukin@jetbrains.com>
This commit is contained in:
committed by
Space Team
parent
d9ddac5571
commit
203b7a4da3
+93
@@ -0,0 +1,93 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.gradle.util.replaceFirst
|
||||
import org.jetbrains.kotlin.gradle.util.replaceText
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
|
||||
@DisplayName("Incremental scenarios with associated compilation")
|
||||
class AssociatedCompilationIT : KGPBaseTest() {
|
||||
override val defaultBuildOptions: BuildOptions
|
||||
get() = super.defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
|
||||
@JvmGradlePluginTests
|
||||
@DisplayName("Rebuild forced if associated compilation changes")
|
||||
@GradleTest
|
||||
fun testRebuildOnAssociatedCompilationChange(gradleVersion: GradleVersion) {
|
||||
val project = getBaseProject(gradleVersion)
|
||||
|
||||
val testSrc = project.kotlinSourcesDir("integrationTest").resolve("test.kt")
|
||||
val utilSrc = project.kotlinSourcesDir("main").resolve("util.kt")
|
||||
|
||||
project.build("compileIntegrationTestKotlin") {
|
||||
assertCompiledKotlinSources(listOf(testSrc, utilSrc).relativizeTo(project.projectPath), output)
|
||||
}
|
||||
|
||||
project.buildGradle.replaceFirst("associateWith(getByName(\"main\"))", "")
|
||||
|
||||
project.buildAndFail("compileIntegrationTestKotlin") {
|
||||
assertTasksFailed(":compileIntegrationTestKotlin")
|
||||
assertOutputContains("Cannot access 'fun doWork(): Int': it is internal in file")
|
||||
}
|
||||
}
|
||||
|
||||
@JvmGradlePluginTests
|
||||
@DisplayName("Rebuild after used internal ABI change in associated compilation")
|
||||
@GradleTest
|
||||
fun testRebuildOnUsedApiChangeInAssociatedCompilation(gradleVersion: GradleVersion) {
|
||||
val project = getBaseProject(gradleVersion)
|
||||
|
||||
val testSrc = project.kotlinSourcesDir("integrationTest").resolve("test.kt")
|
||||
val utilSrc = project.kotlinSourcesDir("main").resolve("util.kt")
|
||||
|
||||
project.build("compileIntegrationTestKotlin")
|
||||
utilSrc.replaceFirst("fun doWork() = 4", "fun doWork() = \"okay\"")
|
||||
|
||||
project.build("compileIntegrationTestKotlin") {
|
||||
assertCompiledKotlinSources(listOf(testSrc, utilSrc).relativizeTo(project.projectPath), output)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmGradlePluginTests
|
||||
@DisplayName("No rebuild after private ABI change in associated compilation")
|
||||
@GradleTest
|
||||
fun testNoRebuildOnPrivateChangeInAssociatedCompilation(gradleVersion: GradleVersion) {
|
||||
val project = getBaseProject(gradleVersion)
|
||||
|
||||
val utilSrc = project.kotlinSourcesDir("main").resolve("util.kt")
|
||||
|
||||
project.build("compileIntegrationTestKotlin")
|
||||
utilSrc.append("private val bar = 2")
|
||||
|
||||
project.build("compileIntegrationTestKotlin") {
|
||||
assertCompiledKotlinSources(listOf(utilSrc).relativizeTo(project.projectPath), output)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmGradlePluginTests
|
||||
@DisplayName("No rebuild after unused ABI change in associated compilation")
|
||||
@GradleTest
|
||||
fun testNoRebuildOnUnusedInternalChangeInAssociatedCompilation(gradleVersion: GradleVersion) {
|
||||
val project = getBaseProject(gradleVersion)
|
||||
|
||||
val utilSrc = project.kotlinSourcesDir("main").resolve("util.kt")
|
||||
|
||||
project.build("compileIntegrationTestKotlin")
|
||||
utilSrc.append("internal val bar = 2")
|
||||
|
||||
project.build("compileIntegrationTestKotlin") {
|
||||
assertCompiledKotlinSources(listOf(utilSrc).relativizeTo(project.projectPath), output)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getBaseProject(gradleVersion: GradleVersion): TestProject {
|
||||
return project("kt-61918-associate-with-incremental", gradleVersion)
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
plugins {
|
||||
id "org.jetbrains.kotlin.jvm"
|
||||
}
|
||||
|
||||
repositories {
|
||||
mavenLocal()
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
kotlin.target.compilations {
|
||||
create("integrationTest") {
|
||||
defaultSourceSet {
|
||||
dependencies {
|
||||
implementation(getByName("main").compileDependencyFiles + getByName("main").output.classesDirs)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//force task instantiation:
|
||||
tasks.getByName("compileIntegrationTestKotlin")
|
||||
|
||||
named("integrationTest").configure { associateWith(getByName("main")) }
|
||||
}
|
||||
+1
@@ -0,0 +1 @@
|
||||
val result = doWork()
|
||||
+1
@@ -0,0 +1 @@
|
||||
internal fun doWork() = 4
|
||||
+10
@@ -102,6 +102,16 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
|
||||
internal open fun isIncrementalCompilationEnabled(): Boolean =
|
||||
incremental
|
||||
|
||||
// This allows us to treat friendPaths as Input rather than InputFiles
|
||||
@get:Input
|
||||
internal val friendPathsSet: Set<String>
|
||||
get() {
|
||||
val buildDirFile = projectLayout.buildDirectory.asFile.get()
|
||||
return friendPaths
|
||||
.filter { it.exists() }
|
||||
.map { it.normalize().relativeTo(buildDirFile).path }.toSet()
|
||||
}
|
||||
|
||||
@Deprecated("Scheduled for removal with Kotlin 2.0", ReplaceWith("moduleName"))
|
||||
@get:Input
|
||||
abstract val ownModuleName: Property<String>
|
||||
|
||||
Reference in New Issue
Block a user