diff --git a/compiler/build-tools/kotlin-build-tools-api/api/kotlin-build-tools-api.api b/compiler/build-tools/kotlin-build-tools-api/api/kotlin-build-tools-api.api index 9f6ca1535f5..40dddca06ac 100644 --- a/compiler/build-tools/kotlin-build-tools-api/api/kotlin-build-tools-api.api +++ b/compiler/build-tools/kotlin-build-tools-api/api/kotlin-build-tools-api.api @@ -10,7 +10,8 @@ public final class org/jetbrains/kotlin/buildtools/api/CompilationResult : java/ public abstract interface class org/jetbrains/kotlin/buildtools/api/CompilationService { public static final field Companion Lorg/jetbrains/kotlin/buildtools/api/CompilationService$Companion; public abstract fun calculateClasspathSnapshot (Ljava/io/File;)Lorg/jetbrains/kotlin/buildtools/api/jvm/ClasspathEntrySnapshot; - public abstract fun compileJvm (Lorg/jetbrains/kotlin/buildtools/api/CompilerExecutionStrategyConfiguration;Lorg/jetbrains/kotlin/buildtools/api/jvm/JvmCompilationConfiguration;Ljava/util/List;Ljava/util/List;)Lorg/jetbrains/kotlin/buildtools/api/CompilationResult; + public abstract fun compileJvm (Lorg/jetbrains/kotlin/buildtools/api/ProjectId;Lorg/jetbrains/kotlin/buildtools/api/CompilerExecutionStrategyConfiguration;Lorg/jetbrains/kotlin/buildtools/api/jvm/JvmCompilationConfiguration;Ljava/util/List;Ljava/util/List;)Lorg/jetbrains/kotlin/buildtools/api/CompilationResult; + public abstract fun finishProjectCompilation (Lorg/jetbrains/kotlin/buildtools/api/ProjectId;)V public static fun loadImplementation (Ljava/lang/ClassLoader;)Lorg/jetbrains/kotlin/buildtools/api/CompilationService; public abstract fun makeCompilerExecutionStrategyConfiguration ()Lorg/jetbrains/kotlin/buildtools/api/CompilerExecutionStrategyConfiguration; public abstract fun makeJvmCompilationConfiguration ()Lorg/jetbrains/kotlin/buildtools/api/jvm/JvmCompilationConfiguration; @@ -46,6 +47,20 @@ public abstract interface class org/jetbrains/kotlin/buildtools/api/KotlinLogger public abstract fun warn (Ljava/lang/String;)V } +public abstract interface class org/jetbrains/kotlin/buildtools/api/ProjectId { +} + +public final class org/jetbrains/kotlin/buildtools/api/ProjectId$ProjectUUID : org/jetbrains/kotlin/buildtools/api/ProjectId { + public fun (Ljava/util/UUID;)V + public final fun component1 ()Ljava/util/UUID; + public final fun copy (Ljava/util/UUID;)Lorg/jetbrains/kotlin/buildtools/api/ProjectId$ProjectUUID; + public static synthetic fun copy$default (Lorg/jetbrains/kotlin/buildtools/api/ProjectId$ProjectUUID;Ljava/util/UUID;ILjava/lang/Object;)Lorg/jetbrains/kotlin/buildtools/api/ProjectId$ProjectUUID; + public fun equals (Ljava/lang/Object;)Z + public final fun getUuid ()Ljava/util/UUID; + public fun hashCode ()I + public fun toString ()Ljava/lang/String; +} + public final class org/jetbrains/kotlin/buildtools/api/SharedApiClassesClassLoader { public static final fun newInstance ()Ljava/lang/ClassLoader; } diff --git a/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/CompilationService.kt b/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/CompilationService.kt index c37c59c6bcb..231be161bf8 100644 --- a/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/CompilationService.kt +++ b/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/CompilationService.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.buildtools.api import org.jetbrains.kotlin.buildtools.api.jvm.ClasspathEntrySnapshot import org.jetbrains.kotlin.buildtools.api.jvm.JvmCompilationConfiguration import java.io.File +import java.util.* /** * A facade for invoking compilation and related stuff (such as [calculateClasspathSnapshot]) in Kotlin compiler. @@ -43,18 +44,31 @@ public interface CompilationService { /** * Compiles Kotlin code targeting JVM platform and using specified options. + * + * The [finishProjectCompilation] must be called with the same [projectId] after the entire project is compiled. + * @param projectId The unique identifier of the project to be compiled. It may be the same for different modules of the project. * @param strategyConfig an instance of [CompilerExecutionStrategyConfiguration] initially obtained from [makeCompilerExecutionStrategyConfiguration] * @param compilationConfig an instance of [JvmCompilationConfiguration] initially obtained from [makeJvmCompilationConfiguration] * @param sources a list of all sources of the compilation unit * @param arguments a list of Kotlin JVM compiler arguments */ public fun compileJvm( + projectId: ProjectId, strategyConfig: CompilerExecutionStrategyConfiguration, compilationConfig: JvmCompilationConfiguration, sources: List, arguments: List ): CompilationResult + /** + * A finalization function that must be called when all the modules of the project are compiled. + * + * May perform cache clean-ups and resource freeing. + * + * @param projectId The unique identifier of the compiled project. + */ + public fun finishProjectCompilation(projectId: ProjectId) + @ExperimentalBuildToolsApi public companion object { @JvmStatic diff --git a/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/ProjectId.kt b/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/ProjectId.kt new file mode 100644 index 00000000000..117e1b9bdfa --- /dev/null +++ b/compiler/build-tools/kotlin-build-tools-api/src/main/kotlin/org/jetbrains/kotlin/buildtools/api/ProjectId.kt @@ -0,0 +1,18 @@ +/* + * 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.buildtools.api + +import java.util.* + +/** + * Represents a unique identifier for a specific project. In this context, a "project" refers to the top-level entity + * or the main project itself, rather than a project's module. It's important to note that in certain build systems, + * like Gradle, the term "project" may be used to refer to individual modules. However, in this interface, we are + * explicitly using it to represent a complete project rather than its sub-modules. + */ +public sealed interface ProjectId { + public data class ProjectUUID(public val uuid: UUID) : ProjectId +} \ No newline at end of file diff --git a/compiler/build-tools/kotlin-build-tools-impl/src/main/kotlin/org/jetbrains/kotlin/buildtools/internal/CompilationServiceImpl.kt b/compiler/build-tools/kotlin-build-tools-impl/src/main/kotlin/org/jetbrains/kotlin/buildtools/internal/CompilationServiceImpl.kt index 7f59fdef6c2..ce688e9158f 100644 --- a/compiler/build-tools/kotlin-build-tools-impl/src/main/kotlin/org/jetbrains/kotlin/buildtools/internal/CompilationServiceImpl.kt +++ b/compiler/build-tools/kotlin-build-tools-impl/src/main/kotlin/org/jetbrains/kotlin/buildtools/internal/CompilationServiceImpl.kt @@ -5,10 +5,7 @@ package org.jetbrains.kotlin.buildtools.internal -import org.jetbrains.kotlin.buildtools.api.CompilationResult -import org.jetbrains.kotlin.buildtools.api.CompilationService -import org.jetbrains.kotlin.buildtools.api.CompilerArgumentsParseException -import org.jetbrains.kotlin.buildtools.api.CompilerExecutionStrategyConfiguration +import org.jetbrains.kotlin.buildtools.api.* import org.jetbrains.kotlin.buildtools.api.jvm.* import org.jetbrains.kotlin.cli.common.ExitCode import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments @@ -27,7 +24,7 @@ private val ExitCode.asCompilationResult else -> error("Unexpected exit code: $this") } -internal class CompilationServiceImpl : CompilationService { +internal object CompilationServiceImpl : CompilationService { override fun calculateClasspathSnapshot(classpathEntry: File): ClasspathEntrySnapshot { TODO("Calculating classpath snapshots via the Build Tools API is not yet implemented: KT-57565") } @@ -37,6 +34,7 @@ internal class CompilationServiceImpl : CompilationService { override fun makeJvmCompilationConfiguration() = JvmCompilationConfigurationImpl() override fun compileJvm( + projectId: ProjectId, strategyConfig: CompilerExecutionStrategyConfiguration, compilationConfig: JvmCompilationConfiguration, sources: List, @@ -55,6 +53,10 @@ internal class CompilationServiceImpl : CompilationService { } } + override fun finishProjectCompilation(projectId: ProjectId) { + + } + private fun compileInProcess( loggerAdapter: KotlinLoggerMessageCollectorAdapter, sources: List, @@ -70,4 +72,6 @@ internal class CompilationServiceImpl : CompilationService { loggerAdapter.report(CompilerMessageSeverity.INFO, arguments.toString()) return compiler.exec(loggerAdapter, Services.EMPTY, parsedArguments).asCompilationResult } -} \ No newline at end of file +} + +internal class CompilationServiceProxy : CompilationService by CompilationServiceImpl \ No newline at end of file diff --git a/compiler/build-tools/kotlin-build-tools-impl/src/main/resources/META-INF/services/org.jetbrains.kotlin.buildtools.api.CompilationService b/compiler/build-tools/kotlin-build-tools-impl/src/main/resources/META-INF/services/org.jetbrains.kotlin.buildtools.api.CompilationService index 015ff5725db..1a8b5fe2a1b 100644 --- a/compiler/build-tools/kotlin-build-tools-impl/src/main/resources/META-INF/services/org.jetbrains.kotlin.buildtools.api.CompilationService +++ b/compiler/build-tools/kotlin-build-tools-impl/src/main/resources/META-INF/services/org.jetbrains.kotlin.buildtools.api.CompilationService @@ -1 +1 @@ -org.jetbrains.kotlin.buildtools.internal.CompilationServiceImpl \ No newline at end of file +org.jetbrains.kotlin.buildtools.internal.CompilationServiceProxy \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index 6c6a6d1d58f..12d7f7647d9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -9,6 +9,7 @@ import org.gradle.api.Project import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logger import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.api.tasks.bundling.AbstractArchiveTask import org.gradle.api.tasks.bundling.Zip import org.gradle.jvm.tasks.Jar @@ -29,8 +30,10 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.internal.ClassLoadersCachingBuildService import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.logging.kotlinInfo +import org.jetbrains.kotlin.gradle.plugin.BuildFinishedListenerService import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion +import org.jetbrains.kotlin.gradle.plugin.internal.BuildIdService import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessor import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget @@ -60,7 +63,9 @@ internal fun createGradleCompilerRunner( buildMetricsReporter: BuildMetricsReporter, workerExecutor: WorkerExecutor, runViaBuildToolsApi: Boolean, - cachedClassLoadersService: Property + cachedClassLoadersService: Property, + buildFinishedListenerService: Provider, + buildIdService: Provider, ): GradleCompilerRunner { return if (runViaBuildToolsApi) { GradleBuildToolsApiCompilerRunner( @@ -70,6 +75,8 @@ internal fun createGradleCompilerRunner( buildMetricsReporter, workerExecutor, cachedClassLoadersService, + buildFinishedListenerService, + buildIdService, ) } else { GradleCompilerRunnerWithWorkers( diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/btapi/BuildToolsApiCompilationWork.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/btapi/BuildToolsApiCompilationWork.kt index dff3d5e7e38..236c3cc6519 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/btapi/BuildToolsApiCompilationWork.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/btapi/BuildToolsApiCompilationWork.kt @@ -21,15 +21,20 @@ import org.jetbrains.kotlin.gradle.internal.ClassLoadersCachingBuildService import org.jetbrains.kotlin.gradle.internal.ParentClassLoaderProvider import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.SL4JKotlinLogger +import org.jetbrains.kotlin.gradle.plugin.BuildFinishedListenerService +import org.jetbrains.kotlin.gradle.plugin.internal.BuildIdService import org.jetbrains.kotlin.gradle.plugin.internal.state.TaskLoggers import org.jetbrains.kotlin.gradle.tasks.KotlinCompilerExecutionStrategy import org.jetbrains.kotlin.gradle.tasks.throwExceptionIfCompilationFailed import org.slf4j.LoggerFactory import java.io.File +import java.util.* @OptIn(ExperimentalBuildToolsApi::class) internal abstract class BuildToolsApiCompilationWork : WorkAction { internal interface BuildToolsApiCompilationParameters : WorkParameters { + val buildIdService: Property + val buildFinishedListenerService: Property val classLoadersCachingService: Property val compilerWorkArguments: Property val taskOutputsToRestore: ListProperty @@ -64,6 +69,10 @@ internal abstract class BuildToolsApiCompilationWork : WorkAction TODO("The daemon strategy is not yet supported in the Build Tools API") @@ -73,6 +82,7 @@ internal abstract class BuildToolsApiCompilationWork : WorkAction, private val workerExecutor: WorkerExecutor, - private val cachedClassLoadersService: Provider + private val cachedClassLoadersService: Provider, + private val buildFinishedListenerService: Provider, + private val buildIdService: Provider, ) : GradleCompilerRunner(taskProvider, jdkToolsJar, compilerExecutionSettings, buildMetrics) { @@ -39,6 +43,8 @@ internal class GradleBuildToolsApiCompilerRunner( workQueue.submit(BuildToolsApiCompilationWork::class.java) { params -> params.compilerWorkArguments.set(workArgs) params.classLoadersCachingService.set(cachedClassLoadersService) + params.buildFinishedListenerService.set(buildFinishedListenerService) + params.buildIdService.set(buildIdService) if (taskOutputsBackup != null) { params.taskOutputsToRestore.set(taskOutputsBackup.outputsToRestore) params.buildDir.set(taskOutputsBackup.buildDirectory) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/BuildIdService.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/BuildIdService.kt new file mode 100644 index 00000000000..138a130b6de --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/internal/BuildIdService.kt @@ -0,0 +1,35 @@ +/* + * 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.plugin.internal + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.gradle.api.tasks.Internal +import org.jetbrains.kotlin.gradle.tasks.withType +import org.jetbrains.kotlin.gradle.utils.registerClassLoaderScopedBuildService +import java.util.* + +internal interface UsesBuildIdProviderService : Task { + @get:Internal + val buildIdService: Property +} + +internal abstract class BuildIdService : BuildService { + val buildId: UUID = UUID.randomUUID() + + companion object { + fun registerIfAbsent(project: Project): Provider = + project.gradle.registerClassLoaderScopedBuildService(BuildIdService::class).also { service -> + project.tasks.withType().configureEach { task -> + task.usesService(service) + } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/AbstractKotlinCompile.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/AbstractKotlinCompile.kt index 789485ec662..9e7ecb74c4a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/AbstractKotlinCompile.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/AbstractKotlinCompile.kt @@ -36,6 +36,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI import org.jetbrains.kotlin.gradle.plugin.UsesBuildFinishedListenerService import org.jetbrains.kotlin.gradle.plugin.UsesVariantImplementationFactories import org.jetbrains.kotlin.gradle.plugin.diagnostics.UsesKotlinToolingDiagnostics +import org.jetbrains.kotlin.gradle.plugin.internal.UsesBuildIdProviderService import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.report.* import org.jetbrains.kotlin.gradle.utils.* @@ -60,6 +61,7 @@ abstract class AbstractKotlinCompile @Inject constr UsesBuildFinishedListenerService, UsesClassLoadersCachingBuildService, UsesKotlinToolingDiagnostics, + UsesBuildIdProviderService, BaseKotlinCompile { init { @@ -188,6 +190,8 @@ abstract class AbstractKotlinCompile @Inject constr workerExecutor, runViaBuildToolsApi.get(), classLoadersCachingService, + buildFinishedListenerService, + buildIdService, ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt index e73f62b7ec1..5e468dc57cf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.gradle.internal.ClassLoadersCachingBuildService import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider +import org.jetbrains.kotlin.gradle.plugin.internal.BuildIdService import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithClosure @@ -69,6 +70,7 @@ internal abstract class AbstractKotlinCompileConfig val propertiesProvider = project.kotlinPropertiesProvider @@ -113,6 +115,7 @@ internal abstract class AbstractKotlinCompileConfig