From 9723d45d27933b5707900975a759325f7f34bad1 Mon Sep 17 00:00:00 2001 From: Ilya Goncharov Date: Thu, 22 Apr 2021 20:55:29 +0300 Subject: [PATCH] [Gradle, JS] Add associateWith compilations to CacheBuilder --- .../kotlin/gradle/plugin/KotlinProperties.kt | 3 + .../gradle/targets/js/ir/KotlinJsIrLink.kt | 196 +++++++++++++----- 2 files changed, 145 insertions(+), 54 deletions(-) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt index 4454de33099..b77d492c577 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt @@ -87,6 +87,9 @@ internal class PropertiesProvider private constructor(private val project: Proje val incrementalJsKlib: Boolean? get() = booleanProperty("kotlin.incremental.js.klib") + val incrementalJsIr: Boolean + get() = booleanProperty("kotlin.incremental.js.ir") ?: false + val incrementalMultiplatform: Boolean? get() = booleanProperty("kotlin.incremental.multiplatform") diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt index 2051134b1e3..7ae88c762cf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt @@ -11,7 +11,9 @@ import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileTree import org.gradle.api.model.ObjectFactory +import org.gradle.api.file.RegularFileProperty import org.gradle.api.logging.Logger +import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.* import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment @@ -23,13 +25,17 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.dsl.copyFreeCompilerArgsToArgs import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.report.ReportingSettings import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.PRODUCTION import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile import org.jetbrains.kotlin.gradle.tasks.SourceRoots -import org.jetbrains.kotlin.gradle.utils.* +import org.jetbrains.kotlin.gradle.utils.getAllDependencies +import org.jetbrains.kotlin.gradle.utils.getCacheDirectory +import org.jetbrains.kotlin.gradle.utils.getDependenciesCacheDirectories +import org.jetbrains.kotlin.gradle.utils.newFileProperty import org.jetbrains.kotlin.incremental.ChangedFiles import java.io.File import javax.inject.Inject @@ -55,6 +61,9 @@ abstract class KotlinJsIrLink @Inject constructor( @get:Internal internal lateinit var compilation: KotlinCompilation<*> + @get:Input + internal val incrementalJsIr: Boolean = PropertiesProvider(project).incrementalJsIr + // Link tasks are not affected by compiler plugin override val pluginClasspath: ConfigurableFileCollection = project.objects.fileCollection() @@ -76,14 +85,49 @@ abstract class KotlinJsIrLink @Inject constructor( @get:PathSensitive(PathSensitivity.RELATIVE) internal abstract val entryModule: DirectoryProperty + override fun getDestinationDir(): File { + return if (kotlinOptions.outputFile == null) { + super.getDestinationDir() + } else { + outputFile.parentFile + } + } + override fun skipCondition(): Boolean { return !entryModule.get().asFile.exists() } override fun callCompilerAsync(args: K2JSCompilerArguments, sourceRoots: SourceRoots, changedFiles: ChangedFiles) { - val cacheArgs = CacheBuilder( + if (incrementalJsIr) { + val visitedDependencies = mutableSetOf() + val visitedFiles = mutableSetOf() + val visitedCompilations = mutableSetOf>() + + val cacheArgs = visitAssociated(compilation, visitedDependencies, visitedFiles, visitedCompilations).distinct() + + args.freeArgs += "-Xcache-directory=${cacheArgs.joinToString(File.pathSeparator) { + it.normalize().absolutePath + }}" + } + super.callCompilerAsync(args, sourceRoots, changedFiles) + } + + private fun visitAssociated( + associated: KotlinCompilation<*>, + visitedDependencies: MutableSet, + visitedFiles: MutableSet, + visitedCompilations: MutableSet> + ): List { + if (associated in visitedCompilations) return emptyList() + visitedCompilations.add(associated) + + val prevRes = associated.associateWith + .flatMap { visitAssociated(it, visitedDependencies, visitedFiles, visitedCompilations) } + + return prevRes + CacheBuilder( buildDir, - compileClasspathConfiguration, + project.configurations.getByName(associated.compileDependencyConfigurationName), + associated.output.classesDirs, kotlinOptions, libraryFilter, compilerRunner, @@ -91,10 +135,10 @@ abstract class KotlinJsIrLink @Inject constructor( computedCompilerClasspath, logger, objects.fileCollection(), - reportingSettings + reportingSettings, + visitedDependencies, + visitedFiles ).buildCompilerArgs() - args.freeArgs += cacheArgs - super.callCompilerAsync(args, sourceRoots, changedFiles) } override fun setupCompilerArgs(args: K2JSCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { @@ -116,10 +160,10 @@ abstract class KotlinJsIrLink @Inject constructor( } } - internal class CacheBuilder( private val buildDir: File, private val compileClasspath: Configuration, + private val additionalForResolve: FileCollection?, private val kotlinOptions: KotlinJsOptions, private val libraryFilter: (File) -> Boolean, private val compilerRunner: GradleCompilerRunner, @@ -127,42 +171,64 @@ internal class CacheBuilder( private val computedCompilerClasspath: List, private val logger: Logger, private val outputFiles: FileCollection, - private val reportingSettings: ReportingSettings + private val reportingSettings: ReportingSettings, + private val visitedDependencies: MutableSet, + private val visitedFiles: MutableSet ) { val rootCacheDirectory by lazy { buildDir.resolve("klib/cache") } - fun buildCompilerArgs(): List { - val visitedDependencies = mutableSetOf() - val allCacheDirectories = mutableSetOf() + fun buildCompilerArgs(): List { + + val allCacheDirectories = mutableListOf() compileClasspath.resolvedConfiguration.firstLevelModuleDependencies .forEach { dependency -> - ensureDependencyCached(dependency, visitedDependencies) + ensureDependencyCached( + dependency, + visitedDependencies, + visitedFiles + ) (listOf(dependency) + getAllDependencies(dependency)) .forEach { - val cacheDirectory = getCacheDirectory(rootCacheDirectory, dependency) + val cacheDirectory = getCacheDirectory(rootCacheDirectory, it) if (cacheDirectory.exists()) { - allCacheDirectories.add(cacheDirectory.normalize().absolutePath) + allCacheDirectories.add(cacheDirectory) } } } + additionalForResolve?.files?.forEach { file -> + val cacheDirectory = rootCacheDirectory.resolve(file.name) + cacheDirectory.mkdirs() + runCompiler( + file, + visitedFiles, + compileClasspath.files, + cacheDirectory, + allCacheDirectories, + + + file.name + ) + allCacheDirectories.add(cacheDirectory) + } + return allCacheDirectories - .map { "-Xcache-directory=${it}" } } private fun ensureDependencyCached( dependency: ResolvedDependency, - visitedDependency: MutableSet + visitedDependency: MutableSet, + visitedFiles: MutableSet ) { if (dependency in visitedDependency) return visitedDependency.add(dependency) dependency.children - .forEach { ensureDependencyCached(it, visitedDependency) } + .forEach { ensureDependencyCached(it, visitedDependency, visitedFiles) } val artifactsToAddToCache = dependency.moduleArtifacts .filter { libraryFilter(it.file) } @@ -178,49 +244,71 @@ internal class CacheBuilder( cacheDirectory.mkdirs() for (library in artifactsToAddToCache) { - val compilerArgs = compilerArgsFactory() - kotlinOptions.copyFreeCompilerArgsToArgs(compilerArgs) - compilerArgs.freeArgs = compilerArgs.freeArgs - .filterNot { arg -> - IGNORED_ARGS.any { - arg.startsWith(it) - } - } + runCompiler( + library.file, + visitedFiles, + getAllDependencies(dependency) + .flatMap { it.moduleArtifacts } + .map { it.file }, + cacheDirectory, + dependenciesCacheDirectories, - compilerArgs.includes = library.file.normalize().absolutePath - compilerArgs.outputFile = cacheDirectory.resolve("${library.name}.js").normalize().absolutePath - dependenciesCacheDirectories.forEach { - compilerArgs.freeArgs += "-Xcache-directory=${it.absolutePath}" + library.name + ) + } + } + + fun runCompiler( + file: File, + visitedFiles: MutableSet, + dependencies: Collection, + cacheDirectory: File, + dependenciesCacheDirectories: Collection, + + + jsName: String + ) { + if (file in visitedFiles) return + val compilerArgs = compilerArgsFactory() + kotlinOptions.copyFreeCompilerArgsToArgs(compilerArgs) + compilerArgs.freeArgs = compilerArgs.freeArgs + .filterNot { arg -> + IGNORED_ARGS.any { + arg.startsWith(it) + } } - // Change it for produce caches - compilerArgs.irProduceJs = true + visitedFiles.add(file) + compilerArgs.includes = file.normalize().absolutePath + compilerArgs.outputFile = cacheDirectory.resolve("${jsName}.js").normalize().absolutePath + compilerArgs.freeArgs += "-Xcache-directory=${dependenciesCacheDirectories.joinToString(File.pathSeparator)}" - compilerArgs.libraries = getAllDependencies(dependency) - .flatMap { it.moduleArtifacts } - .map { it.file } - .filter { it.exists() && libraryFilter(it) } - .distinct() - .joinToString(File.pathSeparator) { it.normalize().absolutePath } + // Change it for produce caches + compilerArgs.irProduceJs = true - val messageCollector = GradlePrintingMessageCollector(logger, false) - val outputItemCollector = OutputItemsCollectorImpl() - val environment = GradleCompilerEnvironment( - computedCompilerClasspath, - messageCollector, - outputItemCollector, - outputFiles = outputFiles, - reportingSettings = reportingSettings + compilerArgs.libraries = dependencies + .filter { it.exists() && libraryFilter(it) } + .distinct() + .filterNot { it == file } + .joinToString(File.pathSeparator) { it.normalize().absolutePath } + + val messageCollector = GradlePrintingMessageCollector(logger, false) + val outputItemCollector = OutputItemsCollectorImpl() + val environment = GradleCompilerEnvironment( + computedCompilerClasspath, + messageCollector, + outputItemCollector, + outputFiles = outputFiles, + reportingSettings = reportingSettings + ) + + compilerRunner + .runJsCompilerAsync( + emptyList(), + emptyList(), + compilerArgs, + environment ) - - compilerRunner - .runJsCompilerAsync( - emptyList(), - emptyList(), - compilerArgs, - environment - ) - } } companion object {