[JPS] Rebuild module on facet change

The logic of detecting changes in Kotlin facets was changed from "Include selected fields" to "Include all compiler arguments and exclude selected". This will help to avoid multiple IC issues when new change-sensitive compiler arguments will be added

(#KTIJ-17137, #KT-51536, #KTIJ-17170, #KTIJ-17300, #KT-47983) Fixed

Merge-request: KT-MR-7455
Merged-by: Aleksei Cherepanov <aleksei.cherepanov@jetbrains.com>
This commit is contained in:
Aleksei.Cherepanov
2022-10-26 09:45:27 +00:00
committed by Space Team
parent 50cd560d09
commit 26e7c29a91
17 changed files with 416 additions and 355 deletions
@@ -108,11 +108,11 @@ abstract class AbstractIncrementalLazyCachesTest : AbstractIncrementalJpsTest()
}.sortedBy { it.target.jpsModuleBuildTarget.presentableName }
allTargets.forEach { (chunk, target) ->
val metaBuildInfo = chunk.buildMetaInfoFile(target.jpsModuleBuildTarget)
val compilerArgumentsFile = chunk.compilerArgumentsFile(target.jpsModuleBuildTarget)
dumpCachesForTarget(
printer, paths, target.jpsModuleBuildTarget,
target.localCacheVersionManager.versionFileForTesting,
metaBuildInfo.toFile(),
compilerArgumentsFile.toFile(),
subdirectory = KOTLIN_CACHE_DIRECTORY_NAME
)
}
@@ -1,59 +0,0 @@
/*
* Copyright 2010-2018 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.jps.build
import junit.framework.TestCase
class JoinToReadableStringTest : TestCase() {
fun test0() {
assertEquals(
"",
listOf<String>().joinToReadableString()
)
}
fun test1() {
assertEquals(
"a",
listOf("a").joinToReadableString()
)
}
fun test2() {
assertEquals(
"a and b",
listOf("a", "b").joinToReadableString()
)
}
fun test3() {
assertEquals(
"a, b and c",
listOf("a", "b", "c").joinToReadableString()
)
}
fun test4() {
assertEquals(
"a, b, c and d",
listOf("a", "b", "c", "d").joinToReadableString()
)
}
fun test5() {
assertEquals(
"a, b, c, d and e",
listOf("a", "b", "c", "d", "e").joinToReadableString()
)
}
fun test6() {
assertEquals(
"a, b, c, d, e and 1 more",
listOf("a", "b", "c", "d", "e", "f").joinToReadableString()
)
}
}
@@ -45,6 +45,7 @@ import org.jetbrains.kotlin.cli.jvm.K2JVMCompiler
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.JvmCodegenUtil
import org.jetbrains.kotlin.config.IncrementalCompilation
import org.jetbrains.kotlin.config.JvmDefaultMode
import org.jetbrains.kotlin.config.KotlinFacetSettings
import org.jetbrains.kotlin.incremental.components.LookupTracker
import org.jetbrains.kotlin.jps.build.KotlinJpsBuildTestBase.LibraryDependency.*
@@ -828,6 +829,121 @@ open class KotlinJpsBuildTest : KotlinJpsBuildTestBase() {
checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt"))
}
@WorkingDir("KotlinProject")
fun testModuleRebuildOnJvmTargetChange() {
initProject(JVM_MOCK_RUNTIME)
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
(facet.compilerArguments as K2JVMCompilerArguments).jvmTarget = "1.8"
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
buildAllModules().assertSuccessful()
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
(facet.compilerArguments as K2JVMCompilerArguments).jvmTarget = "9"
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt"))
}
@WorkingDir("KotlinProject")
fun testModuleRebuildOnBackendChange() {
initProject(JVM_MOCK_RUNTIME)
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
(facet.compilerArguments as K2JVMCompilerArguments).useK2 = false
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
buildAllModules().assertSuccessful()
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
(facet.compilerArguments as K2JVMCompilerArguments).useK2 = true
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt"))
}
@WorkingDir("KotlinProject")
fun testModuleRebuildOnJvmDefaultChange() {
initProject(JVM_MOCK_RUNTIME)
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
(facet.compilerArguments as K2JVMCompilerArguments).jvmDefault = JvmDefaultMode.DEFAULT.description
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
buildAllModules().assertSuccessful()
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
(facet.compilerArguments as K2JVMCompilerArguments).jvmDefault = JvmDefaultMode.ALL_COMPATIBILITY.description
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt"))
}
@WorkingDir("KotlinProject")
fun testModuleRebuildOnAddJavaMoudlesChange() {
initProject(JVM_MOCK_RUNTIME)
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
buildAllModules().assertSuccessful()
myProject.modules.forEach {
val facet = KotlinFacetSettings()
facet.useProjectSettings = false
facet.compilerArguments = K2JVMCompilerArguments()
(facet.compilerArguments as K2JVMCompilerArguments).additionalJavaModules = arrayOf("ALL-MODULE-PATH")
it.container.setChild(
JpsKotlinFacetModuleExtension.KIND,
JpsKotlinFacetModuleExtension(facet)
)
}
checkWhen(emptyArray(), null, packageClasses("kotlinProject", "src/test1.kt", "Test1Kt"))
}
fun testBuildAfterGdwBuild() {
initProject(JVM_FULL_RUNTIME)
findModule("module2").let {
@@ -139,10 +139,8 @@ class KotlinChunk internal constructor(val context: KotlinCompileContext, val ta
}
fun shouldRebuild(): Boolean {
val buildMetaInfo = representativeTarget.buildMetaInfoFactory.create(compilerArguments)
targets.forEach { target ->
if (target.isVersionChanged(this, buildMetaInfo)) {
if (target.isVersionChanged(this, compilerArguments)) {
KotlinBuilder.LOG.info("$target version changed, rebuilding $this")
return true
}
@@ -157,10 +155,10 @@ class KotlinChunk internal constructor(val context: KotlinCompileContext, val ta
return false
}
fun buildMetaInfoFile(target: ModuleBuildTarget): Path = context.dataPaths
fun compilerArgumentsFile(target: ModuleBuildTarget): Path = context.dataPaths
.getTargetDataRoot(target)
.toPath()
.resolve(representativeTarget.buildMetaInfoFileName)
.resolve(representativeTarget.compilerArgumentsFileName)
fun saveVersions() {
context.ensureLookupsCacheAttributesSaved()
@@ -169,10 +167,10 @@ class KotlinChunk internal constructor(val context: KotlinCompileContext, val ta
it.initialLocalCacheAttributesDiff.manager.writeVersion()
}
val serializedMetaInfo = representativeTarget.buildMetaInfoFactory.serializeToString(compilerArguments)
val serializedCompilerArguments = representativeTarget.buildMetaInfo.serializeArgsToString(compilerArguments)
targets.forEach { target ->
Files.newOutputStream(buildMetaInfoFile(target.jpsModuleBuildTarget)).bufferedWriter().use { it.append(serializedMetaInfo) }
Files.newOutputStream(compilerArgumentsFile(target.jpsModuleBuildTarget)).bufferedWriter()
.use { it.append(serializedCompilerArguments) }
}
}
@@ -12,6 +12,7 @@ import org.jetbrains.jps.incremental.GlobalContextKey
import org.jetbrains.jps.incremental.fs.CompilationRound
import org.jetbrains.jps.incremental.messages.BuildMessage
import org.jetbrains.jps.incremental.messages.CompilerMessage
import org.jetbrains.kotlin.build.joinToReadableString
import org.jetbrains.kotlin.config.CompilerRunnerConstants.KOTLIN_COMPILER_NAME
import org.jetbrains.kotlin.incremental.LookupSymbol
import org.jetbrains.kotlin.incremental.storage.FileToPathConverter
@@ -303,10 +304,3 @@ class KotlinCompileContext(val jpsContext: CompileContext) {
}
}
}
fun List<String>.joinToReadableString(): String = when {
size > 5 -> take(5).joinToString() + " and ${size - 5} more"
size > 1 -> dropLast(1).joinToString() + " and ${last()}"
size == 1 -> single()
else -> ""
}
@@ -34,12 +34,12 @@ class KotlinCommonModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModu
override val isIncrementalCompilationEnabled: Boolean
get() = false
override val buildMetaInfoFactory
get() = CommonBuildMetaInfo
override val buildMetaInfoFileName
override val compilerArgumentsFileName
get() = COMMON_BUILD_META_INFO_FILE_NAME
override val buildMetaInfo: CommonBuildMetaInfo
get() = CommonBuildMetaInfo()
override val globalLookupCacheId: String
get() = "metadata-compiler"
@@ -54,12 +54,12 @@ class KotlinJsModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModuleBu
override val isIncrementalCompilationEnabled: Boolean
get() = IncrementalCompilation.isEnabledForJs()
override val buildMetaInfoFactory
get() = JsBuildMetaInfo
override val buildMetaInfoFileName: String
override val compilerArgumentsFileName: String
get() = JS_BUILD_META_INFO_FILE_NAME
override val buildMetaInfo: JsBuildMetaInfo
get() = JsBuildMetaInfo()
val isFirstBuild: Boolean
get() {
val targetDataRoot = jpsGlobalContext.projectDescriptor.dataManager.dataPaths.getTargetDataRoot(jpsModuleBuildTarget)
@@ -62,12 +62,12 @@ class KotlinJvmModuleBuildTarget(kotlinContext: KotlinCompileContext, jpsModuleB
override fun createCacheStorage(paths: BuildDataPaths) =
JpsIncrementalJvmCache(jpsModuleBuildTarget, paths, kotlinContext.fileToPathConverter)
override val buildMetaInfoFactory
get() = JvmBuildMetaInfo
override val buildMetaInfoFileName
override val compilerArgumentsFileName
get() = JVM_BUILD_META_INFO_FILE_NAME
override val buildMetaInfo: JvmBuildMetaInfo
get() = JvmBuildMetaInfo()
override val targetId: TargetId
get() {
val moduleName = module.k2JvmCompilerArguments.moduleName
@@ -15,9 +15,7 @@ import org.jetbrains.jps.model.java.JpsJavaClasspathKind
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.util.JpsPathUtil
import org.jetbrains.kotlin.build.BuildMetaInfo
import org.jetbrains.kotlin.build.BuildMetaInfoFactory
import org.jetbrains.kotlin.build.GeneratedFile
import org.jetbrains.kotlin.build.*
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity
import org.jetbrains.kotlin.compilerRunner.JpsCompilerEnvironment
@@ -306,7 +304,7 @@ abstract class KotlinModuleBuildTarget<BuildMetaInfoType : BuildMetaInfo> intern
)
inner class SourcesToCompile(
sources: Collection<KotlinModuleBuildTarget.Source>,
sources: Collection<Source>,
val removedFiles: Collection<File>
) {
val allFiles = sources.map { it.file }
@@ -330,45 +328,36 @@ abstract class KotlinModuleBuildTarget<BuildMetaInfoType : BuildMetaInfo> intern
}
}
abstract val buildMetaInfoFactory: BuildMetaInfoFactory<BuildMetaInfoType>
abstract val compilerArgumentsFileName: String
abstract val buildMetaInfoFileName: String
abstract val buildMetaInfo: BuildMetaInfoType
fun isVersionChanged(chunk: KotlinChunk, buildMetaInfo: BuildMetaInfo): Boolean {
val file = chunk.buildMetaInfoFile(jpsModuleBuildTarget)
fun isVersionChanged(chunk: KotlinChunk, compilerArguments: CommonCompilerArguments): Boolean {
fun printReasonToRebuild(reasonToRebuild: String) {
KotlinBuilder.LOG.info("$reasonToRebuild. Performing non-incremental rebuild (kotlin only)")
}
val currentCompilerArgumentsMap = buildMetaInfo.createPropertiesMapFromCompilerArguments(compilerArguments)
val file = chunk.compilerArgumentsFile(jpsModuleBuildTarget)
if (Files.notExists(file)) return false
val prevBuildMetaInfo =
val previousCompilerArgsMap =
try {
buildMetaInfoFactory.deserializeFromString(Files.newInputStream(file).bufferedReader().use { it.readText() })
?: return false
buildMetaInfo.deserializeMapFromString(Files.newInputStream(file).bufferedReader().use { it.readText() })
} catch (e: Exception) {
KotlinBuilder.LOG.error("Could not deserialize build meta info", e)
KotlinBuilder.LOG.error("Could not deserialize previous compiler arguments info", e)
return false
}
val prevLangVersion = LanguageVersion.fromVersionString(prevBuildMetaInfo.languageVersionString)
val prevApiVersion = ApiVersion.parse(prevBuildMetaInfo.apiVersionString)
val rebuildReason = buildMetaInfo.obtainReasonForRebuild(currentCompilerArgumentsMap, previousCompilerArgsMap)
val reasonToRebuild = when {
chunk.langVersion != prevLangVersion -> "Language version was changed ($prevLangVersion -> ${chunk.langVersion})"
chunk.apiVersion != prevApiVersion -> "Api version was changed ($prevApiVersion -> ${chunk.apiVersion})"
prevLangVersion != LanguageVersion.KOTLIN_1_0 && prevBuildMetaInfo.isEAP && !buildMetaInfo.isEAP -> {
// If EAP->Non-EAP build with IC, then rebuild all kotlin
"Last build was compiled with EAP-plugin"
}
else -> PluginClasspathsComparator(
prevBuildMetaInfo.pluginClasspaths,
buildMetaInfo.pluginClasspaths
).describeDifferencesOrNull()
return if (rebuildReason != null) {
printReasonToRebuild(rebuildReason)
true
} else {
false
}
if (reasonToRebuild != null) {
KotlinBuilder.LOG.info("$reasonToRebuild. Performing non-incremental rebuild (kotlin only)")
return true
}
return false
}
private fun checkRepresentativeTarget(chunk: KotlinChunk) {
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.jps.targets
import org.jetbrains.jps.builders.storage.BuildDataPaths
import org.jetbrains.jps.incremental.ModuleBuildTarget
import org.jetbrains.kotlin.build.BuildMetaInfo
import org.jetbrains.kotlin.build.BuildMetaInfoFactory
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.compilerRunner.JpsCompilerEnvironment
import org.jetbrains.kotlin.jps.build.KotlinCompileContext
@@ -50,9 +49,9 @@ class KotlinUnsupportedModuleBuildTarget(
shouldNotBeCalled()
}
override val buildMetaInfoFactory: BuildMetaInfoFactory<BuildMetaInfo>
override val compilerArgumentsFileName: String
get() = shouldNotBeCalled()
override val buildMetaInfoFileName: String
override val buildMetaInfo: BuildMetaInfo
get() = shouldNotBeCalled()
}