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