From 46cb4902e1e71ae1f80f4a730524981c715fd09a Mon Sep 17 00:00:00 2001 From: Ivan Gavrilovic Date: Mon, 21 Feb 2022 11:47:35 +0000 Subject: [PATCH] [Gradle] Move more task inputs to properties ... move more configuration logic to TaskConfigAction classes. This is to avoid directly accessing tasks to configure them. The TaskConfigAction objects should eventually have access to all information that is required to configure the task, and they should compute the final values of all properties. This will also allow 3P plugins to configure Kotlin tasks, without the need to create KGP internal objects. ^KT-50869 In Progress --- .../gradle/plugin/KotlinGradleSubplugin.kt | 2 + .../kapt/Kapt3KotlinGradleSubplugin.kt | 450 ++++++------------ .../internal/kapt/KaptGenerateStubsTask.kt | 55 +-- .../kotlin/gradle/internal/kapt/KaptTask.kt | 69 +-- .../internal/kapt/KaptWithKotlincTask.kt | 29 +- .../internal/kapt/KaptWithoutKotlincTask.kt | 49 +- .../gradle/internal/tasks/TaskConfigurator.kt | 13 - .../gradle/model/builder/KaptModelBuilder.kt | 6 +- .../kotlin/gradle/plugin/KotlinPlugin.kt | 147 ++---- .../gradle/plugin/KotlinPluginWrapper.kt | 12 +- .../kotlin/gradle/plugin/KotlinProperties.kt | 31 -- .../gradle/plugin/RunOnceAfterEvaluated.kt | 11 +- .../gradle/plugin/SubpluginEnvironment.kt | 22 +- .../sources/DefaultLanguageSettingsBuilder.kt | 3 +- .../gradle/targets/js/ir/KotlinJsIrLink.kt | 27 +- .../gradle/tasks/CompilerPluginOptions.kt | 56 ++- .../gradle/tasks/KotlinCompileCommon.kt | 43 -- .../jetbrains/kotlin/gradle/tasks/Tasks.kt | 192 +------- .../kotlin/gradle/tasks/TasksProvider.kt | 115 +---- .../AbstractKotlinCompileConfig.kt | 131 +++++ .../gradle/tasks/configuration/KaptConfig.kt | 243 ++++++++++ .../configuration/KaptGenerateStubsConfig.kt | 67 +++ .../configuration/Kotlin2JsCompileConfig.kt | 42 ++ .../KotlinCompileCommonConfig.kt | 60 +++ .../configuration/KotlinCompileConfig.kt | 117 +++++ .../configuration/KotlinJsIrLinkConfig.kt | 25 + 26 files changed, 1060 insertions(+), 957 deletions(-) delete mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/tasks/TaskConfigurator.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileCommonConfig.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt create mode 100644 libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt diff --git a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt index a08b12a2727..1102b9afae0 100644 --- a/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin-api/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinGradleSubplugin.kt @@ -19,6 +19,7 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.provider.Provider +import org.gradle.api.tasks.Internal import java.io.File open class SubpluginOption(val key: String, private val lazyValue: Lazy) { @@ -64,6 +65,7 @@ open class InternalSubpluginOption(key: String, value: String) : SubpluginOption /** Keeps one or more compiler options for one of more compiler plugins. */ open class CompilerPluginConfig { + @get:Internal protected val optionsByPluginId = mutableMapOf>() fun allOptions(): Map> = optionsByPluginId diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 4c07f99dc65..8ad99d52390 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -9,13 +9,10 @@ import com.android.build.gradle.BaseExtension import com.android.build.gradle.api.AndroidSourceSet import com.android.build.gradle.api.BaseVariant import com.android.build.gradle.api.SourceKind -import com.intellij.openapi.util.SystemInfo -import com.intellij.util.lang.JavaVersion import org.gradle.api.Project import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.ExternalDependency -import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.Usage import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider @@ -24,21 +21,20 @@ import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile import org.gradle.process.CommandLineArgumentProvider import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry -import org.gradle.util.GradleVersion -import org.jetbrains.kotlin.gradle.dsl.kotlinExtension -import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE -import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformAction -import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isInfoAsWarnings +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptKeepKdocCommentsInStubs +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isKaptVerbose import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool +import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.tasks.configuration.* import org.jetbrains.kotlin.gradle.tasks.locateTask import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild -import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable import java.io.ByteArrayOutputStream import java.io.File import java.io.ObjectOutputStream @@ -53,17 +49,6 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To override fun apply(target: Project) { target.extensions.create("kapt", KaptExtension::class.java) - target.configurations.create(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply { - val kaptDependency = getPluginArtifact().run { "$groupId:$artifactId:${target.getKotlinPluginVersion()}" } - dependencies.add(target.dependencies.create(kaptDependency)) - dependencies.add( - target.kotlinDependency( - "kotlin-stdlib", - target.kotlinExtension.coreLibrariesVersion - ) - ) - } - registry.register(KaptModelBuilder()) } @@ -82,7 +67,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To const val KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME = "kotlinKaptWorkerDependencies" - private val KAPT_KOTLIN_GENERATED = "kapt.kotlin.generated" + val KAPT_KOTLIN_GENERATED = "kapt.kotlin.generated" private val CLASSLOADERS_CACHE_SIZE = "kapt.classloaders.cache.size" private val CLASSLOADERS_CACHE_DISABLE_FOR_PROCESSORS = "kapt.classloaders.cache.disableForProcessors" @@ -245,6 +230,8 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To private fun Kapt3SubpluginContext.getKaptIncrementalDataDir() = temporaryKaptDirectory("incrementalData") + private fun Kapt3SubpluginContext.getKaptClasspathSnapshotDir() = temporaryKaptDirectory("classpath-snapshot") + private fun Kapt3SubpluginContext.getKaptIncrementalAnnotationProcessingCache() = temporaryKaptDirectory("incApCache") private fun Kapt3SubpluginContext.temporaryKaptDirectory( @@ -326,7 +313,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To Callable { // Avoid circular dependency: the stubs task need the Java sources, but the Java sources generated by Kapt should be // excluded, as the Kapt tasks depend on the stubs ones, and having them in the input would lead to a cycle - val kaptJavaOutput = kaptTaskProvider.get().destinationDir + val kaptJavaOutput = kaptTaskProvider.get().destinationDir.get().asFile androidVariantData.getSourceFolders(SourceKind.JAVA).filter { it.dir != kaptJavaOutput } } ) @@ -343,42 +330,21 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To } // This method should be called no more than once for each Kapt3SubpluginContext - private fun Kapt3SubpluginContext.buildOptions( - aptMode: String, + private fun Kapt3SubpluginContext.buildOptionsForAptMode( javacOptions: Provider> ): Provider> { - disableAnnotationProcessingInJavaTask() - return project.provider { - val pluginOptions = mutableListOf() - - val generatedFilesDir = getKaptGeneratedSourcesDir(project, sourceSetName) - KaptWithAndroid.androidVariantData(this)?.addJavaSourceFoldersToModel(generatedFilesDir) - - pluginOptions += SubpluginOption("aptMode", aptMode) - - pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir)) - pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName))) - - pluginOptions += FilesSubpluginOption("incrementalData", listOf(getKaptIncrementalDataDir())) - - val annotationProcessors = kaptExtension.processors - if (annotationProcessors.isNotEmpty()) { - pluginOptions += SubpluginOption("processors", annotationProcessors) - } - - if (aptMode == "apt") { - // apOptions are needed only for "apt" mode - pluginOptions += getAPOptions().get() - } - - pluginOptions += SubpluginOption("javacArguments", encodeList(javacOptions.get())) - - pluginOptions += SubpluginOption("includeCompileClasspath", includeCompileClasspath.toString()) - - addMiscOptions(pluginOptions) - - pluginOptions + buildKaptSubpluginOptions( + kaptExtension, + project, + javacOptions.get(), + "apt", + generatedSourcesDir = listOf(sourcesOutputDir), + generatedClassesDir = listOf(getKaptGeneratedClassesDir(project, sourceSetName)), + incrementalDataDir = listOf(getKaptIncrementalDataDir()), + includeCompileClasspath = includeCompileClasspath, + kaptStubsDir = listOf(getKaptStubsDir()) + ) + getAPOptions().get() // apOptions are needed only for "apt" mode } } @@ -425,96 +391,14 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To FilesSubpluginOption(KAPT_KOTLIN_GENERATED, listOf(kotlinSourcesOutputDir)) } - private fun Kapt3SubpluginContext.registerSubpluginOptions( - taskProvider: TaskProvider<*>, - optionsProvider: Provider> - ) { - taskProvider.configure { taskInstance -> - val container = when (taskInstance) { - is KaptGenerateStubsTask -> taskInstance.pluginOptions - is KaptWithKotlincTask -> taskInstance.pluginOptions - is KaptWithoutKotlincTask -> taskInstance.processorOptions - else -> error("Unexpected task ${taskInstance.name} (${taskInstance.javaClass})") - } - - - val compilerPluginId = getCompilerPluginId() - - val options = optionsProvider.get() - - taskInstance.registerSubpluginOptionsAsInputs(compilerPluginId, options) - - for (option in options) { - container.addPluginArgument(compilerPluginId, option) - } - } - - // Also register all the subplugin options from the Kotlin task: - project.whenEvaluated { - taskProvider.configure { taskInstance -> - kotlinCompile.get().pluginOptions.subpluginOptionsByPluginId.forEach { (pluginId, options) -> - taskInstance.registerSubpluginOptionsAsInputs("kotlinCompile.$pluginId", options) - } - } - } - } - - private fun encodeList(options: Map): String { - val os = ByteArrayOutputStream() - val oos = ObjectOutputStream(os) - - oos.writeInt(options.size) - for ((key, value) in options.entries) { - oos.writeUTF(key) - oos.writeUTF(value) - } - - oos.flush() - return Base64.getEncoder().encodeToString(os.toByteArray()) - } - - private fun Kapt3SubpluginContext.addMiscOptions(pluginOptions: MutableList) { - if (kaptExtension.generateStubs) { - project.logger.warn("'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin") - } - - // These option names must match those defined in org.jetbrains.kotlin.kapt.cli.KaptCliOption. - pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}") - pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}") - pluginOptions += SubpluginOption("dumpDefaultParameterValues", "${kaptExtension.dumpDefaultParameterValues}") - pluginOptions += SubpluginOption("mapDiagnosticLocations", "${kaptExtension.mapDiagnosticLocations}") - pluginOptions += SubpluginOption( - "strictMode", // Currently doesn't match KaptCliOption.STRICT_MODE_OPTION, is it a typo introduced in https://github.com/JetBrains/kotlin/commit/c83581e6b8155c6d89da977be6e3cd4af30562e5? - "${kaptExtension.strictMode}" - ) - pluginOptions += SubpluginOption("stripMetadata", "${kaptExtension.stripMetadata}") - pluginOptions += SubpluginOption("keepKdocCommentsInStubs", "${project.isKaptKeepKdocCommentsInStubs()}") - pluginOptions += SubpluginOption("showProcessorStats", "${kaptExtension.showProcessorStats}") - pluginOptions += SubpluginOption("detectMemoryLeaks", kaptExtension.detectMemoryLeaks) - pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}") - pluginOptions += FilesSubpluginOption("stubs", listOf(getKaptStubsDir())) - - if (project.isKaptVerbose()) { - pluginOptions += SubpluginOption("verbose", "true") - } - } - private fun Kapt3SubpluginContext.createKaptKotlinTask(useWorkerApi: Boolean): TaskProvider { val taskClass = if (useWorkerApi) KaptWithoutKotlincTask::class.java else KaptWithKotlincTask::class.java val taskName = getKaptTaskName("kapt") - var classStructureIfIncremental: Configuration? = null - - if (project.isIncrementalKapt()) { - maybeRegisterTransform(project) - - classStructureIfIncremental = project.configurations.create("_classStructure${taskName}") - - // Wrap the `kotlinCompile.classpath` into a file collection, so that, if the classpath is represented by a configuration, - // the configuration is not extended (via extendsFrom, which normally happens when one configuration is _added_ into another) - // but is instead included as the (lazily) resolved files. This is needed because the class structure configuration doesn't have - // the attributes that are potentially needed to resolve dependencies on MPP modules, and the classpath configuration does. - project.dependencies.add(classStructureIfIncremental.name, project.files(project.provider { kotlinCompile.get().libraries })) + val taskConfigAction = if (taskClass == KaptWithoutKotlincTask::class.java ) { + KaptWithoutKotlincConfigAction(kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile, kaptExtension) + } else { + KaptWithKotlincConfigAction(kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile, kaptExtension) } val kaptClasspathConfiguration = project.configurations.create("kaptClasspath_$taskName") @@ -522,182 +406,97 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To it.isVisible = false it.isCanBeConsumed = false } - - val kaptTaskProvider = project.registerTask(taskName, taskClass, emptyList()) { kaptTask -> - kaptTask.useBuildCache = kaptExtension.useBuildCache - - val kotlinCompileTask = kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile - if (kaptTask is KaptWithoutKotlincTask) { - KaptWithoutKotlincTask.Configurator(kotlinCompileTask).configure(kaptTask) - } else { - KaptWithKotlincTask.Configurator(kotlinCompileTask).configure(kaptTask as KaptWithKotlincTask) - PropertiesProvider(project).mapKotlinDaemonProperties(kaptTask) - } - - kaptTask.stubsDir.set(getKaptStubsDir()) - - kaptTask.destinationDir = sourcesOutputDir - kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir - kaptTask.classesDir = classesOutputDir - kaptTask.includeCompileClasspath.set(includeCompileClasspath) - - kaptTask.isIncremental = project.isIncrementalKapt() - - if (kaptTask.isIncremental) { - kaptTask.incAptCache.fileValue(getKaptIncrementalAnnotationProcessingCache()).disallowChanges() - - kaptTask.classpathStructure.from( - classStructureIfIncremental!!.incoming.artifactView { viewConfig -> - viewConfig.attributes.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE) - }.files - ).disallowChanges() - - if (kaptTask is KaptWithKotlincTask) { - kaptTask.pluginOptions.addPluginArgument( - getCompilerPluginId(), - SubpluginOption( - "incrementalCache", - lazy { kaptTask.incAptCache.asFile.get().absolutePath } - ) - ) + taskConfigAction.configureTaskProvider { taskProvider -> + if (javaCompile != null) { + val androidVariantData = KaptWithAndroid.androidVariantData(this) + if (androidVariantData != null) { + KaptWithAndroid.registerGeneratedJavaSourceForAndroid(this, project, androidVariantData, taskProvider) + androidVariantData.addJavaSourceFoldersToModel(sourcesOutputDir) + } else { + registerGeneratedJavaSource(taskProvider, javaCompile) } + + disableAnnotationProcessingInJavaTask() } - kaptTask.kaptClasspath.from(kaptClasspathConfiguration).disallowChanges() - kaptTask.kaptExternalClasspath.from(kaptClasspathConfiguration.fileCollection { it is ExternalDependency }) - kaptTask.kaptClasspathConfigurationNames.value(kaptClasspathConfigurations.map { it.name }).disallowChanges() + kotlinCompilation.output.classesDirs.from(taskProvider.flatMap { it.classesDir }) + + kotlinCompilation.compileKotlinTaskProvider.configure { + (it as AbstractKotlinCompileTool<*>).setSource(sourcesOutputDir, kotlinSourcesOutputDir) + } + } + taskConfigAction.configureTask { task -> + task.stubsDir.set(getKaptStubsDir()) + task.destinationDir.set(sourcesOutputDir) + task.kotlinSourcesDestinationDir.set(kotlinSourcesOutputDir) + task.classesDir.set(classesOutputDir) + + if (javaCompile != null) { + task.defaultJavaSourceCompatibility.set(javaCompile.map { it.sourceCompatibility }) + } + + if (project.isIncrementalKapt()) { + task.incAptCache.fileValue(getKaptIncrementalAnnotationProcessingCache()).disallowChanges() + } + + task.kaptClasspath.from(kaptClasspathConfiguration).disallowChanges() + task.kaptExternalClasspath.from(kaptClasspathConfiguration.fileCollection { it is ExternalDependency }) + task.kaptClasspathConfigurationNames.value(kaptClasspathConfigurations.map { it.name }).disallowChanges() KaptWithAndroid.androidVariantData(this)?.annotationProcessorOptionProviders?.let { - kaptTask.annotationProcessorOptionProviders.add(it) + task.annotationProcessorOptionProviders.add(it) } - } - kotlinCompilation.output.classesDirs.from(kaptTaskProvider.map { it.classesDir }) - - kotlinCompilation.compileKotlinTaskProvider.configure { - (it as AbstractKotlinCompileTool<*>).setSource(sourcesOutputDir, kotlinSourcesOutputDir) - } - - if (javaCompile != null) { - val androidVariantData = KaptWithAndroid.androidVariantData(this) - if (androidVariantData != null) { - KaptWithAndroid.registerGeneratedJavaSourceForAndroid(this, project, androidVariantData, kaptTaskProvider) + val pluginOptions: Provider = if (taskClass == KaptWithKotlincTask::class.java) { + buildOptionsForAptMode(taskConfigAction.getJavaOptions(task.defaultJavaSourceCompatibility)) } else { - registerGeneratedJavaSource(kaptTaskProvider, javaCompile) + check(taskClass == KaptWithoutKotlincTask::class.java) + getDslKaptApOptions() + }.map { + val res = CompilerPluginOptions() + it.forEach { res.addPluginArgument(KAPT_SUBPLUGIN_ID, it) } + return@map res } + + task.kaptPluginOptions.add(pluginOptions) } - val dslJavacOptions: Provider> = project.provider { - kaptExtension.getJavacOptions().toMutableMap().also { result -> - if (javaCompile != null && "-source" !in result && "--source" !in result && "--release" !in result) { - val atLeast12Java = - if (isConfigurationCacheAvailable(project.gradle)) { - val currentJavaVersion = - JavaVersion.parse(project.providers.systemProperty("java.version").forUseAtConfigurationTime().get()) - currentJavaVersion.feature >= 12 - } else { - SystemInfo.isJavaVersionAtLeast(12, 0, 0) - } - val sourceOptionKey = if (atLeast12Java) { - "--source" - } else { - "-source" - } - result[sourceOptionKey] = javaCompile.get().sourceCompatibility - } + return if (taskClass == KaptWithoutKotlincTask::class.java) { + taskConfigAction as KaptWithoutKotlincConfigAction + project.registerTask(taskName, KaptWithoutKotlincTask::class.java, emptyList()).also { + taskConfigAction.execute(it) } - } - - if (KaptWithKotlincTask::class.java.isAssignableFrom(taskClass)) { - val subpluginOptions = buildOptions("apt", dslJavacOptions) - registerSubpluginOptions(kaptTaskProvider, subpluginOptions) - } - - if (taskClass == KaptWithoutKotlincTask::class.java) { - kaptTaskProvider.configure { - it as KaptWithoutKotlincTask - it.mapDiagnosticLocations = kaptExtension.mapDiagnosticLocations - it.annotationProcessorFqNames = kaptExtension.processors.split(',').filter { it.isNotEmpty() } - it.javacOptions = dslJavacOptions.get() - if (includeCompileClasspath && project.classLoadersCacheSize() > 0) { - project.logger.warn( - "ClassLoaders cache can't be enabled together with AP discovery in compilation classpath." - + "\nSet 'kapt.include.compile.classpath=false' to disable discovery" - ) - } else { - it.classLoadersCacheSize = project.classLoadersCacheSize() - } - it.disableClassloaderCacheForProcessors = project.disableClassloaderCacheForProcessors() + } else { + taskConfigAction as KaptWithKotlincConfigAction + project.registerTask(taskName, KaptWithKotlincTask::class.java, emptyList()).also { + taskConfigAction.execute(it) } - - val subpluginOptions = getDslKaptApOptions() - registerSubpluginOptions(kaptTaskProvider, subpluginOptions) - } - - kaptTaskProvider.configure { task -> - task.onlyIf { - it as KaptTask - it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty - } - } - - return kaptTaskProvider - } - - private fun maybeRegisterTransform(project: Project) { - if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) { - val transformActionClass = - if (GradleVersion.current() >= GradleVersion.version("5.4")) - StructureTransformAction::class.java - else - StructureTransformLegacyAction::class.java - project.dependencies.registerTransform(transformActionClass) { transformSpec -> - transformSpec.from.attribute(artifactType, "jar") - transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE) - } - - project.dependencies.registerTransform(transformActionClass) { transformSpec -> - transformSpec.from.attribute(artifactType, "directory") - transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE) - } - - project.extensions.extraProperties["KaptStructureTransformAdded"] = true } } private fun Kapt3SubpluginContext.createKaptGenerateStubsTask(): TaskProvider { - val properties = PropertiesProvider(project) val kaptTaskName = getKaptTaskName("kaptGenerateStubs") val kaptTaskProvider = project.registerTask(kaptTaskName) + val projectDir = project.projectDir - val configurator = KaptGenerateStubsTask.Configurator(kotlinCompile, kotlinCompilation, properties) - configurator.runAtConfigurationTime(kaptTaskProvider, project) - - kaptTaskProvider.configure { kaptTask -> - configurator.configure(kaptTask) - - kaptTask.stubsDir.set(getKaptStubsDir()) - kaptTask.destinationDirectory.set(getKaptIncrementalDataDir()) - kaptTask.generatedSourcesDirs = listOf(sourcesOutputDir, kotlinSourcesOutputDir) - - kaptTask.kaptClasspath.from(kaptClasspathConfigurations) - - properties.mapKotlinTaskProperties(kaptTask) - - if (!includeCompileClasspath) { - kaptTask.onlyIf { - !(it as KaptGenerateStubsTask).kaptClasspath.isEmpty - } - } + val taskConfig = KaptGenerateStubsConfig(kotlinCompilation, kotlinCompile) + taskConfig.configureTask { + it.stubsDir.set(getKaptStubsDir()) + it.destinationDirectory.set(getKaptIncrementalDataDir()) + it.exclude( + "${sourcesOutputDir.relativeTo(projectDir).path}/**", + "${kotlinSourcesOutputDir.relativeTo(projectDir).path}/**" + ) + it.kaptClasspath.from(kaptClasspathConfigurations) + it.classpathSnapshotProperties.classpathSnapshotDir.fileValue(getKaptClasspathSnapshotDir()) } + taskConfig.execute(kaptTaskProvider) + project.whenEvaluated { addCompilationSourcesToExternalCompileTask(kotlinCompilation, kaptTaskProvider) } - val subpluginOptions = buildOptions("stubs", project.provider { kaptExtension.getJavacOptions() }) - registerSubpluginOptions(kaptTaskProvider, subpluginOptions) - return kaptTaskProvider } @@ -741,7 +540,72 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To JetBrainsSubpluginArtifact(artifactId = KAPT_ARTIFACT_NAME) } -private val artifactType = Attribute.of("artifactType", String::class.java) +internal fun buildKaptSubpluginOptions( + kaptExtension: KaptExtension, + project: Project, + javacOptions: Map, + aptMode: String, + generatedSourcesDir: Iterable, + generatedClassesDir: Iterable, + incrementalDataDir: Iterable, + includeCompileClasspath: Boolean, + kaptStubsDir: Iterable, +): List { + if (kaptExtension.generateStubs) { + project.logger.warn("'kapt.generateStubs' is not used by the 'kotlin-kapt' plugin") + } + + val pluginOptions = mutableListOf() + + pluginOptions += SubpluginOption("aptMode", aptMode) + + pluginOptions += FilesSubpluginOption("sources", generatedSourcesDir) + pluginOptions += FilesSubpluginOption("classes", generatedClassesDir) + pluginOptions += FilesSubpluginOption("incrementalData", incrementalDataDir) + + val annotationProcessors = kaptExtension.processors + if (annotationProcessors.isNotEmpty()) { + pluginOptions += SubpluginOption("processors", annotationProcessors) + } + pluginOptions += SubpluginOption("javacArguments", encodeList(javacOptions)) + pluginOptions += SubpluginOption("includeCompileClasspath", includeCompileClasspath.toString()) + + // These option names must match those defined in org.jetbrains.kotlin.kapt.cli.KaptCliOption. + pluginOptions += SubpluginOption("useLightAnalysis", "${kaptExtension.useLightAnalysis}") + pluginOptions += SubpluginOption("correctErrorTypes", "${kaptExtension.correctErrorTypes}") + pluginOptions += SubpluginOption("dumpDefaultParameterValues", "${kaptExtension.dumpDefaultParameterValues}") + pluginOptions += SubpluginOption("mapDiagnosticLocations", "${kaptExtension.mapDiagnosticLocations}") + pluginOptions += SubpluginOption( + "strictMode", // Currently doesn't match KaptCliOption.STRICT_MODE_OPTION, is it a typo introduced in https://github.com/JetBrains/kotlin/commit/c83581e6b8155c6d89da977be6e3cd4af30562e5? + "${kaptExtension.strictMode}" + ) + pluginOptions += SubpluginOption("stripMetadata", "${kaptExtension.stripMetadata}") + pluginOptions += SubpluginOption("keepKdocCommentsInStubs", "${project.isKaptKeepKdocCommentsInStubs()}") + pluginOptions += SubpluginOption("showProcessorTimings", "${kaptExtension.showProcessorStats}") + pluginOptions += SubpluginOption("detectMemoryLeaks", kaptExtension.detectMemoryLeaks) + pluginOptions += SubpluginOption("infoAsWarnings", "${project.isInfoAsWarnings()}") + pluginOptions += FilesSubpluginOption("stubs", kaptStubsDir) + + if (project.isKaptVerbose()) { + pluginOptions += SubpluginOption("verbose", "true") + } + + return pluginOptions +} + +private fun encodeList(options: Map): String { + val os = ByteArrayOutputStream() + val oos = ObjectOutputStream(os) + + oos.writeInt(options.size) + for ((key, value) in options.entries) { + oos.writeUTF(key) + oos.writeUTF(value) + } + + oos.flush() + return Base64.getEncoder().encodeToString(os.toByteArray()) +} // Don't reference the BaseVariant type in the Kapt plugin signatures, as those type references will fail to link when there's no Android // Gradle plugin on the project's plugin classpath @@ -771,7 +635,7 @@ private object KaptWithAndroid { internal fun registerGeneratedJavaSource(kaptTask: TaskProvider, javaTaskProvider: TaskProvider) { javaTaskProvider.configure { javaTask -> - val generatedJavaSources = javaTask.project.fileTree(kaptTask.map { it.destinationDir }) + val generatedJavaSources = javaTask.project.fileTree(kaptTask.flatMap { it.destinationDir }) generatedJavaSources.include("**/*.java") javaTask.source(generatedJavaSources) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt index 11a1ecbd332..0b02e06c96d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt @@ -18,18 +18,18 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.file.* import org.gradle.api.model.ObjectFactory +import org.gradle.api.file.ConfigurableFileCollection +import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.Property -import org.gradle.api.provider.Provider import org.gradle.api.tasks.* import org.gradle.work.Incremental import org.gradle.work.NormalizeLineEndings import org.gradle.workers.WorkerExecutor import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptionsImpl -import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData -import org.jetbrains.kotlin.gradle.tasks.* +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.utils.isParentOf +import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions import org.jetbrains.kotlin.incremental.classpathAsList import org.jetbrains.kotlin.incremental.destinationAsFile import java.io.File @@ -45,38 +45,9 @@ abstract class KaptGenerateStubsTask @Inject constructor( objectFactory ) { - internal class Configurator( - private val kotlinCompileTaskProvider: TaskProvider, - kotlinCompilation: KotlinCompilationData<*>, - properties: PropertiesProvider - ) : KotlinCompile.Configurator(kotlinCompilation, properties) { - - override fun configure(task: KaptGenerateStubsTask) { - super.configure(task) - - val kotlinCompileTask = kotlinCompileTaskProvider.get() - val providerFactory = kotlinCompileTask.project.providers - task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges() - task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges() - task.libraries.from(kotlinCompileTask.libraries) - task.kotlinTaskPluginClasspath.from( - providerFactory.provider { kotlinCompileTask.pluginClasspath } - ) - task.compileKotlinArgumentsContributor.set( - providerFactory.provider { - kotlinCompileTask.compilerArgumentsContributor - } - ) - task.verbose.set(KaptTask.queryKaptVerboseProperty(task.project)) - } - } - @get:OutputDirectory abstract val stubsDir: DirectoryProperty - @get:Internal - lateinit var generatedSourcesDirs: List - @get:Internal("Not an input, just passed as kapt args. ") abstract val kaptClasspath: ConfigurableFileCollection @@ -84,11 +55,6 @@ abstract class KaptGenerateStubsTask @Inject constructor( @Input fun getIfKaptClasspathIsPresent() = !kaptClasspath.isEmpty - @get:NormalizeLineEndings - @get:Classpath - @Suppress("unused") - internal abstract val kotlinTaskPluginClasspath: ConfigurableFileCollection - @get:Input abstract val verbose: Property @@ -105,8 +71,7 @@ abstract class KaptGenerateStubsTask @Inject constructor( private fun File.isSourceRootAllowed(): Boolean = !destinationDirectory.get().asFile.isParentOf(this) && - !stubsDir.asFile.get().isParentOf(this) && - generatedSourcesDirs.none { it.isParentOf(this) } + !stubsDir.asFile.get().isParentOf(this) override fun skipCondition(): Boolean = sources.isEmpty && javaSources.isEmpty @@ -123,10 +88,10 @@ abstract class KaptGenerateStubsTask @Inject constructor( } @get:Internal - override val scriptSources: FileCollection = objectFactory.fileCollection() + abstract override val scriptSources: FileCollection @get:Internal - override val androidLayoutResources: FileCollection = objectFactory.fileCollection() + abstract override val androidLayoutResources: FileCollection override val incrementalProps: List get() = listOf( @@ -159,11 +124,11 @@ abstract class KaptGenerateStubsTask @Inject constructor( ) ) - val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath) - args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray() + val pluginOptionsWithKapt = pluginOptions.toSingleCompilerPluginOptions().withWrappedKaptOptions(withApClasspath = kaptClasspath) + args.pluginOptions = (pluginOptionsWithKapt.arguments).toTypedArray() args.verbose = verbose.get() args.classpathAsList = this.libraries.filter { it.exists() }.toList() args.destinationAsFile = this.destinationDirectory.get().asFile } -} \ No newline at end of file +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt index 7fb345a4609..414813a0f77 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt @@ -19,13 +19,11 @@ import org.jetbrains.kotlin.gradle.internal.kapt.incremental.ClasspathSnapshot import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptClasspathChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges import org.jetbrains.kotlin.gradle.internal.kapt.incremental.UnknownSnapshot -import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.utils.addToStdlib.cast import java.io.File -import java.util.concurrent.Callable import java.util.jar.JarFile import javax.inject.Inject @@ -36,30 +34,6 @@ abstract class KaptTask @Inject constructor( TaskWithLocalState, UsesKotlinJavaToolchain { - open class Configurator(protected val kotlinCompileTask: KotlinCompile) : TaskConfigurator { - override fun configure(task: T) { - val objectFactory = task.project.objects - - task.compilerClasspath.from({ kotlinCompileTask.defaultCompilerClasspath }) - task.classpath.from(kotlinCompileTask.libraries) - task.compiledSources.from( - kotlinCompileTask.destinationDirectory, - Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } } - ).disallowChanges() - task.sourceSetName.value(kotlinCompileTask.sourceSetName).disallowChanges() - task.localStateDirectories.from(Callable { task.incAptCache.orNull }).disallowChanges() - task.source.from( - objectFactory.fileCollection().from( - kotlinCompileTask.javaSources, - task.stubsDir - ).asFileTree - .matching { it.include("**/*.java") } - .filter { f -> task.isRootAllowed(f) } - ).disallowChanges() - task.verbose.set(queryKaptVerboseProperty(task.project)) - } - } - init { cacheOnlyIfEnabledForKotlin() @@ -95,6 +69,9 @@ abstract class KaptTask @Inject constructor( @get:InputFiles abstract val classpathStructure: ConfigurableFileCollection + @get:Internal + abstract val kaptPluginOptions: ListProperty + /** * Output directory that contains caches necessary to support incremental annotation processing. */ @@ -102,13 +79,14 @@ abstract class KaptTask @Inject constructor( abstract val incAptCache: DirectoryProperty @get:OutputDirectory - internal lateinit var classesDir: File + internal abstract val classesDir: DirectoryProperty @get:OutputDirectory - lateinit var destinationDir: File + abstract val destinationDir: DirectoryProperty + /** Used in the model builder only. */ @get:OutputDirectory - lateinit var kotlinSourcesDestinationDir: File + abstract val kotlinSourcesDestinationDir: DirectoryProperty @get:Nested internal val annotationProcessorOptionProviders: MutableList = mutableListOf() @@ -176,37 +154,8 @@ abstract class KaptTask @Inject constructor( @get:Input abstract val verbose: Property - private fun isRootAllowed(file: File): Boolean = - file.exists() && - !isAncestor(destinationDir, file) && - !isAncestor(classesDir, file) - - //Have to avoid using FileUtil because it is required system property reading that is not allowed for configuration cache - private fun isAncestor(dir: File, file: File): Boolean { - val path = file.canonicalPath - val prefix = dir.canonicalPath - val pathLength = path.length - val prefixLength = prefix.length - //TODO - val caseSensitive = true - return if (prefixLength == 0) { - true - } else if (prefixLength > pathLength) { - false - } else if (!path.regionMatches(0, prefix, 0, prefixLength, ignoreCase = !caseSensitive)) { - return false - } else if (pathLength == prefixLength) { - return true - } else { - val lastPrefixChar: Char = prefix.get(prefixLength - 1) - var slashOrSeparatorIdx = prefixLength - if (lastPrefixChar == '/' || lastPrefixChar == File.separatorChar) { - slashOrSeparatorIdx = prefixLength - 1 - } - val next1 = path[slashOrSeparatorIdx] - return !(next1 != '/' && next1 != File.separatorChar) - } - } + @get:Internal + abstract val defaultJavaSourceCompatibility: Property protected fun checkAnnotationProcessorClasspath() { if (!includeCompileClasspath.get()) return diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt index b109eb1898e..5b3593aa9eb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt @@ -35,21 +35,6 @@ abstract class KaptWithKotlincTask @Inject constructor( CompilerArgumentAwareWithInput, CompileUsingKotlinDaemonWithNormalization { - class Configurator(kotlinCompileTask: KotlinCompile): KaptTask.Configurator(kotlinCompileTask) { - override fun configure(task: KaptWithKotlincTask) { - super.configure(task) - task.pluginClasspath.from(kotlinCompileTask.pluginClasspath) - task.compileKotlinArgumentsContributor.set( - task.project.provider { kotlinCompileTask.compilerArgumentsContributor } - ) - task.javaPackagePrefix.set(task.project.provider { kotlinCompileTask.javaPackagePrefix }) - task.reportingSettings.set(task.project.provider { kotlinCompileTask.reportingSettings() }) - } - } - - @get:Internal - internal val pluginOptions = CompilerPluginOptions() - @get:NormalizeLineEndings @get:Classpath abstract val pluginClasspath: ConfigurableFileCollection @@ -59,6 +44,10 @@ abstract class KaptWithKotlincTask @Inject constructor( objectFactory.newInstance(project.gradle, this, project) ) + /** Used only as task input, actual values come from [compileKotlinArgumentsContributor]. */ + @get:Nested + internal abstract val additionalPluginOptionsAsInputs: ListProperty + override fun createCompilerArgs(): K2JVMCompilerArguments = K2JVMCompilerArguments() abstract override val kotlinDaemonJvmArguments: ListProperty @@ -74,8 +63,7 @@ abstract class KaptWithKotlincTask @Inject constructor( )) args.pluginClasspaths = pluginClasspath.toPathsArray() - - val pluginOptionsWithKapt: CompilerPluginOptions = pluginOptions.withWrappedKaptOptions( + val pluginOptionsWithKapt: CompilerPluginOptions = kaptPluginOptions.toSingleCompilerPluginOptions().withWrappedKaptOptions( withApClasspath = kaptClasspath, changedFiles = changedFiles, classpathChanges = classpathChanges, @@ -95,8 +83,11 @@ abstract class KaptWithKotlincTask @Inject constructor( private var classpathChanges: List = emptyList() private var processIncrementally = false - private val javaPackagePrefix = objectFactory.property(String::class.java) - private val reportingSettings = objectFactory.property(ReportingSettings::class.java) + @get:Internal + internal abstract val javaPackagePrefix: Property + + @get:Internal + internal abstract val reportingSettings: Property @TaskAction fun compile(inputChanges: InputChanges) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt index 73164095ac9..a395a8acc45 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithoutKotlincTask.kt @@ -9,6 +9,7 @@ import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.FileCollection import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.ProviderFactory import org.gradle.api.tasks.* @@ -20,13 +21,12 @@ import org.gradle.workers.IsolationMode import org.gradle.workers.WorkAction import org.gradle.workers.WorkParameters import org.gradle.workers.WorkerExecutor -import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.ClassLoadersCache import org.jetbrains.kotlin.gradle.internal.kapt.classloaders.rootOrSelf import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinAndroidPluginWrapper -import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast import org.jetbrains.kotlin.utils.PathUtil import org.slf4j.LoggerFactory @@ -42,16 +42,6 @@ abstract class KaptWithoutKotlincTask @Inject constructor( private val workerExecutor: WorkerExecutor ) : KaptTask(objectFactory) { - class Configurator(kotlinCompileTask: KotlinCompile): KaptTask.Configurator(kotlinCompileTask) { - override fun configure(task: KaptWithoutKotlincTask) { - super.configure(task) - task.addJdkClassesToClasspath.value( - task.project.providers.provider { task.project.plugins.none { it is AbstractKotlinAndroidPluginWrapper } } - ).disallowChanges() - task.kaptJars.from(task.project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)).disallowChanges() - } - } - @get:NormalizeLineEndings @get:Classpath abstract val kaptJars: ConfigurableFileCollection @@ -66,16 +56,13 @@ abstract class KaptWithoutKotlincTask @Inject constructor( var mapDiagnosticLocations: Boolean = false @get:Input - lateinit var annotationProcessorFqNames: List - - @get:Internal - internal val processorOptions = CompilerPluginOptions() + abstract val annotationProcessorFqNames: ListProperty @get:Input - lateinit var javacOptions: Map + abstract val javacOptions: MapProperty @get:Input - internal abstract val addJdkClassesToClasspath: Property + abstract val addJdkClassesToClasspath: Property @get:Internal internal val projectDir = project.projectDir @@ -84,11 +71,9 @@ abstract class KaptWithoutKotlincTask @Inject constructor( val kaptProcessJvmArgs: ListProperty = objectFactory.listProperty().convention(emptyList()) private fun getAnnotationProcessorOptions(): Map { - val options = processorOptions.subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID] ?: return emptyMap() - val result = mutableMapOf() - for (option in options) { - result[option.key] = option.value + kaptPluginOptions.toSingleCompilerPluginOptions().subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID]?.forEach { + result[it.key] = it.value } annotationProcessorOptionProviders.forEach { providers -> (providers as List<*>).forEach { provider -> @@ -104,6 +89,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor( @TaskAction fun compile(inputChanges: InputChanges) { logger.info("Running kapt annotation processing using the Gradle Worker API") + checkProcessorCachingSetup() checkAnnotationProcessorClasspath() val incrementalChanges = getIncrementalChanges(inputChanges) @@ -137,16 +123,16 @@ abstract class KaptWithoutKotlincTask @Inject constructor( incAptCache.orNull?.asFile, classpathChanges.toList(), - destinationDir, - classesDir, + destinationDir.get().asFile, + classesDir.get().asFile, stubsDir.asFile.get(), kaptClasspath.files.toList(), kaptExternalClasspath.files.toList(), - annotationProcessorFqNames, + annotationProcessorFqNames.get(), getAnnotationProcessorOptions(), - javacOptions, + javacOptions.get(), kaptFlagsForWorker, @@ -154,7 +140,7 @@ abstract class KaptWithoutKotlincTask @Inject constructor( ) // Skip annotation processing if no annotation processors were provided. - if (annotationProcessorFqNames.isEmpty() && kaptClasspath.isEmpty()) { + if (annotationProcessorFqNames.get().isEmpty() && kaptClasspath.isEmpty()) { logger.info("No annotation processors provided. Skip KAPT processing.") return } @@ -259,6 +245,15 @@ abstract class KaptWithoutKotlincTask @Inject constructor( ).run() } } + + private fun checkProcessorCachingSetup() { + if (includeCompileClasspath.get() && classLoadersCacheSize > 0) { + logger.warn( + "ClassLoaders cache can't be enabled together with AP discovery in compilation classpath." + + "\nSet 'kapt.include.compile.classpath=false' to disable discovery" + ) + } + } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/tasks/TaskConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/tasks/TaskConfigurator.kt deleted file mode 100644 index 21b291b4280..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/internal/tasks/TaskConfigurator.kt +++ /dev/null @@ -1,13 +0,0 @@ -/* - * Copyright 2010-2021 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.internal.tasks - -import org.gradle.api.Task - -/** Classes that participate in task configuration should implement this interface. */ -interface TaskConfigurator { - fun configure(task: T) -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt index cbc239538f1..8ad5fecd4f7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/model/builder/KaptModelBuilder.kt @@ -39,9 +39,9 @@ class KaptModelBuilder : ToolingModelBuilder { true ) ) KaptSourceSet.KaptSourceSetType.TEST else KaptSourceSet.KaptSourceSetType.PRODUCTION, - destinationDir, - kotlinSourcesDestinationDir, - classesDir + destinationDir.get().asFile, + kotlinSourcesDestinationDir.get().asFile, + classesDir.get().asFile ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt index 24613a54a16..112ec05c019 100755 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPlugin.kt @@ -36,11 +36,11 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin -import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode import org.jetbrains.kotlin.gradle.targets.js.ir.* import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget import org.jetbrains.kotlin.gradle.tasks.* import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.tasks.configuration.* import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.tooling.includeKotlinToolingMetadataInApk import org.jetbrains.kotlin.gradle.utils.* @@ -67,7 +67,7 @@ abstract class KotlinCompilationProcessor>( protected val project: Project get() = kotlinCompilation.project - protected val defaultKotlinDestinationDir: File + protected val defaultKotlinDestinationDir: Provider get() { val kotlinExt = project.topLevelExtension val targetSubDirectory = @@ -75,7 +75,7 @@ abstract class KotlinCompilationProcessor>( "" // In single-target projects, don't add the target name part to this path else kotlinCompilation.compilationClassifier?.let { "$it/" }.orEmpty() - return File(project.buildDir, "classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationPurpose}") + return project.layout.buildDirectory.dir("classes/kotlin/$targetSubDirectory${kotlinCompilation.compilationPurpose}") } } @@ -103,23 +103,10 @@ internal abstract class KotlinSourceSetProcessor>( } private fun prepareKotlinCompileTask(): TaskProvider = - registerKotlinCompileTask(register = ::doRegisterTask).also { task -> + doRegisterTask(project, kotlinCompilation.compileKotlinTaskName).also { task -> kotlinCompilation.output.classesDirs.from(task.flatMap { it.destinationDirectory }) } - protected fun registerKotlinCompileTask( - name: String = kotlinCompilation.compileKotlinTaskName, - register: (Project, String, (T) -> Unit) -> TaskProvider - ): TaskProvider { - logger.kotlinDebug("Creating kotlin compile task $name") - - return register(project, name) { - it.description = taskDescription - it.destinationDirectory.set(defaultKotlinDestinationDir) - it.libraries.from({ kotlinCompilation.compileDependencyFiles }) - } - } - override fun run() { addKotlinDirectoriesToJavaSourceSet() doTargetSpecificProcessing() @@ -165,7 +152,15 @@ internal abstract class KotlinSourceSetProcessor>( } } - protected abstract fun doRegisterTask(project: Project, taskName: String, configureAction: (T) -> (Unit)): TaskProvider + protected fun applyStandardTaskConfiguration(taskConfiguration: AbstractKotlinCompileConfig<*>) { + taskConfiguration.configureTask { + it.description = taskDescription + it.destinationDirectory.convention(defaultKotlinDestinationDir) + it.libraries.from({ kotlinCompilation.compileDependencyFiles }) + } + } + + protected abstract fun doRegisterTask(project: Project, taskName: String): TaskProvider } internal class Kotlin2JvmSourceSetProcessor( @@ -174,12 +169,11 @@ internal class Kotlin2JvmSourceSetProcessor( ) : KotlinSourceSetProcessor( tasksProvider, "Compiles the $kotlinCompilation.", kotlinCompilation ) { - override fun doRegisterTask( - project: Project, - taskName: String, - configureAction: (KotlinCompile) -> (Unit) - ): TaskProvider = - tasksProvider.registerKotlinJVMTask(project, taskName, kotlinCompilation, configureAction) + override fun doRegisterTask(project: Project, taskName: String): TaskProvider { + val configAction = KotlinCompileConfig(kotlinCompilation) + applyStandardTaskConfiguration(configAction) + return tasksProvider.registerKotlinJVMTask(project, taskName, kotlinCompilation.kotlinOptions, configAction) + } override fun doTargetSpecificProcessing() { ifKaptEnabled(project) { @@ -232,12 +226,11 @@ internal class Kotlin2JsSourceSetProcessor( taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.", kotlinCompilation = kotlinCompilation ) { - override fun doRegisterTask( - project: Project, - taskName: String, - configureAction: (Kotlin2JsCompile) -> (Unit) - ): TaskProvider = - tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation, configureAction) + override fun doRegisterTask(project: Project, taskName: String): TaskProvider { + val configAction = Kotlin2JsCompileConfig(kotlinCompilation) + applyStandardTaskConfiguration(configAction) + return tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation.kotlinOptions, configAction) + } override fun doTargetSpecificProcessing() { project.tasks.named(kotlinCompilation.compileAllTaskName).configure { @@ -298,27 +291,10 @@ internal class KotlinJsIrSourceSetProcessor( tasksProvider, taskDescription = "Compiles the Kotlin sources in $kotlinCompilation to JavaScript.", kotlinCompilation = kotlinCompilation ) { - override fun doRegisterTask( - project: Project, - taskName: String, - configureAction: (Kotlin2JsCompile) -> (Unit) - ): TaskProvider = - tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation, configureAction) - - private fun registerJsLink( - project: Project, - taskName: String, - mode: KotlinJsBinaryMode, - configureAction: (Kotlin2JsCompile) -> Unit - ): TaskProvider { - return tasksProvider.registerKotlinJsIrTask( - project, - taskName, - kotlinCompilation - ) { task -> - task.mode = mode - configureAction(task) - } + override fun doRegisterTask(project: Project, taskName: String): TaskProvider { + val configAction = Kotlin2JsCompileConfig(kotlinCompilation) + applyStandardTaskConfiguration(configAction) + return tasksProvider.registerKotlinJSTask(project, taskName, kotlinCompilation.kotlinOptions, configAction) } override fun doTargetSpecificProcessing() { @@ -331,14 +307,14 @@ internal class KotlinJsIrSourceSetProcessor( compilation.binaries .withType(JsIrBinary::class.java) .all { binary -> - registerKotlinCompileTask( - binary.linkTaskName - ) { project, name, action -> - registerJsLink(project, name, binary.mode) { compileTask -> - action(compileTask) - compileTask.dependsOn(kotlinTask) - } + val configAction = KotlinJsIrLinkConfig(compilation) + applyStandardTaskConfiguration(configAction) + configAction.configureTask { task -> + task.modeProperty.set(binary.mode) + task.dependsOn(kotlinTask) } + + tasksProvider.registerKotlinJsIrTask(project, binary.linkTaskName, configAction) } project.whenEvaluated { @@ -369,13 +345,11 @@ internal class KotlinCommonSourceSetProcessor( } } - // protected abstract fun doRegisterTask(project: Project, taskName: String, configureAction: (T) -> (Unit)): TaskHolder - override fun doRegisterTask( - project: Project, - taskName: String, - configureAction: (KotlinCompileCommon) -> (Unit) - ): TaskProvider = - tasksProvider.registerKotlinCommonTask(project, taskName, kotlinCompilation, configureAction) + override fun doRegisterTask(project: Project, taskName: String): TaskProvider { + val configAction = KotlinCompileCommonConfig(kotlinCompilation) + applyStandardTaskConfiguration(configAction) + return tasksProvider.registerKotlinCommonTask(project, taskName, kotlinCompilation.kotlinOptions, configAction) + } } internal abstract class AbstractKotlinPlugin( @@ -683,7 +657,7 @@ internal open class KotlinAndroidPlugin( companion object { const val MINIMAL_SUPPORTED_AGP_VERSION = "3.6.4" fun androidTargetHandler(): AbstractAndroidProjectHandler { - val tasksProvider = AndroidTasksProvider() + val tasksProvider = KotlinTasksProvider() if (androidPluginVersion != null) { if (compareVersionNumbers(androidPluginVersion, MINIMAL_SUPPORTED_AGP_VERSION) < 0) { @@ -957,15 +931,15 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationTool val defaultSourceSet = project.kotlinExtension.sourceSets.maybeCreate(compilation.defaultSourceSetName) - val kotlinTaskName = compilation.compileKotlinTaskName - - tasksProvider.registerKotlinJVMTask(project, kotlinTaskName, compilation) { - it.parentKotlinOptionsImpl.set(rootKotlinOptions) - + val configAction = KotlinCompileConfig(compilation) + configAction.configureTask { task -> + task.parentKotlinOptionsImpl.value(rootKotlinOptions).disallowChanges() + task.useModuleDetection.value(true).disallowChanges() // store kotlin classes in separate directory. They will serve as class-path to java compiler - it.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName")) - it.description = "Compiles the $variantDataName kotlin." + task.destinationDirectory.set(project.layout.buildDirectory.dir("tmp/kotlin-classes/$variantDataName")) + task.description = "Compiles the $variantDataName kotlin." } + tasksProvider.registerKotlinJVMTask(project, compilation.compileKotlinTaskName, compilation.kotlinOptions, configAction) // Register the source only after the task is created, because the task is required for that: compilation.source(defaultSourceSet) @@ -1026,33 +1000,6 @@ private fun SourceSet.clearJavaSrcDirs() { java.setSrcDirs(emptyList()) } -internal fun Task.registerSubpluginOptionsAsInputs(subpluginId: String, subpluginOptions: List) { - // There might be several options with the same key. We group them together - // and add an index to the Gradle input property name to resolve possible duplication: - val pluginOptionsGrouped = subpluginOptions.groupBy { it.key } - for ((optionKey, optionsGroup) in pluginOptionsGrouped) { - optionsGroup.forEachIndexed { index, option -> - val indexSuffix = if (optionsGroup.size > 1) ".$index" else "" - when (option) { - is InternalSubpluginOption -> Unit - - is CompositeSubpluginOption -> { - val subpluginIdWithWrapperKey = "$subpluginId.$optionKey$indexSuffix" - registerSubpluginOptionsAsInputs(subpluginIdWithWrapperKey, option.originalOptions) - } - - is FilesSubpluginOption -> when (option.kind) { - FilesOptionKind.INTERNAL -> Unit - }.run { /* exhaustive when */ } - - else -> { - inputs.property("$subpluginId." + option.key + indexSuffix, Callable { option.value }) - } - } - } - } -} - //copied from BasePlugin.getLocalVersion internal val androidPluginVersion by lazy { try { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt index 0f71006d85c..19bf15fa2ed 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinPluginWrapper.kt @@ -100,19 +100,13 @@ abstract class KotlinBasePluginWrapper : Plugin { KotlinGradleBuildServices.detectKotlinPluginLoadedInMultipleProjects(project, kotlinPluginVersion) - val buildMetricReporter = BuildMetricsReporterService.registerIfAbsent(project) - - buildMetricReporter?.also { BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it) } + BuildMetricsReporterService.registerIfAbsent(project)?.also { + BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it) + } HttpReportService.registerIfAbsent(project, kotlinPluginVersion) ?.also { BuildEventsListenerRegistryHolder.getInstance(project).listenerRegistry.onTaskCompletion(it) } - project.tasks.withType(AbstractKotlinCompile::class.java).configureEach { - if (buildMetricReporter != null) { - it.buildMetricsReporterService.set(buildMetricReporter) - } - } - project.createKotlinExtension(projectExtensionClass).apply { coreLibrariesVersion = kotlinPluginVersion diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt index adff6a254e8..86843f5876c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinProperties.kt @@ -36,37 +36,6 @@ import org.jetbrains.kotlin.statistics.metrics.StringMetrics import java.io.File import java.util.* -internal fun PropertiesProvider.mapKotlinTaskProperties(task: AbstractKotlinCompile<*>) { - if (task is KotlinCompile) { - incrementalJvm?.let { task.incremental = it } - usePreciseJavaTracking?.let { - task.usePreciseJavaTracking = it - } - task.classpathSnapshotProperties.useClasspathSnapshot.value(useClasspathSnapshot).disallowChanges() - useFir?.let { - if (it == true) { - task.kotlinOptions.useFir = true - } - } - task.jvmTargetValidationMode.set(jvmTargetValidationMode) - task.useKotlinAbiSnapshot.value(useKotlinAbiSnapshot).disallowChanges() - } - - if (task is Kotlin2JsCompile) { - incrementalJs?.let { task.incremental = it } - incrementalJsKlib?.let { task.incrementalJsKlib = it } - } -} - -internal fun PropertiesProvider.mapKotlinDaemonProperties(task: CompileUsingKotlinDaemon) { - kotlinDaemonJvmArgs?.let { - task.kotlinDaemonJvmArguments.set(it.split("\\s+".toRegex())) - } - if (!task.compilerExecutionStrategy.isPresent) { - task.compilerExecutionStrategy.set(kotlinCompilerExecutionStrategy) - } -} - internal class PropertiesProvider private constructor(private val project: Project) { private val localProperties: Properties by lazy { Properties().apply { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/RunOnceAfterEvaluated.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/RunOnceAfterEvaluated.kt index 00d24d97af3..c76bc8d817e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/RunOnceAfterEvaluated.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/RunOnceAfterEvaluated.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.plugin import org.gradle.api.Project import org.gradle.api.logging.Logging -import org.gradle.api.tasks.TaskProvider /** * This class encapsulated logic which should be invoked during not before the script evaluation is ready and @@ -45,14 +44,8 @@ internal class RunOnceAfterEvaluated(private val name: String, private val actio } } -internal fun Project.runOnceAfterEvaluated(name: String, task: TaskProvider<*>, action: () -> (Unit)) { +internal fun Project.runOnceAfterEvaluated(name: String, action: () -> (Unit)) { val runOnce = RunOnceAfterEvaluated(name, action) - runOnceAfterEvaluated(runOnce, task) -} - -internal fun Project.runOnceAfterEvaluated(runOnce: RunOnceAfterEvaluated, task: TaskProvider<*>) { whenEvaluated { runOnce.onEvaluated() } - task.configure { - runOnce.onConfigure() - } + runOnce.onConfigure() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/SubpluginEnvironment.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/SubpluginEnvironment.kt index db8a6e98ece..cb2fd707606 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/SubpluginEnvironment.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/SubpluginEnvironment.kt @@ -49,14 +49,20 @@ class SubpluginEnvironment( val subpluginOptionsProvider = subplugin.applyToCompilation(kotlinCompilation) val subpluginId = subplugin.getCompilerPluginId() + val compilerOptions = subpluginOptionsProvider.map { subpluginOptions -> + val options = CompilerPluginOptions() + subpluginOptions.forEach { opt -> + options.addPluginArgument(subpluginId, opt) + } + options + } val configureKotlinTask: (KotlinCompile<*>) -> Unit = { - val pluginOptions = it.getPluginOptions() - val subpluginOptions = subpluginOptionsProvider.get() - for (option in subpluginOptions) { - pluginOptions.addPluginArgument(subpluginId, option) + when (it) { + is AbstractKotlinCompile<*> -> it.pluginOptions.add(compilerOptions) + is KotlinNativeCompile -> it.compilerPluginOptions.addPluginArgument(compilerOptions.get()) + else -> error("Unexpected task ${it.name}, class: ${it.javaClass}") } - it.registerSubpluginOptionsAsInputs(subpluginId, subpluginOptions) } kotlinCompilation.compileKotlinTaskProvider.configure(configureKotlinTask) @@ -75,12 +81,6 @@ class SubpluginEnvironment( return appliedSubplugins } - private fun KotlinCompile<*>.getPluginOptions(): CompilerPluginOptions = when (this) { - is AbstractKotlinCompile<*> -> pluginOptions - is KotlinNativeCompile -> compilerPluginOptions - else -> error("Unexpected task ${this.name}, class: ${this.javaClass}") - } - private fun Project.addMavenDependency(configuration: String, artifact: SubpluginArtifact) { val artifactVersion = artifact.version ?: kotlinPluginVersion val mavenCoordinate = "${artifact.groupId}:${artifact.artifactId}:$artifactVersion" diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt index 8114880d02f..754d57ae36b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile +import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions import org.jetbrains.kotlin.project.model.LanguageSettings import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics import org.jetbrains.kotlin.statistics.metrics.StringMetrics @@ -76,7 +77,7 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { get() { val pluginOptionsTask = compilerPluginOptionsTask.value ?: return null return when (pluginOptionsTask) { - is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions + is AbstractKotlinCompile<*> -> pluginOptionsTask.pluginOptions.toSingleCompilerPluginOptions() is AbstractKotlinNativeCompile<*, *, *> -> pluginOptionsTask.compilerPluginOptions else -> error("Unexpected task: $pluginOptionsTask") }.arguments diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt index 96023af2e75..b6ad368c60f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrLink.kt @@ -5,11 +5,11 @@ package org.jetbrains.kotlin.gradle.targets.js.ir -import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.file.ProjectLayout import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property import org.gradle.api.tasks.* import org.gradle.work.NormalizeLineEndings import org.gradle.workers.WorkerExecutor @@ -46,18 +46,6 @@ abstract class KotlinJsIrLink @Inject constructor( workerExecutor ) { - class Configurator(compilation: KotlinCompilationData<*>) : Kotlin2JsCompile.Configurator(compilation) { - - override fun configure(task: KotlinJsIrLink) { - super.configure(task) - - task.entryModule.fileProvider( - (compilation as KotlinJsIrCompilation).output.classesDirs.elements.map { it.single().asFile } - ).disallowChanges() - task.destinationDirectory.fileProvider(task.outputFileProperty.map { it.parentFile }).disallowChanges() - } - } - init { // Not check sources, only klib module disallowSourceChanges() @@ -88,11 +76,16 @@ abstract class KotlinJsIrLink @Inject constructor( @get:Input val outputGranularity: KotlinJsIrOutputGranularity = propertiesProvider.jsIrOutputGranularity - // Link tasks are not affected by compiler plugin - override val pluginClasspath: ConfigurableFileCollection = project.objects.fileCollection() + @get:Internal + @get:Deprecated("Please use modeProperty instead.") + var mode: KotlinJsBinaryMode + get() = modeProperty.get() + set(value) { + modeProperty.set(value) + } - @Input - lateinit var mode: KotlinJsBinaryMode + @get:Input + internal abstract val modeProperty: Property private val buildDir = project.buildDir diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt index 7e847844ae2..824dd7a0991 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/CompilerPluginOptions.kt @@ -16,7 +16,10 @@ package org.jetbrains.kotlin.gradle.tasks -import org.jetbrains.kotlin.gradle.plugin.CompilerPluginConfig +import org.gradle.api.provider.ListProperty +import org.gradle.api.tasks.Input +import org.gradle.api.tasks.Internal +import org.jetbrains.kotlin.gradle.plugin.* class CompilerPluginOptions() : CompilerPluginConfig() { @@ -24,8 +27,10 @@ class CompilerPluginOptions() : CompilerPluginConfig() { copyOptionsFrom(options) } - val subpluginOptionsByPluginId = optionsByPluginId + @get:Internal + internal val subpluginOptionsByPluginId = optionsByPluginId + @get:Internal val arguments: List get() = optionsByPluginId.flatMap { (pluginId, subplubinOptions) -> subplubinOptions.map { option -> @@ -33,6 +38,10 @@ class CompilerPluginOptions() : CompilerPluginConfig() { } } + fun addPluginArgument(options: CompilerPluginOptions) { + copyOptionsFrom(options) + } + operator fun plus(options: CompilerPluginConfig?): CompilerPluginOptions { if (options == null) return this val newOptions = CompilerPluginOptions() @@ -42,9 +51,52 @@ class CompilerPluginOptions() : CompilerPluginConfig() { return newOptions } + @Input + fun getAsTaskInputArgs(): Map { + val result = mutableMapOf() + subpluginOptionsByPluginId.forEach { (id, subpluginOptions) -> + result += computeForSubpluginId(id, subpluginOptions) + } + return result + } + + private fun computeForSubpluginId(subpluginId: String, subpluginOptions: List): Map { + // There might be several options with the same key. We group them together + // and add an index to the Gradle input property name to resolve possible duplication: + val result = mutableMapOf() + val pluginOptionsGrouped = subpluginOptions.groupBy { it.key } + for ((optionKey, optionsGroup) in pluginOptionsGrouped) { + optionsGroup.forEachIndexed { index, option -> + val indexSuffix = if (optionsGroup.size > 1) ".$index" else "" + when (option) { + is InternalSubpluginOption -> return@forEachIndexed + + is CompositeSubpluginOption -> { + val subpluginIdWithWrapperKey = "$subpluginId.$optionKey$indexSuffix" + result += computeForSubpluginId(subpluginIdWithWrapperKey, option.originalOptions) + } + + is FilesSubpluginOption -> when (option.kind) { + FilesOptionKind.INTERNAL -> Unit + }.run { /* exhaustive when */ } + + else -> { + result["$subpluginId." + option.key + indexSuffix] = option.value + } + } + } + } + return result + } + private fun copyOptionsFrom(options: CompilerPluginConfig) { options.allOptions().forEach { entry -> optionsByPluginId[entry.key] = entry.value.toMutableList() } } +} + +internal fun ListProperty.toSingleCompilerPluginOptions(): CompilerPluginOptions { + val values = this.orNull ?: return CompilerPluginOptions() + return values.reduceOrNull(CompilerPluginOptions::plus) ?: CompilerPluginOptions() } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index 2dd0d5be53b..2ec062d9c5b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -16,7 +16,6 @@ package org.jetbrains.kotlin.gradle.tasks -import org.gradle.api.Project import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Provider @@ -32,13 +31,6 @@ import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector -import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet -import org.jetbrains.kotlin.gradle.plugin.KotlinTarget -import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.* -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.AbstractKotlinFragmentMetadataCompilationData -import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure import org.jetbrains.kotlin.gradle.utils.propertyWithConvention import java.io.File import javax.inject.Inject @@ -51,41 +43,6 @@ abstract class KotlinCompileCommon @Inject constructor( ) : AbstractKotlinCompile(objectFactory), KotlinCommonCompile { - class Configurator(compilation: KotlinCompilationData<*>) : AbstractKotlinCompile.Configurator(compilation) { - override fun configure(task: KotlinCompileCommon) { - super.configure(task) - task.refinesMetadataPaths.from(getRefinesMetadataPaths(task.project)).disallowChanges() - task.expectActualLinker - .value(task.project.provider { (compilation as? KotlinCommonCompilation)?.isKlibCompilation == true || compilation is KotlinMetadataCompilationData }) - .disallowChanges() - } - - private fun getRefinesMetadataPaths(project: Project): Provider> { - return project.provider { - when (compilation) { - is KotlinCompilation<*> -> { - val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet - val metadataTarget = compilation.owner as KotlinTarget - defaultKotlinSourceSet.dependsOnClosure - .mapNotNull { sourceSet -> metadataTarget.compilations.findByName(sourceSet.name)?.output?.classesDirs } - .flatten() - } - is AbstractKotlinFragmentMetadataCompilationData -> { - val fragment = compilation.fragment - project.files( - fragment.refinesClosure.map { - val compilation = compilation.metadataCompilationRegistry.getForFragmentOrNull(it) - ?: return@map project.files() - compilation.output.classesDirs - } - ) - } - else -> error("unexpected compilation type") - } - } - } - } - override val compilerRunner: Provider = objectFactory.propertyWithConvention( gradleCompileTaskProvider.map { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index a65e2a667b7..e35e8ff2d41 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -10,7 +10,6 @@ import org.gradle.api.DefaultTask import org.gradle.api.GradleException import org.gradle.api.Project import org.gradle.api.Task -import org.gradle.api.attributes.Attribute import org.gradle.api.file.* import org.gradle.api.invocation.Gradle import org.gradle.api.logging.Logger @@ -46,21 +45,17 @@ import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.incremental.* import org.jetbrains.kotlin.gradle.internal.* -import org.jetbrains.kotlin.gradle.internal.tasks.TaskConfigurator import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles -import org.jetbrains.kotlin.gradle.internal.transforms.ClasspathEntrySnapshotTransform import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.mpp.* -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.report.BuildMetricsReporterService import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.report.ReportingSettings -import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.incremental.* import org.jetbrains.kotlin.incremental.ClasspathChanges.ClasspathSnapshotDisabled @@ -261,42 +256,6 @@ abstract class AbstractKotlinCompile @Inject constr ) : AbstractKotlinCompileTool(objectFactory), CompileUsingKotlinDaemonWithNormalization { - open class Configurator>(protected val compilation: KotlinCompilationData<*>) : TaskConfigurator { - override fun configure(task: T) { - val project = task.project - task.friendPaths.from(project.provider { compilation.friendPaths }) - - if (compilation is KotlinCompilation<*>) { - task.friendSourceSets.set(project.provider { compilation.associateWithClosure.map { it.name } }) - // FIXME support compiler plugins with PM20 - task.pluginClasspath.from(project.configurations.getByName(compilation.pluginConfigurationName)) - } - task.moduleName.set(project.provider { compilation.moduleName }) - task.sourceSetName.set(project.provider { compilation.compilationPurpose }) - task.multiPlatformEnabled.value( - project.provider { - project.plugins.any { - it is KotlinPlatformPluginBase || - it is AbstractKotlinMultiplatformPluginWrapper || - it is AbstractKotlinPm20PluginWrapper - } - } - ).disallowChanges() - task.taskBuildCacheableOutputDirectory.value(getKotlinBuildDir(task).map { it.dir("cacheable") }).disallowChanges() - task.taskBuildLocalStateDirectory.value(getKotlinBuildDir(task).map { it.dir("local-state") }).disallowChanges() - - task.localStateDirectories.from(task.taskBuildLocalStateDirectory).disallowChanges() - - PropertiesProvider(task.project).mapKotlinDaemonProperties(task) - } - - private fun getKotlinBuildDir(task: T): Provider = - task.project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}") - - protected fun getClasspathSnapshotDir(task: T): Provider = - getKotlinBuildDir(task).map { it.dir("classpath-snapshot") } - } - init { cacheOnlyIfEnabledForKotlin() } @@ -312,7 +271,7 @@ abstract class AbstractKotlinCompile @Inject constr // avoid creating directory in getter: this can lead to failure in parallel build @get:LocalState - internal val taskBuildLocalStateDirectory: DirectoryProperty = objectFactory.directoryProperty() + internal abstract val taskBuildLocalStateDirectory: DirectoryProperty @get:Internal internal val buildHistoryFile @@ -342,7 +301,7 @@ abstract class AbstractKotlinCompile @Inject constr internal fun reportingSettings() = buildMetricsReporterService.orNull?.parameters?.reportingSettings ?: ReportingSettings() @get:Input - internal val useModuleDetection: Property = objectFactory.property(Boolean::class.java).value(false) + internal abstract val useModuleDetection: Property @get:Internal protected val multiModuleICSettings: MultiModuleICSettings @@ -350,10 +309,10 @@ abstract class AbstractKotlinCompile @Inject constr @get:NormalizeLineEndings @get:Classpath - open val pluginClasspath: ConfigurableFileCollection = objectFactory.fileCollection() + abstract val pluginClasspath: ConfigurableFileCollection - @get:Internal - internal val pluginOptions = CompilerPluginOptions() + @get:Nested + internal abstract val pluginOptions: ListProperty /** @@ -368,7 +327,7 @@ abstract class AbstractKotlinCompile @Inject constr internal val javaOutputDir: DirectoryProperty = objectFactory.directoryProperty() @get:Internal - internal val sourceSetName: Property = objectFactory.property(String::class.java) + internal abstract val sourceSetName: Property @get:InputFiles @get:IgnoreEmptyDirectories @@ -378,7 +337,7 @@ abstract class AbstractKotlinCompile @Inject constr internal val commonSourceSet: ConfigurableFileCollection = objectFactory.fileCollection() @get:Input - internal val moduleName: Property = objectFactory.property(String::class.java) + internal abstract val moduleName: Property @get:Internal val abiSnapshotFile @@ -394,12 +353,10 @@ abstract class AbstractKotlinCompile @Inject constr internal val friendSourceSets = objectFactory.listProperty(String::class.java) @get:Internal // takes part in the compiler arguments - val friendPaths: ConfigurableFileCollection = objectFactory.fileCollection() + abstract val friendPaths: ConfigurableFileCollection private val kotlinLogger by lazy { GradleKotlinLogger(logger) } - abstract override val kotlinDaemonJvmArguments: ListProperty - @get:Internal protected val gradleCompileTaskProvider: Provider = objectFactory .property( @@ -473,8 +430,6 @@ abstract class AbstractKotlinCompile @Inject constr protected open fun skipCondition(): Boolean = sources.isEmpty - private val projectDir = project.rootProject.projectDir - @get:Internal protected open val incrementalProps: List get() = listOfNotNull( @@ -489,7 +444,7 @@ abstract class AbstractKotlinCompile @Inject constr ) { val allKotlinSources = sources.asFileTree.files - logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(projectDir)}" } + logger.kotlinDebug { "All kotlin sources: ${allKotlinSources.pathsAsStringRelativeTo(gradleCompileTaskProvider.get().projectDir.get())}" } if (!inputChanges.isIncremental && skipCondition()) { // Skip running only if non-incremental run. Otherwise, we may need to do some cleanup. @@ -542,7 +497,7 @@ abstract class AbstractKotlinCompile @Inject constr ) @get:Input - internal val multiPlatformEnabled: Property = objectFactory.property(Boolean::class.java) + internal abstract val multiPlatformEnabled: Property @get:Internal internal val abstractKotlinCompileArgumentsContributor by lazy { @@ -568,8 +523,7 @@ open class KotlinCompileArgumentsProvider( - kotlinCompilation: KotlinCompilationData<*>, - private val properties: PropertiesProvider - ) : AbstractKotlinCompile.Configurator(kotlinCompilation) { - - companion object { - private const val TRANSFORMS_REGISTERED = "_kgp_internal_kotlin_compile_transforms_registered" - - val ARTIFACT_TYPE_ATTRIBUTE: Attribute = Attribute.of("artifactType", String::class.java) - private const val DIRECTORY_ARTIFACT_TYPE = "directory" - private const val JAR_ARTIFACT_TYPE = "jar" - const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot" - } - - /** - * Prepares for configuration of the task. This method must be called during build configuration, not during task configuration - * (which typically happens after build configuration). The reason is that some actions must be performed early (e.g., creating - * configurations should be done early to avoid issues with composite builds (https://issuetracker.google.com/183952598)). - */ - fun runAtConfigurationTime(taskProvider: TaskProvider, project: Project) { - if (properties.useClasspathSnapshot) { - registerTransformsOnce(project) - project.configurations.create(classpathSnapshotConfigurationName(taskProvider.name)).apply { - project.dependencies.add(name, project.files(project.provider { taskProvider.get().libraries })) - } - } - } - - private fun registerTransformsOnce(project: Project) { - if (project.extensions.extraProperties.has(TRANSFORMS_REGISTERED)) { - return - } - project.extensions.extraProperties[TRANSFORMS_REGISTERED] = true - - val buildMetricsReporterService = BuildMetricsReporterService.registerIfAbsent(project) - project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) { - it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, JAR_ARTIFACT_TYPE) - it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE) - it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir) - buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) } - } - project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) { - it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DIRECTORY_ARTIFACT_TYPE) - it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE) - it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir) - buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) } - } - } - - private fun classpathSnapshotConfigurationName(taskName: String) = "_kgp_internal_${taskName}_classpath_snapshot" - - override fun configure(task: T) { - super.configure(task) - - val compileJavaTaskProvider = when (compilation) { - is KotlinJvmCompilation -> compilation.compileJavaTaskProvider - is KotlinJvmAndroidCompilation -> compilation.compileJavaTaskProvider - is KotlinWithJavaCompilation -> compilation.compileJavaTaskProvider - else -> null - } - - if (compileJavaTaskProvider != null) { - task.associatedJavaCompileTaskTargetCompatibility.set( - compileJavaTaskProvider.map { it.targetCompatibility } - ) - task.associatedJavaCompileTaskSources.from( - compileJavaTaskProvider.map { javaTask -> - javaTask.source - } - ) - task.associatedJavaCompileTaskName.set( - compileJavaTaskProvider.map { it.name } - ) - } - task.moduleName.set(task.project.provider { - task.kotlinOptions.moduleName ?: task.parentKotlinOptionsImpl.orNull?.moduleName ?: compilation.moduleName - }) - - if (properties.useClasspathSnapshot) { - val classpathSnapshot = task.project.configurations.getByName(classpathSnapshotConfigurationName(task.name)) - task.classpathSnapshotProperties.classpathSnapshot.from( - classpathSnapshot.incoming.artifactView { - it.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE) - }.files - ) - val classpathSnapshotDir = getClasspathSnapshotDir(task) - task.classpathSnapshotProperties.classpathSnapshotDir.value(classpathSnapshotDir).disallowChanges() - } else { - task.classpathSnapshotProperties.classpath.from(task.project.provider { task.libraries }) - } - } - } - - @get:Internal - internal val parentKotlinOptionsImpl: Property = objectFactory.property(KotlinJvmOptions::class.java) + @get:Internal("Takes part in compiler args.") + internal abstract val parentKotlinOptionsImpl: Property /** A package prefix that is used for locating Java sources in a directory structure with non-full-depth packages. * @@ -1070,33 +931,6 @@ abstract class Kotlin2JsCompile @Inject constructor( incremental = true } - open class Configurator(compilation: KotlinCompilationData<*>) : - AbstractKotlinCompile.Configurator(compilation) { - - override fun configure(task: T) { - super.configure(task) - - task.outputFileProperty.value( - task.project.provider { - task.kotlinOptions.outputFile?.let(::File) - ?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}.js") - } - ).disallowChanges() - task.optionalOutputFile.fileProvider( - task.outputFileProperty.flatMap { outputFile -> - task.project.provider { - outputFile.takeUnless { task.kotlinOptions.isProduceUnzippedKlib() } - } - } - ).disallowChanges() - val libraryCacheService = task.project.rootProject.gradle.sharedServices.registerIfAbsent( - "${LibraryFilterCachingService::class.java.canonicalName}_${LibraryFilterCachingService::class.java.classLoader.hashCode()}", - LibraryFilterCachingService::class.java - ) {} - task.libraryCache.set(libraryCacheService).also { task.libraryCache.disallowChanges() } - } - } - internal abstract class LibraryFilterCachingService : BuildService, AutoCloseable { internal data class LibraryFilterCacheKey(val dependency: File, val irEnabled: Boolean, val preIrDisabled: Boolean) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt index 582e50b42f1..11df9600c01 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt @@ -21,12 +21,9 @@ import org.gradle.api.Task import org.gradle.api.UnknownTaskException import org.gradle.api.tasks.TaskCollection import org.gradle.api.tasks.TaskProvider -import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider -import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties -import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData -import org.jetbrains.kotlin.gradle.plugin.runOnceAfterEvaluated -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink +import org.jetbrains.kotlin.gradle.tasks.configuration.* /** * Registers the task with [name] and [type] and initialization script [body] @@ -92,114 +89,42 @@ internal inline fun Project.locateOrRegisterTask( internal open class KotlinTasksProvider { open fun registerKotlinJVMTask( - project: Project, - name: String, - compilation: KotlinCompilationData<*>, - configureAction: (KotlinCompile) -> (Unit) + project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: KotlinCompileConfig ): TaskProvider { - val properties = PropertiesProvider(project) - val kotlinCompile = project.registerTask( - name, - KotlinCompile::class.java, - constructorArgs = listOf(compilation.kotlinOptions) - ) - - val configurator = KotlinCompile.Configurator(compilation, properties) - configurator.runAtConfigurationTime(kotlinCompile, project) - - kotlinCompile.configure { - configureAction(it) - configurator.configure(it) + return project.registerTask(taskName, KotlinCompile::class.java, constructorArgs = listOf(kotlinOptions)).also { + configuration.execute(it) } - configure(kotlinCompile, project, properties, compilation) - - return kotlinCompile } fun registerKotlinJSTask( - project: Project, - name: String, - compilation: KotlinCompilationData<*>, - configureAction: (Kotlin2JsCompile) -> Unit + project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: Kotlin2JsCompileConfig ): TaskProvider { - val properties = PropertiesProvider(project) - val result = project.registerTask( - name, + return project.registerTask( + taskName, Kotlin2JsCompile::class.java, - constructorArgs = listOf(compilation.kotlinOptions) - ) { - configureAction(it) - Kotlin2JsCompile.Configurator(compilation).configure(it) + constructorArgs = listOf(kotlinOptions) + ).also { + configuration.execute(it) } - configure(result, project, properties, compilation) - return result } fun registerKotlinJsIrTask( - project: Project, - name: String, - compilation: KotlinCompilationData<*>, - configureAction: (KotlinJsIrLink) -> Unit + project: Project, taskName: String, configuration: KotlinJsIrLinkConfig ): TaskProvider { - val properties = PropertiesProvider(project) - val result = project.registerTask( - name, - KotlinJsIrLink::class.java - ) { - it.compilation = compilation - configureAction(it) - KotlinJsIrLink.Configurator(compilation).configure(it) + return project.registerTask(taskName, KotlinJsIrLink::class.java).also { + configuration.execute(it) } - configure(result, project, properties, compilation) - return result } fun registerKotlinCommonTask( - project: Project, - name: String, - compilation: KotlinCompilationData<*>, - configureAction: (KotlinCompileCommon) -> (Unit) + project: Project, taskName: String, kotlinOptions: KotlinCommonOptions, configuration: KotlinCompileCommonConfig ): TaskProvider { - val properties = PropertiesProvider(project) - val result = project.registerTask( - name, + return project.registerTask( + taskName, KotlinCompileCommon::class.java, - constructorArgs = listOf(compilation.kotlinOptions) - ) { - configureAction(it) - KotlinCompileCommon.Configurator(compilation).configure(it) - } - configure(result, project, properties, compilation) - return result - } - - open fun configure( - kotlinTaskHolder: TaskProvider>, - project: Project, - propertiesProvider: PropertiesProvider, - compilation: KotlinCompilationData<*> - ) { - project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) { - propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get()) - - applyLanguageSettingsToKotlinOptions( - compilation.languageSettings, - (kotlinTaskHolder.get() as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>).kotlinOptions - ) - } - } -} - -internal class AndroidTasksProvider : KotlinTasksProvider() { - override fun configure( - kotlinTaskHolder: TaskProvider>, - project: Project, - propertiesProvider: PropertiesProvider, - compilation: KotlinCompilationData<*> - ) { - super.configure(kotlinTaskHolder, project, propertiesProvider, compilation) - kotlinTaskHolder.configure { - it.useModuleDetection.set(true) + constructorArgs = listOf(kotlinOptions) + ).also { + configuration.execute(it) } } } 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 new file mode 100644 index 00000000000..e14b187b4e8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt @@ -0,0 +1,131 @@ +/* + * Copyright 2010-2021 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.tasks.configuration + +import org.gradle.api.Project +import org.gradle.api.Task +import org.gradle.api.file.Directory +import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Provider +import org.gradle.api.provider.ProviderFactory +import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.gradle.dsl.topLevelExtension +import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider +import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithClosure +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData +import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinOptions +import org.jetbrains.kotlin.gradle.report.BuildMetricsReporterService +import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile +import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME +import java.util.concurrent.Callable + +/** + * Configuration for the base compile task, [org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile]. + * + * This contains all data necessary to configure the tasks, and should avoid exposing global state (project, extensions, other tasks) + * to the task instance as much as possible. + */ +internal abstract class AbstractKotlinCompileConfig>( + project: Project, +) : TaskConfigAction(project) { + + constructor(compilation: KotlinCompilationData<*>) : this(compilation.project) { + val ext = compilation.project.topLevelExtension + + configureTaskProvider { taskProvider -> + project.runOnceAfterEvaluated("apply properties and language settings to ${taskProvider.name}") { + taskProvider.configure { + applyLanguageSettingsToKotlinOptions( + compilation.languageSettings, (it as org.jetbrains.kotlin.gradle.dsl.KotlinCompile<*>).kotlinOptions + ) + } + } + } + + configureTask { task -> + task.friendPaths.from({ compilation.friendPaths }) + if (compilation is KotlinCompilation<*>) { + task.friendSourceSets.value(providers.provider { compilation.associateWithClosure.map { it.name } }) + .disallowChanges() + task.pluginClasspath.from(compilation.project.configurations.getByName(compilation.pluginConfigurationName)) + } + task.moduleName.set(providers.provider { compilation.moduleName }) + task.sourceSetName.value(providers.provider { compilation.compilationPurpose }) + task.multiPlatformEnabled.value( + providers.provider { + compilation.project.plugins.any { + it is KotlinPlatformPluginBase || + it is AbstractKotlinMultiplatformPluginWrapper || + it is AbstractKotlinPm20PluginWrapper + } + } + ) + val propertiesProvider = project.kotlinPropertiesProvider + + task.taskBuildCacheableOutputDirectory + .value(getKotlinBuildDir(task).map { it.dir("cacheable") }) + .disallowChanges() + task.taskBuildLocalStateDirectory + .value(getKotlinBuildDir(task).map { it.dir("local-state") }) + .disallowChanges() + + task.localStateDirectories.from(task.taskBuildLocalStateDirectory).disallowChanges() + BuildMetricsReporterService.registerIfAbsent(project)?.let { + task.buildMetricsReporterService.value(it) + } + + propertiesProvider.kotlinDaemonJvmArgs?.let { kotlinDaemonJvmArgs -> + task.kotlinDaemonJvmArguments.set(providers.provider { + kotlinDaemonJvmArgs.split("\\s+".toRegex()) + }) + } + task.compilerExecutionStrategy.value(propertiesProvider.kotlinCompilerExecutionStrategy) + + // Default values + task.incremental = false + task.useModuleDetection.convention(false) + } + } + + private fun getKotlinBuildDir(task: TASK): Provider = + task.project.layout.buildDirectory.dir("$KOTLIN_BUILD_DIR_NAME/${task.name}") + + protected fun getClasspathSnapshotDir(task: TASK): Provider = + getKotlinBuildDir(task).map { it.dir("classpath-snapshot") } +} + +internal abstract class TaskConfigAction(protected val project: Project) { + + protected val objectFactory: ObjectFactory = project.objects + protected val providers: ProviderFactory = project.providers + protected val propertiesProvider = project.kotlinPropertiesProvider + + private var executed = false + + // Collect all task configurations, and run them later (in order they were added). + private val taskConfigActions = ArrayDeque<(TaskProvider) -> Unit>() + + fun configureTaskProvider(configAction: (TaskProvider) -> Unit) { + check(!executed) { + "Task has already been configured. Configuration actions should be added to this object before `this.execute` method runs." + } + taskConfigActions.addLast(configAction) + } + + fun configureTask(configAction: (TASK) -> Unit) { + configureTaskProvider { taskProvider -> + taskProvider.configure(configAction) + } + } + + fun execute(taskProvider: TaskProvider) { + executed = true + taskConfigActions.forEach { + it(taskProvider) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt new file mode 100644 index 00000000000..57b2041f67a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptConfig.kt @@ -0,0 +1,243 @@ +/* + * Copyright 2010-2021 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. + */ + +@file:Suppress("MemberVisibilityCanBePrivate") + +package org.jetbrains.kotlin.gradle.tasks.configuration + +import com.intellij.openapi.util.SystemInfo +import com.intellij.util.lang.JavaVersion +import org.gradle.api.Project +import org.gradle.api.attributes.Attribute +import org.gradle.api.file.FileCollection +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.TaskProvider +import org.gradle.util.GradleVersion +import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension +import org.jetbrains.kotlin.gradle.dsl.topLevelExtension +import org.jetbrains.kotlin.gradle.internal.* +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_SUBPLUGIN_ID +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.classLoadersCacheSize +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.disableClassloaderCacheForProcessors +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isIncludeCompileClasspath +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isIncrementalKapt +import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE +import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformAction +import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureTransformLegacyAction +import org.jetbrains.kotlin.gradle.plugin.AbstractKotlinAndroidPluginWrapper +import org.jetbrains.kotlin.gradle.plugin.KaptExtension +import org.jetbrains.kotlin.gradle.plugin.SubpluginOption +import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion +import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.utils.isConfigurationCacheAvailable +import org.jetbrains.kotlin.gradle.utils.listProperty +import java.io.File +import java.util.concurrent.Callable + +internal open class KaptConfigAction( + project: Project, + protected val ext: KaptExtension, +) : TaskConfigAction(project) { + + internal constructor(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : this(kotlinCompileTask.project, ext) { + configureTaskProvider { taskProvider -> + val kaptClasspathSnapshot = getKaptClasspathSnapshot(taskProvider) + + taskProvider.configure { task -> + task.classpath.from(kotlinCompileTask.libraries) + task.compiledSources.from( + kotlinCompileTask.destinationDirectory, + Callable { kotlinCompileTask.javaOutputDir.takeIf { it.isPresent } }) + .disallowChanges() + task.sourceSetName.value(kotlinCompileTask.sourceSetName).disallowChanges() + + val kaptSources = objectFactory + .fileCollection() + .from(kotlinCompileTask.javaSources, task.stubsDir) + .asFileTree + .matching { it.include("**/*.java") } + .filter { + it.exists() && + !isAncestor(task.destinationDir.get().asFile, it) && + !isAncestor(task.classesDir.get().asFile, it) + } + task.source.from(kaptSources).disallowChanges() + task.verbose.set(KaptTask.queryKaptVerboseProperty(project)) + task.compilerClasspath.from(providers.provider { kotlinCompileTask.defaultCompilerClasspath }) + + task.isIncremental = project.isIncrementalKapt() + task.useBuildCache = ext.useBuildCache + + task.includeCompileClasspath.set(ext.includeCompileClasspath ?: project.isIncludeCompileClasspath()) + task.classpathStructure.from(kaptClasspathSnapshot) + + task.localStateDirectories.from(Callable { task.incAptCache.orNull }) + task.onlyIf { + it as KaptTask + it.includeCompileClasspath.get() || !it.kaptClasspath.isEmpty + } + } + } + } + + private fun getKaptClasspathSnapshot(taskProvider: TaskProvider): FileCollection? { + return if (project.isIncrementalKapt()) { + maybeRegisterTransform(project) + + val classStructureConfiguration = project.configurations.detachedConfiguration() + + // Wrap the `kotlinCompile.classpath` into a file collection, so that, if the classpath is represented by a configuration, + // the configuration is not extended (via extendsFrom, which normally happens when one configuration is _added_ into another) + // but is instead included as the (lazily) resolved files. This is needed because the class structure configuration doesn't have + // the attributes that are potentially needed to resolve dependencies on MPP modules, and the classpath configuration does. + classStructureConfiguration.dependencies.add(project.dependencies.create(project.files(project.provider { taskProvider.get().classpath }))) + classStructureConfiguration.incoming.artifactView { viewConfig -> + viewConfig.attributes.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE) + }.files + } else null + } + + private fun maybeRegisterTransform(project: Project) { + if (!project.extensions.extraProperties.has("KaptStructureTransformAdded")) { + val transformActionClass = + if (GradleVersion.current() >= GradleVersion.version("5.4")) + StructureTransformAction::class.java + else + StructureTransformLegacyAction::class.java + project.dependencies.registerTransform(transformActionClass) { transformSpec -> + transformSpec.from.attribute(artifactType, "jar") + transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE) + } + + project.dependencies.registerTransform(transformActionClass) { transformSpec -> + transformSpec.from.attribute(artifactType, "directory") + transformSpec.to.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE) + } + + project.extensions.extraProperties["KaptStructureTransformAdded"] = true + } + } + + internal fun getJavaOptions(defaultJavaSourceCompatibility: Provider): Provider> { + return providers.provider { + ext.getJavacOptions().toMutableMap().also { result -> + if ("-source" in result || "--source" in result || "--release" in result) return@also + + if (defaultJavaSourceCompatibility.isPresent) { + val atLeast12Java = + if (isConfigurationCacheAvailable(project.gradle)) { + val currentJavaVersion = + JavaVersion.parse(project.providers.systemProperty("java.version").forUseAtConfigurationTime().get()) + currentJavaVersion.feature >= 12 + } else { + SystemInfo.isJavaVersionAtLeast(12, 0, 0) + } + val sourceOptionKey = if (atLeast12Java) { + "--source" + } else { + "-source" + } + result[sourceOptionKey] = defaultJavaSourceCompatibility.get() + } + } + } + } +} + +//Have to avoid using FileUtil because it is required system property reading that is not allowed for configuration cache +private fun isAncestor(dir: File, file: File): Boolean { + val path = file.canonicalPath + val prefix = dir.canonicalPath + val pathLength = path.length + val prefixLength = prefix.length + val caseSensitive = true + return if (prefixLength == 0) { + true + } else if (prefixLength > pathLength) { + false + } else if (!path.regionMatches(0, prefix, 0, prefixLength, ignoreCase = !caseSensitive)) { + return false + } else if (pathLength == prefixLength) { + return true + } else { + val lastPrefixChar: Char = prefix.get(prefixLength - 1) + var slashOrSeparatorIdx = prefixLength + if (lastPrefixChar == '/' || lastPrefixChar == File.separatorChar) { + slashOrSeparatorIdx = prefixLength - 1 + } + val next1 = path[slashOrSeparatorIdx] + return !(next1 != '/' && next1 != File.separatorChar) + } +} + +internal class KaptWithoutKotlincConfigAction(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : + KaptConfigAction(kotlinCompileTask, ext) { + + init { + initKaptWorkersConfiguration(project.topLevelExtension) + + configureTask { task -> + task.addJdkClassesToClasspath.set( + project.providers.provider { + project.plugins.none { it is AbstractKotlinAndroidPluginWrapper } + } + ) + task.kaptJars.from(project.configurations.getByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME)) + task.mapDiagnosticLocations = ext.mapDiagnosticLocations + task.annotationProcessorFqNames.set(providers.provider { ext.processors.split(',').filter { it.isNotEmpty() } }) + task.disableClassloaderCacheForProcessors = project.disableClassloaderCacheForProcessors() + task.classLoadersCacheSize = project.classLoadersCacheSize() + task.javacOptions.set(getJavaOptions(task.defaultJavaSourceCompatibility)) + } + } + + private fun initKaptWorkersConfiguration(kotlinExt: KotlinTopLevelExtension) { + project.configurations.findByName(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME) + ?: project.configurations.create(Kapt3GradleSubplugin.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply { + dependencies.addAllLater(project.listProperty { + val kaptDependency = "org.jetbrains.kotlin:kotlin-annotation-processing-gradle:${project.getKotlinPluginVersion()}" + listOf( + project.dependencies.create(kaptDependency), + project.kotlinDependency( + "kotlin-stdlib", + kotlinExt.coreLibrariesVersion + ) + ) + }) + } + } +} + +internal class KaptWithKotlincConfigAction(kotlinCompileTask: KotlinCompile, ext: KaptExtension) : + KaptConfigAction(kotlinCompileTask, ext) { + + init { + configureTask { task -> + if (project.isIncrementalKapt()) { + val incAptCacheOption = task.incAptCache.locationOnly.map { incAptCacheDir -> + CompilerPluginOptions().also { + it.addPluginArgument( + KAPT_SUBPLUGIN_ID, SubpluginOption("incrementalCache", lazy { incAptCacheDir.asFile.absolutePath }) + ) + } + } + task.kaptPluginOptions.add(incAptCacheOption) + } + + task.pluginClasspath.from(kotlinCompileTask.pluginClasspath) + task.additionalPluginOptionsAsInputs.value(kotlinCompileTask.pluginOptions).disallowChanges() + task.compileKotlinArgumentsContributor.set(providers.provider { kotlinCompileTask.compilerArgumentsContributor }) + task.javaPackagePrefix.set(providers.provider { kotlinCompileTask.javaPackagePrefix }) + task.reportingSettings.set(providers.provider { kotlinCompileTask.reportingSettings() }) + propertiesProvider.kotlinDaemonJvmArgs?.let { + task.kotlinDaemonJvmArguments.value(it.split("\\s+".toRegex())).disallowChanges() + } + task.compilerExecutionStrategy.value(propertiesProvider.kotlinCompilerExecutionStrategy).disallowChanges() + } + } +} + +private val artifactType = Attribute.of("artifactType", String::class.java) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt new file mode 100644 index 00000000000..c3fd73a9c5e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KaptGenerateStubsConfig.kt @@ -0,0 +1,67 @@ +/* + * Copyright 2010-2021 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.tasks.configuration + +import org.gradle.api.provider.Provider +import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_SUBPLUGIN_ID +import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.isIncludeCompileClasspath +import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask +import org.jetbrains.kotlin.gradle.internal.KaptTask +import org.jetbrains.kotlin.gradle.internal.buildKaptSubpluginOptions +import org.jetbrains.kotlin.gradle.plugin.KaptExtension +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData +import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import java.util.concurrent.Callable + +internal class KaptGenerateStubsConfig(compilation: KotlinCompilationData<*>, kotlinTaskProvider: TaskProvider) : + BaseKotlinCompileConfig(compilation) { + + private val kaptExtension: KaptExtension = project.extensions.getByType(KaptExtension::class.java) + + init { + configureTask { task -> + val kotlinCompileTask = kotlinTaskProvider.get() + task.useModuleDetection.value(kotlinCompileTask.useModuleDetection).disallowChanges() + task.moduleName.value(kotlinCompileTask.moduleName).disallowChanges() + task.libraries.from({ kotlinCompileTask.libraries }) + task.compileKotlinArgumentsContributor.set(providers.provider { kotlinCompileTask.compilerArgumentsContributor }) + task.verbose.set(KaptTask.queryKaptVerboseProperty(project)) + + task.pluginOptions.add(buildOptions(task)) + + if (!isIncludeCompileClasspath()) { + task.onlyIf { + !(it as KaptGenerateStubsTask).kaptClasspath.isEmpty + } + } + } + } + + private fun isIncludeCompileClasspath() = kaptExtension.includeCompileClasspath ?: project.isIncludeCompileClasspath() + + private fun buildOptions(task: KaptGenerateStubsTask): Provider { + val javacOptions = project.provider { kaptExtension.getJavacOptions() } + return project.provider { + val compilerPluginOptions = CompilerPluginOptions() + buildKaptSubpluginOptions( + kaptExtension, + project, + javacOptions.get(), + aptMode = "stubs", + generatedSourcesDir = objectFactory.fileCollection().from(task.destinationDirectory.asFile), + generatedClassesDir = objectFactory.fileCollection().from(task.destinationDirectory.asFile), + incrementalDataDir = objectFactory.fileCollection().from(task.destinationDirectory.asFile), + includeCompileClasspath = isIncludeCompileClasspath(), + kaptStubsDir = objectFactory.fileCollection().from(task.stubsDir.asFile) + ).forEach { + compilerPluginOptions.addPluginArgument(KAPT_SUBPLUGIN_ID, it) + } + return@provider compilerPluginOptions + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt new file mode 100644 index 00000000000..fb6093d4d91 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/Kotlin2JsCompileConfig.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2021 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.tasks.configuration + +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData +import org.jetbrains.kotlin.gradle.targets.js.ir.isProduceUnzippedKlib +import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile +import java.io.File + +internal typealias Kotlin2JsCompileConfig = BaseKotlin2JsCompileConfig + +internal open class BaseKotlin2JsCompileConfig( + compilation: KotlinCompilationData<*> +) : AbstractKotlinCompileConfig(compilation) { + + init { + val libraryCacheService = project.rootProject.gradle.sharedServices.registerIfAbsent( + "${Kotlin2JsCompile.LibraryFilterCachingService::class.java.canonicalName}_${Kotlin2JsCompile.LibraryFilterCachingService::class.java.classLoader.hashCode()}", + Kotlin2JsCompile.LibraryFilterCachingService::class.java + ) {} + + configureTask { task -> + task.incremental = propertiesProvider.incrementalJs ?: true + task.incrementalJsKlib = propertiesProvider.incrementalJsKlib ?: true + + task.outputFileProperty.value(task.project.provider { + task.kotlinOptions.outputFile?.let(::File) + ?: task.destinationDirectory.locationOnly.get().asFile.resolve("${compilation.ownModuleName}.js") + }).disallowChanges() + + task.optionalOutputFile.fileProvider(task.outputFileProperty.flatMap { outputFile -> + task.project.provider { + outputFile.takeUnless { task.kotlinOptions.isProduceUnzippedKlib() } + } + }).disallowChanges() + task.libraryCache.set(libraryCacheService).also { task.libraryCache.disallowChanges() } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileCommonConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileCommonConfig.kt new file mode 100644 index 00000000000..b2db4372b3a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileCommonConfig.kt @@ -0,0 +1,60 @@ +/* + * Copyright 2010-2021 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.tasks.configuration + +import org.gradle.api.Project +import org.gradle.api.provider.Provider +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.KotlinTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.AbstractKotlinFragmentMetadataCompilationData +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinMetadataCompilationData +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.refinesClosure +import org.jetbrains.kotlin.gradle.plugin.sources.dependsOnClosure +import org.jetbrains.kotlin.gradle.tasks.KotlinCompileCommon +import java.io.File + +internal class KotlinCompileCommonConfig( + private val compilation: KotlinCompilationData<*>, +) : AbstractKotlinCompileConfig(compilation) { + init { + configureTask { task -> + task.expectActualLinker.value( + providers.provider { + (compilation as? KotlinCommonCompilation)?.isKlibCompilation == true || compilation is KotlinMetadataCompilationData + } + ).disallowChanges() + task.refinesMetadataPaths.from(getRefinesMetadataPaths(project)).disallowChanges() + } + } + + private fun getRefinesMetadataPaths(project: Project): Provider> { + return project.provider { + when (compilation) { + is KotlinCompilation<*> -> { + val defaultKotlinSourceSet: KotlinSourceSet = compilation.defaultSourceSet + val metadataTarget = compilation.owner as KotlinTarget + defaultKotlinSourceSet.dependsOnClosure + .mapNotNull { sourceSet -> metadataTarget.compilations.findByName(sourceSet.name)?.output?.classesDirs } + .flatten() + } + is AbstractKotlinFragmentMetadataCompilationData -> { + val fragment = compilation.fragment + project.files( + fragment.refinesClosure.minus(fragment).map { + val compilation = compilation.metadataCompilationRegistry.getForFragmentOrNull(it) + ?: return@map project.files() + compilation.output.classesDirs + } + ) + } + else -> error("unexpected compilation type") + } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt new file mode 100644 index 00000000000..d29d70a0cc8 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt @@ -0,0 +1,117 @@ +/* + * Copyright 2010-2022 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.tasks.configuration + +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.attributes.Attribute +import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.jetbrains.kotlin.gradle.internal.transforms.ClasspathEntrySnapshotTransform +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation +import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinCompilationData +import org.jetbrains.kotlin.gradle.report.BuildMetricsReporterService +import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +internal typealias KotlinCompileConfig = BaseKotlinCompileConfig + +internal open class BaseKotlinCompileConfig : AbstractKotlinCompileConfig { + + @Suppress("ConvertSecondaryConstructorToPrimary") + constructor(compilation: KotlinCompilationData<*>) : super(compilation) { + val javaTaskProvider = when (compilation) { + is KotlinJvmCompilation -> compilation.compileJavaTaskProvider + is KotlinJvmAndroidCompilation -> compilation.compileJavaTaskProvider + is KotlinWithJavaCompilation<*> -> compilation.compileJavaTaskProvider + else -> null + } + + configureTaskProvider { taskProvider -> + val snapshotConfiguration = runAtConfigurationTime(taskProvider) + + taskProvider.configure { task -> + javaTaskProvider?.let { + task.associatedJavaCompileTaskTargetCompatibility.value(javaTaskProvider.map { it.targetCompatibility }) + task.associatedJavaCompileTaskSources.from(javaTaskProvider.map { it.source }) + task.associatedJavaCompileTaskName.value(javaTaskProvider.name) + } + task.moduleName.value(providers.provider { + (compilation.kotlinOptions as? KotlinJvmOptions)?.moduleName ?: task.parentKotlinOptionsImpl.orNull?.moduleName + ?: compilation.moduleName + }) + + task.incremental = propertiesProvider.incrementalJvm ?: true + + if (propertiesProvider.useFir == true) { + task.kotlinOptions.useFir = true + } + task.usePreciseJavaTracking = propertiesProvider.usePreciseJavaTracking ?: true + task.jvmTargetValidationMode.set(propertiesProvider.jvmTargetValidationMode) + task.classpathSnapshotProperties.useClasspathSnapshot.value(propertiesProvider.useClasspathSnapshot) + task.useKotlinAbiSnapshot.value(propertiesProvider.useKotlinAbiSnapshot).disallowChanges() + + if (snapshotConfiguration != null) { + val snapshotFiles = snapshotConfiguration.incoming.artifactView { + it.attributes.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE) + }.files + task.classpathSnapshotProperties.classpathSnapshot.from(snapshotFiles).disallowChanges() + task.classpathSnapshotProperties.classpathSnapshotDir + .value(getClasspathSnapshotDir(task)) + .disallowChanges() + } else { + task.classpathSnapshotProperties.classpath.from(task.project.provider { task.libraries }) + } + } + } + } + + companion object { + private const val TRANSFORMS_REGISTERED = "_kgp_internal_kotlin_compile_transforms_registered" + + val ARTIFACT_TYPE_ATTRIBUTE: Attribute = Attribute.of("artifactType", String::class.java) + private const val DIRECTORY_ARTIFACT_TYPE = "directory" + private const val JAR_ARTIFACT_TYPE = "jar" + const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot" + } + + private fun registerTransformsOnce(project: Project) { + if (project.extensions.extraProperties.has(TRANSFORMS_REGISTERED)) { + return + } + project.extensions.extraProperties[TRANSFORMS_REGISTERED] = true + + val buildMetricsReporterService = BuildMetricsReporterService.registerIfAbsent(project) + project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) { + it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, JAR_ARTIFACT_TYPE) + it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE) + it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir) + buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) } + } + project.dependencies.registerTransform(ClasspathEntrySnapshotTransform::class.java) { + it.from.attribute(ARTIFACT_TYPE_ATTRIBUTE, DIRECTORY_ARTIFACT_TYPE) + it.to.attribute(ARTIFACT_TYPE_ATTRIBUTE, CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE) + it.parameters.gradleUserHomeDir.set(project.gradle.gradleUserHomeDir) + buildMetricsReporterService?.apply { it.parameters.buildMetricsReporterService.set(this) } + } + } + + /** + * Prepares for configuration of the task. This method must be called during build configuration, not during task configuration + * (which typically happens after build configuration). The reason is that some actions must be performed early (e.g., creating + * configurations should be done early to avoid issues with composite builds (https://issuetracker.google.com/183952598)). + */ + private fun runAtConfigurationTime(taskProvider: TaskProvider): Configuration? { + return if (propertiesProvider.useClasspathSnapshot) { + registerTransformsOnce(project) + project.configurations.detachedConfiguration( + project.dependencies.create(objectFactory.fileCollection().from(taskProvider.get().libraries)) + ) + } else null + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt new file mode 100644 index 00000000000..d134c024dc0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinJsIrLinkConfig.kt @@ -0,0 +1,25 @@ +/* + * Copyright 2010-2021 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.tasks.configuration + +import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation +import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrLink + +internal open class KotlinJsIrLinkConfig( + compilation: KotlinJsIrCompilation +) : BaseKotlin2JsCompileConfig(compilation) { + + init { + configureTask { task -> + // Link tasks are not affected by compiler plugin, so set to empty + task.pluginClasspath.setFrom(objectFactory.fileCollection()) + + task.entryModule.fileProvider(compilation.output.classesDirs.elements.map { it.single().asFile }).disallowChanges() + task.compilation = compilation + task.destinationDirectory.fileProvider(task.outputFileProperty.map { it.parentFile }) + } + } +} \ No newline at end of file