JPS: Support new MPP model.
This commit is contained in:
committed by
Sergey Igushkin
parent
ecf607d4fa
commit
839a6b5e60
@@ -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)
|
||||
}
|
||||
|
||||
@@ -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<JavaSourceRootDescriptor>(JavaModuleBuildTargetType.ALL_TYPES) {
|
||||
override fun getAdditionalRoots(
|
||||
target: BuildTarget<JavaSourceRootDescriptor>,
|
||||
@@ -41,7 +33,12 @@ class KotlinSourceRootProvider : AdditionalRootsProviderService<JavaSourceRootDe
|
||||
|
||||
val result = mutableListOf<JavaSourceRootDescriptor>()
|
||||
|
||||
// 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<JavaSourceRootDe
|
||||
)
|
||||
}
|
||||
|
||||
// add source roots of the expectedBy modules
|
||||
// new multiplatform model support:
|
||||
module.sourceSetModules.forEach { sourceSetModule ->
|
||||
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<JavaSourceRootDescriptor>,
|
||||
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<JavaSourceRootDe
|
||||
}
|
||||
}
|
||||
|
||||
// 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.
|
||||
JpsJavaExtensionService.dependencies(commonModule)
|
||||
.also {
|
||||
if (!target.isTests) it.productionOnly()
|
||||
}
|
||||
.processModules {
|
||||
addCommonModuleSourceRoots(
|
||||
result,
|
||||
it,
|
||||
ModuleBuildTarget(it, target.targetType as JavaModuleBuildTargetType)
|
||||
)
|
||||
}
|
||||
if (recursive) {
|
||||
JpsJavaExtensionService.dependencies(module)
|
||||
.also {
|
||||
if (!target.isTests) it.productionOnly()
|
||||
}
|
||||
.processModules {
|
||||
addModuleSourceRoots(
|
||||
result,
|
||||
it,
|
||||
ModuleBuildTarget(it, target.targetType as JavaModuleBuildTargetType),
|
||||
true
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,13 +116,13 @@ private val JpsModuleSourceRootType<*>.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,
|
||||
|
||||
@@ -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] "
|
||||
}
|
||||
|
||||
@@ -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<JpsModule>
|
||||
get() = findDependencies(kotlinFacet?.settings?.sourceSetNames)
|
||||
|
||||
/**
|
||||
* Legacy. List of modules with `expectedBy` dependency.
|
||||
*/
|
||||
val JpsModule.expectedByModules: List<JpsModule>
|
||||
get() {
|
||||
val kotlinFacetExtension = kotlinFacet
|
||||
val implementedModuleNames = kotlinFacetExtension?.settings?.implementedModuleNames ?: return listOf()
|
||||
if (implementedModuleNames.isEmpty()) return listOf()
|
||||
get() = findDependencies(kotlinFacet?.settings?.implementedModuleNames)
|
||||
|
||||
val result = ArrayList<JpsModule>(implementedModuleNames.size)
|
||||
private fun JpsModule.findDependencies(moduleNames: List<String>?): List<JpsModule> {
|
||||
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<JpsModule>(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() {
|
||||
|
||||
@@ -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<BuildMetaInfoType : BuildMetaInfo>(
|
||||
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<BuildMetaInfoType : BuildMetaInfo>(
|
||||
}
|
||||
|
||||
/**
|
||||
* @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<File>
|
||||
get() = sources.values.map { it.file }
|
||||
|
||||
Reference in New Issue
Block a user