From c475e35489a6ecb83282c654d8dad9be75c99406 Mon Sep 17 00:00:00 2001 From: Sergey Rostov Date: Tue, 31 Jul 2018 15:50:17 +0300 Subject: [PATCH] JPS: Support new MPP model. Original commit: 839a6b5e603b06f48fd07e70531f9abef0fab445 --- .../kotlin/jps/build/KotlinBuilder.kt | 33 +++++++-- .../jps/build/KotlinSourceRootProvider.kt | 74 ++++++++++--------- .../jps/build/MessageCollectorAdapter.kt | 2 +- .../kotlin/jps/model/ModuleSettings.kt | 42 +++++++---- .../jps/platforms/KotlinModuleBuildTarget.kt | 12 +-- 5 files changed, 101 insertions(+), 62 deletions(-) diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt index e818a7c1435..be2d855cb69 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinBuilder.kt @@ -41,13 +41,17 @@ import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.INFO import org.jetbrains.kotlin.cli.common.messages.MessageCollectorUtil import org.jetbrains.kotlin.compilerRunner.* import org.jetbrains.kotlin.config.IncrementalCompilation +import org.jetbrains.kotlin.config.KotlinModuleKind import org.jetbrains.kotlin.config.Services import org.jetbrains.kotlin.daemon.common.isDaemonEnabled import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.jps.incremental.* -import org.jetbrains.kotlin.jps.platforms.* +import org.jetbrains.kotlin.jps.model.kotlinKind +import org.jetbrains.kotlin.jps.platforms.KotlinJvmModuleBuildTarget +import org.jetbrains.kotlin.jps.platforms.KotlinModuleBuildTarget +import org.jetbrains.kotlin.jps.platforms.kotlinBuildTargets import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.preloading.ClassCondition import org.jetbrains.kotlin.utils.KotlinPaths @@ -242,13 +246,28 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) { return NOTHING_DONE val kotlinTarget = context.kotlinBuildTargets[chunk.representativeTarget()] ?: return OK - val messageCollector = MessageCollectorAdapter(context, kotlinTarget) + + // New mpp project model: modules which is imported from sources sets of the compilations shouldn't be compiled for now. + // It should be compiled only as one of source root of target compilation, which is added in [KotlinSourceRootProvider]. + if (chunk.modules.any { it.kotlinKind == KotlinModuleKind.SOURCE_SET_HOLDER }) { + if (chunk.modules.size > 1) { + messageCollector.report( + CompilerMessageSeverity.ERROR, + "Cyclically dependent modules is not supported in multiplatform projects" + ) + return ABORT + } + + return NOTHING_DONE + } + val kotlinDirtyFilesHolder = KotlinDirtySourceFilesHolder(chunk, context, dirtyFilesHolder) val fsOperations = FSOperationsHelper(context, chunk, kotlinDirtyFilesHolder, LOG) try { - val proposedExitCode = doBuild(chunk, kotlinTarget, context, kotlinDirtyFilesHolder, messageCollector, outputConsumer, fsOperations) + val proposedExitCode = + doBuild(chunk, kotlinTarget, context, kotlinDirtyFilesHolder, messageCollector, outputConsumer, fsOperations) val actualExitCode = if (proposedExitCode == OK && fsOperations.hasMarkedDirty) ADDITIONAL_PASS_REQUIRED else proposedExitCode @@ -605,10 +624,10 @@ class KotlinBuilder : ModuleLevelBuilder(BuilderCategory.SOURCE_PROCESSOR) { val representativeTarget = chunk.representativeTarget() fun SimpleOutputItem.target() = sourceFiles.firstOrNull()?.let { sourceToTarget[it] } ?: chunk.targets.singleOrNull { - it.outputDir?.let { - outputFile.startsWith(it) - } ?: false - } ?: representativeTarget + it.outputDir?.let { + outputFile.startsWith(it) + } ?: false + } ?: representativeTarget return outputItemCollector.outputs.groupBy(SimpleOutputItem::target, SimpleOutputItem::toGeneratedFile) } diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinSourceRootProvider.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinSourceRootProvider.kt index 545d1996354..a11453753af 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinSourceRootProvider.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/KotlinSourceRootProvider.kt @@ -20,17 +20,9 @@ import org.jetbrains.jps.model.module.JpsModuleSourceRootType import org.jetbrains.kotlin.config.KotlinResourceRootType import org.jetbrains.kotlin.config.KotlinSourceRootType import org.jetbrains.kotlin.jps.model.expectedByModules +import org.jetbrains.kotlin.jps.model.sourceSetModules import java.io.File -/** - * - adds roots with KotlinSourceRootType as JavaSourceRootDescriptor (see note below) - * - for Multiplatform Projects: adds all the source roots of the expectedBy modules to the platform modules. - * - * Note: `KotlinSourceRootType` cannot be supported directly, since `SourceRootDescriptors` are computed by - * `ModuleBuildTarget.computeAllTargets`. `ModuleBuildTarget` is required for incremental compilation. - * We cannot define our own `ModuleBuildTarget` since it is final and `ModuleBuildTarget` supports only `JavaSourceRootDescriptor`. - * So the only one way to support `KotlinSourceRootType` is to add a fake `JavaSourceRootDescriptor` for each source root with that type. - */ class KotlinSourceRootProvider : AdditionalRootsProviderService(JavaModuleBuildTargetType.ALL_TYPES) { override fun getAdditionalRoots( target: BuildTarget, @@ -41,7 +33,12 @@ class KotlinSourceRootProvider : AdditionalRootsProviderService() - // add source roots with type KotlinSourceRootType + // Add source roots with type KotlinSourceRootType. + // + // Note: `KotlinSourceRootType` cannot be supported directly, since `SourceRootDescriptors` are computed by + // `ModuleBuildTarget.computeAllTargets`. `ModuleBuildTarget` is required for incremental compilation. + // We cannot define our own `ModuleBuildTarget` since it is final and `ModuleBuildTarget` supports only `JavaSourceRootDescriptor`. + // So the only one way to support `KotlinSourceRootType` is to add a fake `JavaSourceRootDescriptor` for each source root with that type. val kotlinSourceRootType = if (target.isTests) KotlinSourceRootType.TestSource else KotlinSourceRootType.Source module.getSourceRoots(kotlinSourceRootType).forEach { result.add( @@ -56,26 +53,37 @@ class KotlinSourceRootProvider : AdditionalRootsProviderService + addModuleSourceRoots(result, sourceSetModule, target, false) + } + + // legacy multiplatform model support: module.expectedByModules.forEach { commonModule -> - addCommonModuleSourceRoots(result, commonModule, target) + // At the moment, incremental compilation is not supported by K2Metadata compiler. + // To avoid long running compilation of common modules, we do not run K2Metadata at all: + // instead all the common source roots are transitively added to the final platform modules. + val isRecursive = true + + addModuleSourceRoots(result, commonModule, target, isRecursive) } return result } - private fun addCommonModuleSourceRoots( + private fun addModuleSourceRoots( result: MutableList, - commonModule: JpsModule, - target: ModuleBuildTarget + module: JpsModule, + target: ModuleBuildTarget, + recursive: Boolean = false ) { - for (commonSourceRoot in commonModule.sourceRoots) { + for (commonSourceRoot in module.sourceRoots) { val isCommonTestsRootType = commonSourceRoot.rootType.isTestsRootType if (isCommonTestsRootType != null && target.isTests == isCommonTestsRootType) { val javaSourceRootProperties = commonSourceRoot.properties as? JavaSourceRootProperties result.add( - KotlinCommonModuleSourceRoot( + KotlinIncludedModuleSourceRoot( commonSourceRoot.file, target, javaSourceRootProperties?.isForGeneratedSources ?: false, @@ -87,20 +95,20 @@ class KotlinSourceRootProvider : AdditionalRootsProviderService.isTestsRootType get() = when (this) { is KotlinSourceRootType -> this == KotlinSourceRootType.TestSource is KotlinResourceRootType -> this == KotlinResourceRootType.TestResource - // for compatibility: + // for compatibility: is JavaSourceRootType -> this == JavaSourceRootType.TEST_SOURCE is JavaResourceRootType -> this == JavaResourceRootType.TEST_RESOURCE else -> null } -class KotlinCommonModuleSourceRoot( +class KotlinIncludedModuleSourceRoot( root: File, target: ModuleBuildTarget, isGenerated: Boolean, diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/MessageCollectorAdapter.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/MessageCollectorAdapter.kt index 60ba5e93e24..2bdb4e8c217 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/MessageCollectorAdapter.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/build/MessageCollectorAdapter.kt @@ -32,7 +32,7 @@ class MessageCollectorAdapter( val kind = kind(severity) if (kind != null) { // Report target when cross-compiling common files - if (location != null && kotlinTarget != null && kotlinTarget.isCommonModuleFile(File(location.path))) { + if (location != null && kotlinTarget != null && kotlinTarget.isFromIncludedSourceRoot(File(location.path))) { val moduleName = kotlinTarget.module.name prefix += "[$moduleName] " } diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/model/ModuleSettings.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/model/ModuleSettings.kt index feb6670c87d..46adf9e6b56 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/model/ModuleSettings.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/model/ModuleSettings.kt @@ -5,15 +5,14 @@ package org.jetbrains.kotlin.jps.model -import org.jetbrains.jps.builders.java.JavaSourceRootDescriptor import org.jetbrains.jps.model.ex.JpsElementBase import org.jetbrains.jps.model.ex.JpsElementChildRoleBase -import org.jetbrains.jps.model.java.JavaSourceRootType import org.jetbrains.jps.model.java.JpsJavaExtensionService import org.jetbrains.jps.model.module.JpsModule import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.config.CompilerSettings import org.jetbrains.kotlin.config.KotlinFacetSettings +import org.jetbrains.kotlin.config.KotlinModuleKind import org.jetbrains.kotlin.config.TargetPlatformKind val JpsModule.kotlinFacet: JpsKotlinFacetModuleExtension? @@ -22,24 +21,37 @@ val JpsModule.kotlinFacet: JpsKotlinFacetModuleExtension? val JpsModule.targetPlatform: TargetPlatformKind<*>? get() = kotlinFacet?.settings?.targetPlatformKind +val JpsModule.kotlinKind: KotlinModuleKind + get() = kotlinFacet?.settings?.kind ?: KotlinModuleKind.DEFAULT + +/** + * Modules which is imported from sources sets of the compilation represented by this module. + * This module is not included. + */ +val JpsModule.sourceSetModules: List + get() = findDependencies(kotlinFacet?.settings?.sourceSetNames) + +/** + * Legacy. List of modules with `expectedBy` dependency. + */ val JpsModule.expectedByModules: List - get() { - val kotlinFacetExtension = kotlinFacet - val implementedModuleNames = kotlinFacetExtension?.settings?.implementedModuleNames ?: return listOf() - if (implementedModuleNames.isEmpty()) return listOf() + get() = findDependencies(kotlinFacet?.settings?.implementedModuleNames) - val result = ArrayList(implementedModuleNames.size) +private fun JpsModule.findDependencies(moduleNames: List?): List { + if (moduleNames == null || moduleNames.isEmpty()) return listOf() - JpsJavaExtensionService.dependencies(this) - .processModules { - if (it.name in implementedModuleNames) { - // Note, production sources should be added for both production and tests targets - result.add(it) - } + val result = ArrayList(moduleNames.size) + + JpsJavaExtensionService.dependencies(this) + .processModules { + if (it.name in moduleNames) { + // Note, production sources should be added for both production and tests targets + result.add(it) } + } - return result - } + return result +} val JpsModule.productionOutputFilePath: String? get() { diff --git a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/platforms/KotlinModuleBuildTarget.kt b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/platforms/KotlinModuleBuildTarget.kt index 2382da36257..9b6e245d9fc 100644 --- a/jps/jps-plugin/src/org/jetbrains/kotlin/jps/platforms/KotlinModuleBuildTarget.kt +++ b/jps/jps-plugin/src/org/jetbrains/kotlin/jps/platforms/KotlinModuleBuildTarget.kt @@ -32,7 +32,7 @@ import org.jetbrains.kotlin.incremental.LookupTrackerImpl import org.jetbrains.kotlin.incremental.components.ExpectActualTracker import org.jetbrains.kotlin.incremental.components.LookupTracker import org.jetbrains.kotlin.jps.build.KotlinBuilder -import org.jetbrains.kotlin.jps.build.KotlinCommonModuleSourceRoot +import org.jetbrains.kotlin.jps.build.KotlinIncludedModuleSourceRoot import org.jetbrains.kotlin.jps.build.KotlinDirtySourceFilesHolder import org.jetbrains.kotlin.jps.build.isKotlinSourceFile import org.jetbrains.kotlin.jps.incremental.CacheVersionProvider @@ -124,13 +124,13 @@ abstract class KotlinModuleBuildTarget( val buildRootIndex = context.projectDescriptor.buildRootIndex val roots = buildRootIndex.getTargetRoots(jpsModuleBuildTarget, context) roots.forEach { rootDescriptor -> - val isCommonRoot = rootDescriptor is KotlinCommonModuleSourceRoot + val isIncludedSourceRoot = rootDescriptor is KotlinIncludedModuleSourceRoot rootDescriptor.root.walkTopDown() .onEnter { file -> file !in moduleExcludes } .forEach { file -> if (!compilerExcludes.isExcluded(file) && file.isFile && file.isKotlinSourceFile) { - receiver[file] = Source(file, isCommonRoot) + receiver[file] = Source(file, isIncludedSourceRoot) } } @@ -138,14 +138,14 @@ abstract class KotlinModuleBuildTarget( } /** - * @property isCommonModule for reporting errors during cross-compilation common module sources + * @property isIncludedSourceRoot for reporting errors during cross-compilation common module sources */ class Source( val file: File, - val isCommonModule: Boolean + val isIncludedSourceRoot: Boolean ) - fun isCommonModuleFile(file: File): Boolean = sources[file]?.isCommonModule == true + fun isFromIncludedSourceRoot(file: File): Boolean = sources[file]?.isIncludedSourceRoot == true val sourceFiles: Collection get() = sources.values.map { it.file }