Use TCA-compliant Gradle APIs in the Kotlin Gradle plugin

This commit is contained in:
Sergey Igushkin
2020-06-06 00:13:10 +03:00
parent 84287d77ca
commit 58e9b3ae0e
19 changed files with 260 additions and 217 deletions
@@ -27,6 +27,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.isMain import org.jetbrains.kotlin.gradle.plugin.mpp.isMain
import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.utils.archivePathCompatible import org.jetbrains.kotlin.gradle.utils.archivePathCompatible
import org.jetbrains.kotlin.gradle.utils.newTmpFile import org.jetbrains.kotlin.gradle.utils.newTmpFile
import org.jetbrains.kotlin.gradle.utils.relativeToRoot import org.jetbrains.kotlin.gradle.utils.relativeToRoot
@@ -201,7 +202,7 @@ internal open class GradleCompilerRunner(protected val task: Task) {
if (compilation.isMain()) { if (compilation.isMain()) {
if (isMultiplatformProject) { if (isMultiplatformProject) {
(project.tasks.findByName(target.artifactsTaskName) as? AbstractArchiveTask)?.let { jarTask -> project.locateTask<AbstractArchiveTask>(target.artifactsTaskName)?.configure { jarTask ->
jarToModule[jarTask.archivePathCompatible.canonicalFile] = module jarToModule[jarTask.archivePathCompatible.canonicalFile] = module
} }
} else { } else {
@@ -21,6 +21,7 @@ import org.gradle.api.plugins.InvalidPluginException
import org.gradle.api.plugins.JavaPlugin import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.plugins.JavaPluginConvention import org.gradle.api.plugins.JavaPluginConvention
import org.gradle.api.plugins.MavenPluginConvention import org.gradle.api.plugins.MavenPluginConvention
import org.gradle.api.provider.Provider
import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.tasks.CompileClasspathNormalizer import org.gradle.api.tasks.CompileClasspathNormalizer
@@ -222,7 +223,10 @@ internal class Kotlin2JvmSourceSetProcessor(
.flatMap { it.getSubpluginKotlinTasks(project, kotlinTaskInstance) } .flatMap { it.getSubpluginKotlinTasks(project, kotlinTaskInstance) }
.forEach { plugin -> kotlinCompilation.allKotlinSourceSets.forEach { sourceSet -> plugin.source(sourceSet.kotlin) } } .forEach { plugin -> kotlinCompilation.allKotlinSourceSets.forEach { sourceSet -> plugin.source(sourceSet.kotlin) } }
javaTask?.let { configureJavaTask(kotlinTaskInstance, it) } javaSourceSet?.let { java ->
val javaTask = project.tasks.withType<AbstractCompile>().named(java.compileJavaTaskName)
configureJavaTask(kotlinTask, javaTask)
}
if (project.pluginManager.hasPlugin("java-library") && sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) { if (project.pluginManager.hasPlugin("java-library") && sourceSetName == SourceSet.MAIN_SOURCE_SET_NAME) {
registerKotlinOutputForJavaLibrary(kotlinTaskInstance.destinationDir, kotlinTaskInstance) registerKotlinOutputForJavaLibrary(kotlinTaskInstance.destinationDir, kotlinTaskInstance)
@@ -405,10 +409,10 @@ internal class KotlinCommonSourceSetProcessor(
tasksProvider, taskDescription = "Compiles the kotlin sources in $compilation to Metadata.", kotlinCompilation = compilation tasksProvider, taskDescription = "Compiles the kotlin sources in $compilation to Metadata.", kotlinCompilation = compilation
) { ) {
override fun doTargetSpecificProcessing() { override fun doTargetSpecificProcessing() {
project.tasks.findByName(kotlinCompilation.compileAllTaskName)!!.dependsOn(kotlinTask) project.tasks.named(kotlinCompilation.compileAllTaskName).dependsOn(kotlinTask)
// can be missing (e.g. in case of tests) // can be missing (e.g. in case of tests)
if (kotlinCompilation.isMain()) { if (kotlinCompilation.isMain()) {
project.tasks.findByName(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask) project.locateTask<Task>(kotlinCompilation.target.artifactsTaskName)?.dependsOn(kotlinTask)
} }
project.runOnceAfterEvaluated("KotlinCommonSourceSetProcessor.doTargetSpecificProcessing", kotlinTask) { project.runOnceAfterEvaluated("KotlinCommonSourceSetProcessor.doTargetSpecificProcessing", kotlinTask) {
@@ -514,10 +518,10 @@ internal abstract class AbstractKotlinPlugin(
} }
private fun configureClassInspectionForIC(project: Project) { private fun configureClassInspectionForIC(project: Project) {
val classesTask = project.tasks.findByName(JavaPlugin.CLASSES_TASK_NAME) val classesTask = project.locateTask<Task>(JavaPlugin.CLASSES_TASK_NAME)
val jarTask = project.tasks.findByName(JavaPlugin.JAR_TASK_NAME) val jarTask = project.locateTask<Jar>(JavaPlugin.JAR_TASK_NAME)
if (classesTask == null || jarTask !is Jar) { if (classesTask == null || jarTask == null) {
project.logger.info( project.logger.info(
"Could not configure class inspection task " + "Could not configure class inspection task " +
"(classes task = ${classesTask?.javaClass?.canonicalName}, " + "(classes task = ${classesTask?.javaClass?.canonicalName}, " +
@@ -528,8 +532,8 @@ internal abstract class AbstractKotlinPlugin(
val inspectTask = val inspectTask =
project.registerTask<InspectClassesForMultiModuleIC>("inspectClassesForKotlinIC") { project.registerTask<InspectClassesForMultiModuleIC>("inspectClassesForKotlinIC") {
it.sourceSetName = SourceSet.MAIN_SOURCE_SET_NAME it.sourceSetName = SourceSet.MAIN_SOURCE_SET_NAME
it.archivePath.set(project.provider { jarTask.archivePathCompatible.canonicalPath }) it.archivePath.set(project.provider { jarTask.get().archivePathCompatible.canonicalPath })
it.archiveName.set(project.provider { jarTask.archiveFileName.get() }) it.archiveName.set(project.provider { jarTask.get().archiveFileName.get() })
it.dependsOn(classesTask) it.dependsOn(classesTask)
} }
jarTask.dependsOn(inspectTask) jarTask.dependsOn(inspectTask)
@@ -1085,27 +1089,33 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationTool
} }
} }
internal fun configureJavaTask(kotlinTask: KotlinCompile, javaTask: AbstractCompile) { internal fun configureJavaTask(
kotlinTask.javaOutputDir = javaTask.destinationDir kotlinTaskProvider: TaskProvider<out KotlinCompile>,
javaTaskProvider: TaskProvider<out AbstractCompile>
) {
javaTaskProvider.configure { javaTask ->
val kotlinTask = kotlinTaskProvider.get()
kotlinTask.javaOutputDir = javaTask.destinationDir
// Make Gradle check if the javaTask is up-to-date based on the Kotlin classes // Make Gradle check if the javaTask is up-to-date based on the Kotlin classes
javaTask.inputs.run { javaTask.inputs.run {
dir(kotlinTask.destinationDir) dir(kotlinTask.destinationDir)
.withNormalizer(CompileClasspathNormalizer::class.java) .withNormalizer(CompileClasspathNormalizer::class.java)
.withPropertyName("${kotlinTask.name}OutputClasses") .withPropertyName("${kotlinTask.name}OutputClasses")
}
// Also, use kapt1 annotations file for up-to-date check since annotation processing is done with javac
javaTask.dependsOn(kotlinTask)
/*
* It's important to modify javaTask.classpath only in doFirst,
* because Android plugin uses ConventionMapping to modify it too (see JavaCompileConfigAction.execute),
* and setting classpath explicitly prevents usage of Android mappings.
* Also classpath set by Android can be modified after execution of some tasks (see VarianConfiguration.getCompileClasspath)
* ex. it adds some support libraries jars after execution of prepareComAndroidSupportSupportV42311Library task,
* so it's only safe to modify javaTask.classpath right before its usage
*/
// todo: remove?
javaTask.appendClasspathDynamically(kotlinTask.destinationDir)
} }
// Also, use kapt1 annotations file for up-to-date check since annotation processing is done with javac
javaTask.dependsOn(kotlinTask)
/*
* It's important to modify javaTask.classpath only in doFirst,
* because Android plugin uses ConventionMapping to modify it too (see JavaCompileConfigAction.execute),
* and setting classpath explicitly prevents usage of Android mappings.
* Also classpath set by Android can be modified after execution of some tasks (see VarianConfiguration.getCompileClasspath)
* ex. it adds some support libraries jars after execution of prepareComAndroidSupportSupportV42311Library task,
* so it's only safe to modify javaTask.classpath right before its usage
*/
// todo: remove?
javaTask.appendClasspathDynamically(kotlinTask.destinationDir)
} }
private fun ifKaptEnabled(project: Project, block: () -> Unit) { private fun ifKaptEnabled(project: Project, block: () -> Unit) {
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle.plugin package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.NamedDomainObjectContainer import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
@@ -21,6 +22,7 @@ import org.gradle.api.plugins.BasePlugin
import org.gradle.api.plugins.ExtensionAware import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.tasks.Delete import org.gradle.api.tasks.Delete
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip import org.gradle.api.tasks.bundling.Zip
import org.gradle.language.base.plugins.LifecycleBasePlugin import org.gradle.language.base.plugins.LifecycleBasePlugin
@@ -31,6 +33,8 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.COMPILE import org.jetbrains.kotlin.gradle.utils.COMPILE
import org.jetbrains.kotlin.gradle.utils.RUNTIME import org.jetbrains.kotlin.gradle.utils.RUNTIME
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
@@ -65,8 +69,9 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
) : KotlinTargetConfigurator<KotlinTargetType> { ) : KotlinTargetConfigurator<KotlinTargetType> {
private fun Project.registerOutputsForStaleOutputCleanup(kotlinCompilation: KotlinCompilation<*>) { private fun Project.registerOutputsForStaleOutputCleanup(kotlinCompilation: KotlinCompilation<*>) {
val cleanTask = tasks.getByName(LifecycleBasePlugin.CLEAN_TASK_NAME) as Delete tasks.withType<Delete>().named(LifecycleBasePlugin.CLEAN_TASK_NAME).configure { cleanTask ->
cleanTask.delete(kotlinCompilation.output.allOutputs) cleanTask.delete(kotlinCompilation.output.allOutputs)
}
} }
protected open fun setupCompilationDependencyFiles(compilation: KotlinCompilation<KotlinCommonOptions>) { protected open fun setupCompilationDependencyFiles(compilation: KotlinCompilation<KotlinCommonOptions>) {
@@ -125,10 +130,11 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
) { ) {
val project = compilation.target.project val project = compilation.target.project
val resourcesTask = project.tasks.maybeCreate(compilation.processResourcesTaskName, ProcessResources::class.java) project.registerTask<ProcessResources>(compilation.processResourcesTaskName) { resourcesTask ->
resourcesTask.description = "Processes $resourceSet." resourcesTask.description = "Processes $resourceSet."
DslObject(resourcesTask).conventionMapping.map("destinationDir") { project.file(compilation.output.resourcesDir) } DslObject(resourcesTask).conventionMapping.map("destinationDir") { project.file(compilation.output.resourcesDir) }
resourcesTask.from(resourceSet) resourcesTask.from(resourceSet)
}
} }
protected fun createLifecycleTask(compilation: KotlinCompilation<*>) { protected fun createLifecycleTask(compilation: KotlinCompilation<*>) {
@@ -136,12 +142,12 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
compilation.output.classesDirs.from(project.files().builtBy(compilation.compileAllTaskName)) compilation.output.classesDirs.from(project.files().builtBy(compilation.compileAllTaskName))
project.tasks.create(compilation.compileAllTaskName).apply { project.registerTask<DefaultTask>(compilation.compileAllTaskName) {
group = LifecycleBasePlugin.BUILD_GROUP it.group = LifecycleBasePlugin.BUILD_GROUP
description = "Assembles outputs for compilation '${compilation.name}' of target '${compilation.target.name}'" it.description = "Assembles outputs for compilation '${compilation.name}' of target '${compilation.target.name}'"
dependsOn(compilation.compileKotlinTaskName) it.dependsOn(compilation.compileKotlinTaskName)
if (compilation is KotlinCompilationWithResources) { if (compilation is KotlinCompilationWithResources) {
dependsOn(compilation.processResourcesTaskName) it.dependsOn(compilation.processResourcesTaskName)
} }
} }
} }
@@ -228,22 +234,23 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
override fun configureBuild(target: KotlinTargetType) { override fun configureBuild(target: KotlinTargetType) {
val project = target.project val project = target.project
val buildNeeded = project.tasks.getByName(JavaBasePlugin.BUILD_NEEDED_TASK_NAME) val buildNeeded = project.tasks.named(JavaBasePlugin.BUILD_NEEDED_TASK_NAME)
val buildDependent = project.tasks.getByName(JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME) val buildDependent = project.tasks.named(JavaBasePlugin.BUILD_DEPENDENTS_TASK_NAME)
if (createTestCompilation) { if (createTestCompilation) {
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME) val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
if (testCompilation is KotlinCompilationToRunnableFiles) { if (testCompilation is KotlinCompilationToRunnableFiles) {
addDependsOnTaskInOtherProjects(buildNeeded, true, testCompilation.deprecatedRuntimeConfigurationName) addDependsOnTaskInOtherProjects(project, buildNeeded, true, testCompilation.deprecatedRuntimeConfigurationName)
addDependsOnTaskInOtherProjects(buildDependent, false, testCompilation.deprecatedRuntimeConfigurationName) addDependsOnTaskInOtherProjects(project, buildDependent, false, testCompilation.deprecatedRuntimeConfigurationName)
} }
} }
} }
private fun addDependsOnTaskInOtherProjects(task: Task, useDependedOn: Boolean, configurationName: String) { private fun addDependsOnTaskInOtherProjects(project: Project, taskProvider: TaskProvider<*>, useDependedOn: Boolean, configurationName: String) {
val project = task.project
val configuration = project.configurations.getByName(configurationName) val configuration = project.configurations.getByName(configurationName)
task.dependsOn(configuration.getTaskDependencyFromProjectDependency(useDependedOn, task.name)) taskProvider.configure { task ->
task.dependsOn(configuration.getTaskDependencyFromProjectDependency(useDependedOn, taskProvider.name))
}
} }
companion object { companion object {
@@ -359,12 +366,12 @@ abstract class KotlinOnlyTargetConfigurator<KotlinCompilationType : KotlinCompil
} }
/** The implementations are expected to create a [Zip] task under the name [KotlinTarget.artifactsTaskName] of the [target]. */ /** The implementations are expected to create a [Zip] task under the name [KotlinTarget.artifactsTaskName] of the [target]. */
protected open fun createArchiveTasks(target: KotlinTargetType): Zip { protected open fun createArchiveTasks(target: KotlinTargetType): TaskProvider<out Zip> {
//TODO Change Jar on Zip //TODO Change Jar on Zip
return target.project.tasks.create(target.artifactsTaskName, Jar::class.java).apply { return target.project.registerTask<Jar>(target.artifactsTaskName) {
description = "Assembles an archive containing the main classes." it.description = "Assembles an archive containing the main classes."
group = BasePlugin.BUILD_GROUP it.group = BasePlugin.BUILD_GROUP
from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs) it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
} }
} }
@@ -375,7 +382,11 @@ abstract class KotlinOnlyTargetConfigurator<KotlinCompilationType : KotlinCompil
val task = createArchiveTasks(target) val task = createArchiveTasks(target)
target.disambiguationClassifier?.let { task.appendix = it.toLowerCase() } target.disambiguationClassifier?.let { classifier ->
task.configure { taskInstance ->
taskInstance.archiveAppendix.set(classifier.toLowerCase())
}
}
// Workaround: adding the artifact during configuration seems to interfere with the Java plugin, which results into missing // Workaround: adding the artifact during configuration seems to interfere with the Java plugin, which results into missing
// task dependency 'assemble -> jar' if the Java plugin is applied after this steps // task dependency 'assemble -> jar' if the Java plugin is applied after this steps
@@ -30,7 +30,7 @@ open class KotlinMetadataTarget @Inject constructor(project: Project) :
val javaApiUsage = project.usageByName("java-api-jars") val javaApiUsage = project.usageByName("java-api-jars")
usageContexts += run { usageContexts += run {
val allMetadataJar = project.tasks.getByName(KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME) val allMetadataJar = project.tasks.named(KotlinMetadataTargetConfigurator.ALL_METADATA_JAR_NAME)
val allMetadataArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, allMetadataJar) { val allMetadataArtifact = project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, allMetadataJar) {
it.classifier = if (project.isCompatibilityMetadataVariantEnabled) "all" else "" it.classifier = if (project.isCompatibilityMetadataVariantEnabled) "all" else ""
} }
@@ -17,6 +17,8 @@ import org.gradle.api.publish.PublicationContainer
import org.gradle.api.publish.PublishingExtension import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.maven.MavenPublication import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal
import org.gradle.api.publish.maven.tasks.AbstractPublishToMaven
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.jvm.tasks.Jar import org.gradle.jvm.tasks.Jar
import org.gradle.util.ConfigureUtil import org.gradle.util.ConfigureUtil
@@ -35,9 +37,9 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubplugin
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget.* import org.jetbrains.kotlin.konan.target.KonanTarget.*
import org.jetbrains.kotlin.konan.target.presetName import org.jetbrains.kotlin.konan.target.presetName
@@ -338,7 +340,7 @@ internal fun applyUserDefinedAttributes(target: AbstractKotlinTarget) {
} }
} }
internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String?, artifactNameAppendix: String): Jar = internal fun sourcesJarTask(compilation: KotlinCompilation<*>, componentName: String?, artifactNameAppendix: String): TaskProvider<Jar> =
sourcesJarTask(compilation.target.project, lazy { compilation.allKotlinSourceSets }, componentName, artifactNameAppendix) sourcesJarTask(compilation.target.project, lazy { compilation.allKotlinSourceSets }, componentName, artifactNameAppendix)
internal fun sourcesJarTask( internal fun sourcesJarTask(
@@ -346,20 +348,25 @@ internal fun sourcesJarTask(
sourceSets: Lazy<Set<KotlinSourceSet>>, sourceSets: Lazy<Set<KotlinSourceSet>>,
componentName: String?, componentName: String?,
artifactNameAppendix: String artifactNameAppendix: String
): Jar { ): TaskProvider<Jar> {
val taskName = lowerCamelCaseName(componentName, "sourcesJar") val taskName = lowerCamelCaseName(componentName, "sourcesJar")
(project.tasks.findByName(taskName) as? Jar)?.let { return it } project.tasks.withType<Jar>().run {
if (taskName in names)
return named(taskName)
}
val result = project.tasks.create(taskName, Jar::class.java) { sourcesJar -> val result = project.registerTask<Jar>(taskName) { sourcesJar ->
sourcesJar.archiveAppendix.set(artifactNameAppendix) sourcesJar.archiveAppendix.set(artifactNameAppendix)
sourcesJar.archiveClassifier.set("sources") sourcesJar.archiveClassifier.set("sources")
} }
project.whenEvaluated { project.whenEvaluated {
sourceSets.value.forEach { sourceSet -> result.configure {
result.from(sourceSet.kotlin) { copySpec -> sourceSets.value.forEach { sourceSet ->
copySpec.into(sourceSet.name) it.from(sourceSet.kotlin) { copySpec ->
copySpec.into(sourceSet.name)
}
} }
} }
} }
@@ -113,7 +113,7 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
// To configure a task that may have not yet been created at this point, use 'withType-matching-all`: // To configure a task that may have not yet been created at this point, use 'withType-matching-all`:
.withType(AbstractKotlinCompile::class.java) .withType(AbstractKotlinCompile::class.java)
.matching { it.name == compileKotlinTaskName } .matching { it.name == compileKotlinTaskName }
.all { compileKotlinTask -> .configureEach { compileKotlinTask ->
compileKotlinTask.configureAction() compileKotlinTask.configureAction()
} }
} }
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.gradle.targets.js.ir package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.attributes.Usage import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Zip import org.gradle.api.tasks.bundling.Zip
import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions import org.jetbrains.kotlin.gradle.dsl.KotlinJsOptions
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
@@ -54,9 +55,9 @@ open class KotlinJsIrTargetConfigurator(kotlinPluginVersion: String) :
return KotlinJsIrSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion) return KotlinJsIrSourceSetProcessor(tasksProvider, compilation, kotlinPluginVersion)
} }
override fun createArchiveTasks(target: KotlinJsIrTarget): Zip { override fun createArchiveTasks(target: KotlinJsIrTarget): TaskProvider<out Zip> {
return super.createArchiveTasks(target).apply { return super.createArchiveTasks(target).apply {
archiveExtension.set(KLIB_TYPE) configure { it.archiveExtension.set(KLIB_TYPE) }
} }
} }
@@ -19,7 +19,7 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation
import java.util.concurrent.Callable import java.util.concurrent.Callable
import javax.inject.Inject import javax.inject.Inject
@@ -61,11 +61,11 @@ open class KotlinJvmTarget @Inject constructor(
javaPluginConvention.sourceSets.all { javaSourceSet -> javaPluginConvention.sourceSets.all { javaSourceSet ->
val compilation = compilations.getByName(javaSourceSet.name) val compilation = compilations.getByName(javaSourceSet.name)
val compileJavaTask = project.tasks.getByName(javaSourceSet.compileJavaTaskName) as AbstractCompile val compileJavaTask = project.tasks.withType<AbstractCompile>().named(javaSourceSet.compileJavaTaskName)
setupJavaSourceSetSourcesAndResources(javaSourceSet, compilation) setupJavaSourceSetSourcesAndResources(javaSourceSet, compilation)
val javaClasses = project.files(Callable { compileJavaTask.destinationDir }).builtBy(compileJavaTask) val javaClasses = project.files(compileJavaTask.map { it.destinationDir })
compilation.output.classesDirs.from(javaClasses) compilation.output.classesDirs.from(javaClasses)
@@ -110,16 +110,19 @@ open class KotlinJvmTarget @Inject constructor(
private fun disableJavaPluginTasks(javaPluginConvention: JavaPluginConvention) { private fun disableJavaPluginTasks(javaPluginConvention: JavaPluginConvention) {
// A 'normal' build should not do redundant job like running the tests twice or building two JARs, // A 'normal' build should not do redundant job like running the tests twice or building two JARs,
// so disable some tasks and just make them depend on the others: // so disable some tasks and just make them depend on the others:
val targetJar = project.tasks.getByName(artifactsTaskName) as Jar val targetJar = project.tasks.withType(Jar::class.java).named(artifactsTaskName)
val javaJar = project.tasks.getByName(javaPluginConvention.sourceSets.getByName("main").jarTaskName) as Jar
(javaJar.source as? ConfigurableFileCollection)?.setFrom(targetJar.source)
javaJar.conventionMapping("archiveName") { targetJar.archiveFileName.get() }
javaJar.dependsOn(targetJar)
javaJar.enabled = false
val javaTestTask = project.tasks.getByName(JavaPlugin.TEST_TASK_NAME) as Test project.tasks.withType(Jar::class.java).named(javaPluginConvention.sourceSets.getByName("main").jarTaskName) { javaJar ->
javaTestTask.dependsOn(project.tasks.getByName(testTaskName) as Test) (javaJar.source as? ConfigurableFileCollection)?.setFrom(targetJar.map { it.source })
javaTestTask.enabled = false javaJar.conventionMapping("archiveName") { targetJar.get().archiveFileName.get() }
javaJar.dependsOn(targetJar)
javaJar.enabled = false
}
project.tasks.withType(Test::class.java).named(JavaPlugin.TEST_TASK_NAME) { javaTestTask ->
javaTestTask.dependsOn(project.tasks.named(testTaskName))
javaTestTask.enabled = false
}
} }
private fun setupDependenciesCrossInclusionForJava( private fun setupDependenciesCrossInclusionForJava(
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.gradle.targets.jvm package org.jetbrains.kotlin.gradle.targets.jvm
import org.gradle.api.Task
import org.gradle.api.plugins.JavaBasePlugin import org.gradle.api.plugins.JavaBasePlugin
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.Kotlin2JvmSourceSetProcessor import org.jetbrains.kotlin.gradle.plugin.Kotlin2JvmSourceSetProcessor
@@ -12,6 +13,8 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSetProcessor
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName import org.jetbrains.kotlin.gradle.testing.testTaskName
@@ -49,8 +52,8 @@ class KotlinJvmTargetConfigurator(kotlinPluginVersion: String) :
): KotlinJvmTestRun = KotlinJvmTestRun(name, target).apply { ): KotlinJvmTestRun = KotlinJvmTestRun(name, target).apply {
val testTaskOrProvider = target.project.registerTask<KotlinJvmTest>(testTaskName) { testTask -> val testTaskOrProvider = target.project.registerTask<KotlinJvmTest>(testTaskName) { testTask ->
testTask.targetName = target.disambiguationClassifier testTask.targetName = target.disambiguationClassifier
testTask.project.tasks.findByName(JavaBasePlugin.CHECK_TASK_NAME)?.dependsOn(testTask)
} }
target.project.locateTask<Task>(JavaBasePlugin.CHECK_TASK_NAME)?.dependsOn(testTaskOrProvider)
executionTask = testTaskOrProvider executionTask = testTaskOrProvider
@@ -11,14 +11,12 @@ import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.internal.component.SoftwareComponentInternal import org.gradle.api.internal.component.SoftwareComponentInternal
import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.BasePlugin
import org.gradle.api.tasks.AbstractCopyTask
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip import org.gradle.api.tasks.bundling.Zip
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.sources.* import org.jetbrains.kotlin.gradle.plugin.sources.*
@@ -81,10 +79,10 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
createMergedAllSourceSetsConfigurations(target) createMergedAllSourceSetsConfigurations(target)
val allMetadataJar = target.project.tasks.getByName(ALL_METADATA_JAR_NAME) as Jar val allMetadataJar = target.project.tasks.withType<Jar>().named(ALL_METADATA_JAR_NAME)
createMetadataCompilationsForCommonSourceSets(target, allMetadataJar) createMetadataCompilationsForCommonSourceSets(target, allMetadataJar)
configureProjectStructureMetadataGeneration(allMetadataJar) configureProjectStructureMetadataGeneration(target.project, allMetadataJar)
setupDependencyTransformationForCommonSourceSets(target) setupDependencyTransformationForCommonSourceSets(target)
@@ -125,12 +123,12 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
override val kotlinTask: TaskProvider<out KotlinNativeCompile> = override val kotlinTask: TaskProvider<out KotlinNativeCompile> =
with(nativeTargetConfigurator) { with(nativeTargetConfigurator) {
project.createKlibCompilationTask(kotlinCompilation) project.createKlibCompilationTask(kotlinCompilation)
}.thisTaskProvider }
override fun run() = Unit override fun run() = Unit
} }
override fun createArchiveTasks(target: KotlinMetadataTarget): Zip { override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider<out Zip> {
val result = super.createArchiveTasks(target) val result = super.createArchiveTasks(target)
if (target.project.isKotlinGranularMetadataEnabled) { if (target.project.isKotlinGranularMetadataEnabled) {
@@ -172,7 +170,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
private fun createMetadataCompilationsForCommonSourceSets( private fun createMetadataCompilationsForCommonSourceSets(
target: KotlinMetadataTarget, target: KotlinMetadataTarget,
allMetadataJar: Jar allMetadataJar: TaskProvider<out Jar>
) = target.project.whenEvaluated { ) = target.project.whenEvaluated {
// Do this after all targets are configured by the user build script // Do this after all targets are configured by the user build script
@@ -194,14 +192,15 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
} }
} }
private fun configureProjectStructureMetadataGeneration(allMetadataJar: Jar): AbstractCopyTask { private fun configureProjectStructureMetadataGeneration(project: Project, allMetadataJar: TaskProvider<out Jar>) {
val project = allMetadataJar.project
val generateMetadata = project.createGenerateProjectStructureMetadataTask() val generateMetadata = project.createGenerateProjectStructureMetadataTask()
return allMetadataJar.from( allMetadataJar.configure {
project.files(Callable { generateMetadata.get().resultXmlFile }).builtBy(generateMetadata) it.from(
) { spec -> project.files(Callable { generateMetadata.get().resultXmlFile }).builtBy(generateMetadata)
spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_FILE_NAME } ) { spec ->
spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_FILE_NAME }
}
} }
} }
@@ -249,7 +248,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
private fun createMetadataCompilation( private fun createMetadataCompilation(
target: KotlinMetadataTarget, target: KotlinMetadataTarget,
sourceSet: KotlinSourceSet, sourceSet: KotlinSourceSet,
allMetadataJar: Jar, allMetadataJar: TaskProvider<out Jar>,
isHostSpecific: Boolean isHostSpecific: Boolean
): AbstractKotlinCompilation<*> { ): AbstractKotlinCompilation<*> {
val project = target.project val project = target.project
@@ -276,7 +275,7 @@ class KotlinMetadataTargetConfigurator(kotlinPluginVersion: String) :
if (!isHostSpecific) { if (!isHostSpecific) {
val metadataContent = project.filesWithUnpackedArchives(this@apply.output.allOutputs, setOf("klib")) val metadataContent = project.filesWithUnpackedArchives(this@apply.output.allOutputs, setOf("klib"))
allMetadataJar.from(metadataContent) { spec -> spec.into(this@apply.defaultSourceSet.name) } allMetadataJar.configure { it.from(metadataContent) { spec -> spec.into(this@apply.defaultSourceSet.name) } }
} else { } else {
if (platformCompilations.filterIsInstance<KotlinNativeCompilation>().none { it.konanTarget.enabledOnCurrentHost }) { if (platformCompilations.filterIsInstance<KotlinNativeCompilation>().none { it.konanTarget.enabledOnCurrentHost }) {
// Then we don't have any platform module to put this compiled source set to, so disable the compilation task: // Then we don't have any platform module to put this compiled source set to, so disable the compilation task:
@@ -57,8 +57,9 @@ class KotlinMetadataTargetPreset(
project.whenEvaluated { project.whenEvaluated {
// Since there's no default source set, apply language settings from commonMain: // Since there's no default source set, apply language settings from commonMain:
val compileKotlinMetadata = mainCompilation.compileKotlinTask mainCompilation.compileKotlinTaskProvider.configure { compileKotlinMetadata ->
applyLanguageSettingsToKotlinOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.kotlinOptions) applyLanguageSettingsToKotlinOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.kotlinOptions)
}
} }
} }
} }
@@ -10,6 +10,7 @@ import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Property
import org.gradle.util.ConfigureUtil import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.CInteropSettings import org.jetbrains.kotlin.gradle.plugin.CInteropSettings
import org.jetbrains.kotlin.gradle.plugin.CInteropSettings.IncludeDirectories import org.jetbrains.kotlin.gradle.plugin.CInteropSettings.IncludeDirectories
@@ -56,7 +57,9 @@ open class DefaultCInteropSettings @Inject constructor(
target.disambiguationClassifier target.disambiguationClassifier
) )
var defFile: File = project.projectDir.resolve("src/nativeInterop/cinterop/$name.def") val defFile: Property<File> = project.objects.property(File::class.java)
.apply { set(project.projectDir.resolve("src/nativeInterop/cinterop/$name.def")) }
var packageName: String? = null var packageName: String? = null
val compilerOpts = mutableListOf<String>() val compilerOpts = mutableListOf<String>()
@@ -69,7 +72,7 @@ open class DefaultCInteropSettings @Inject constructor(
// DSL methods. // DSL methods.
override fun defFile(file: Any) { override fun defFile(file: Any) {
defFile = project.file(file) defFile.set(project.file(file))
} }
override fun packageName(value: String) { override fun packageName(value: String) {
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.gradle.plugin.sources.getVisibleSourceSetsFromAssoci
import org.jetbrains.kotlin.gradle.targets.metadata.getMetadataCompilationForSourceSet import org.jetbrains.kotlin.gradle.targets.metadata.getMetadataCompilationForSourceSet
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import java.util.concurrent.Callable import java.util.concurrent.Callable
@@ -6,15 +6,15 @@
@file:Suppress("PackageDirectoryMismatch") // Old package for compatibility @file:Suppress("PackageDirectoryMismatch") // Old package for compatibility
package org.jetbrains.kotlin.gradle.plugin package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.DefaultTask
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.ConfigurationContainer import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.internal.artifacts.ArtifactAttributes import org.gradle.api.internal.artifacts.ArtifactAttributes
import org.gradle.api.internal.artifacts.publish.DefaultPublishArtifact
import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.BasePlugin
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Copy import org.gradle.api.tasks.Copy
import org.gradle.api.tasks.Exec import org.gradle.api.tasks.Exec
import org.gradle.language.base.plugins.LifecycleBasePlugin import org.gradle.language.base.plugins.LifecycleBasePlugin
@@ -33,7 +33,6 @@ import org.jetbrains.kotlin.gradle.testing.testTaskName
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File import java.io.File
import java.util.*
open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>( open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
private val kotlinPluginVersion: String private val kotlinPluginVersion: String
@@ -58,9 +57,9 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
// region Artifact creation. // region Artifact creation.
private fun Project.createKlibArtifact( private fun Project.createKlibArtifact(
compilation: KotlinNativeCompilation, compilation: KotlinNativeCompilation,
artifactFile: File, artifactFile: Provider<File>,
classifier: String?, classifier: String?,
producingTask: Task, producingTask: TaskProvider<*>,
copy: Boolean = false copy: Boolean = false
) { ) {
if (!compilation.konanTarget.enabledOnCurrentHost) { if (!compilation.konanTarget.enabledOnCurrentHost) {
@@ -69,33 +68,30 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
val apiElements = configurations.getByName(compilation.target.apiElementsConfigurationName) val apiElements = configurations.getByName(compilation.target.apiElementsConfigurationName)
val realProducingTask: Task val realProducingTask: TaskProvider<*>
// TODO: Someone remove this HACK PLEASE! // TODO: Someone remove this HACK PLEASE!
val realArtifactFile = if (copy) { val realArtifactFile = if (copy) {
realProducingTask = project.tasks.create("copy${producingTask.name.capitalize()}", Copy::class.java) { realProducingTask = project.registerTask<Copy>("copy${producingTask.name.capitalize()}") {
val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty() val targetSubDirectory = compilation.target.disambiguationClassifier?.let { "$it/" }.orEmpty()
it.destinationDir = project.buildDir.resolve("libs/$targetSubDirectory${compilation.name}") it.destinationDir = project.buildDir.resolve("libs/$targetSubDirectory${compilation.name}")
it.from(artifactFile) it.from(artifactFile)
it.dependsOn(producingTask) it.dependsOn(producingTask)
} }
realProducingTask.destinationDir.resolve(artifactFile.name) realProducingTask.map { (it as Copy).destinationDir.resolve(artifactFile.get().name) }
} else { } else {
realProducingTask = producingTask realProducingTask = producingTask
artifactFile artifactFile
} }
val klibArtifact = DefaultPublishArtifact( with(apiElements) {
compilation.name, val klibArtifact = project.artifacts.add(apiElements.name, realArtifactFile) { artifact ->
"klib", artifact.name = compilation.name
"klib", artifact.extension = "klib"
classifier, artifact.type = "klib"
Date(), artifact.classifier = classifier
realArtifactFile, artifact.builtBy(realProducingTask)
realProducingTask }
) project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
with(apiElements.outgoing) {
artifacts.add(klibArtifact) artifacts.add(klibArtifact)
attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB) attributes.attribute(ArtifactAttributes.ARTIFACT_FORMAT, NativeArtifactFormat.KLIB)
} }
@@ -103,115 +99,117 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
private fun Project.createRegularKlibArtifact( private fun Project.createRegularKlibArtifact(
compilation: KotlinNativeCompilation, compilation: KotlinNativeCompilation,
compileTask: KotlinNativeCompile compileTask: TaskProvider<out KotlinNativeCompile>
) = createKlibArtifact(compilation, compileTask.outputFile.get(), null, compileTask) ) = createKlibArtifact(compilation, compileTask.map { it.outputFile.get() }, null, compileTask)
private fun Project.createCInteropKlibArtifact( private fun Project.createCInteropKlibArtifact(
interop: DefaultCInteropSettings, interop: DefaultCInteropSettings,
interopTask: CInteropProcess interopTask: TaskProvider<out CInteropProcess>
) = createKlibArtifact(interop.compilation, interopTask.outputFile, "cinterop-${interop.name}", interopTask, copy = true) ) = createKlibArtifact(interop.compilation, interopTask.map { it.outputFile }, "cinterop-${interop.name}", interopTask, copy = true)
// endregion. // endregion.
// region Task creation. // region Task creation.
private fun Project.createLinkTask(binary: NativeBinary) { private fun Project.createLinkTask(binary: NativeBinary) {
tasks.create( val result = registerTask<KotlinNativeLink>(
binary.linkTaskName, binary.linkTaskName
KotlinNativeLink::class.java ) {
).apply {
val target = binary.target val target = binary.target
this.binary = binary it.binary = binary
group = BasePlugin.BUILD_GROUP it.group = BasePlugin.BUILD_GROUP
description = "Links ${binary.outputKind.description} '${binary.name}' for a target '${target.name}'." it.description = "Links ${binary.outputKind.description} '${binary.name}' for a target '${target.name}'."
enabled = binary.konanTarget.enabledOnCurrentHost it.enabled = binary.konanTarget.enabledOnCurrentHost
it.destinationDir = binary.outputDirectory
}
addCompilerPlugins() addCompilerPlugins()
if (binary !is TestExecutable) { if (binary !is TestExecutable) {
tasks.maybeCreate(target.artifactsTaskName).dependsOn(this) tasks.named(binary.compilation.target.artifactsTaskName).configure { it.dependsOn(result) }
tasks.maybeCreate(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(this) tasks.maybeCreate(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(result)
}
} }
} }
private fun Project.createRunTask(binary: Executable) { private fun Project.createRunTask(binary: Executable) {
val taskName = binary.runTaskName ?: return val taskName = binary.runTaskName ?: return
tasks.create(taskName, Exec::class.java).apply { registerTask<Exec>(taskName) { exec ->
group = RUN_GROUP exec.group = RUN_GROUP
description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}" exec.description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}"
enabled = binary.konanTarget.isCurrentHost exec.enabled = binary.konanTarget.isCurrentHost
executable = binary.outputFile.absolutePath exec.executable = binary.outputFile.absolutePath
workingDir = project.projectDir exec.workingDir = project.projectDir
onlyIf { binary.outputFile.exists() } exec.onlyIf { binary.outputFile.exists() }
dependsOn(binary.linkTaskName) exec.dependsOn(binary.linkTaskName)
} }
} }
internal fun Project.createKlibCompilationTask(compilation: AbstractKotlinNativeCompilation): KotlinNativeCompile { internal fun Project.createKlibCompilationTask(compilation: AbstractKotlinNativeCompilation): TaskProvider<KotlinNativeCompile> {
val compileTask = project.tasks.create( val compileTaskProvider = registerTask<KotlinNativeCompile>(
compilation.compileKotlinTaskName, compilation.compileKotlinTaskName
KotlinNativeCompile::class.java ) {
).also { task -> it.compilation = compilation
task.compilation = compilation it.group = BasePlugin.BUILD_GROUP
task.group = BasePlugin.BUILD_GROUP it.description = "Compiles a klibrary from the '${compilation.name}' " +
task.description = "Compiles a klibrary from the '${compilation.name}' " +
"compilation for target '${compilation.platformType.name}'." "compilation for target '${compilation.platformType.name}'."
task.enabled = compilation.konanTarget.enabledOnCurrentHost it.enabled = compilation.konanTarget.enabledOnCurrentHost
task.destinationDir = klibOutputDirectory(compilation) it.destinationDir = klibOutputDirectory(compilation)
task.addCompilerPlugins()
compilation.output.addClassesDir {
project.files(task.outputFile).builtBy(task)
}
} }
project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTask)
compilation.output.addClassesDir {
project.files(compileTaskProvider.map { it.outputFile })
}
project.tasks.getByName(compilation.compileAllTaskName).dependsOn(compileTaskProvider)
if (compilation.isMain()) { if (compilation.isMain()) {
compilation as? KotlinNativeCompilation ?: error("Main shared-Native compilation is not yet supported!") compilation as? KotlinNativeCompilation ?: error("Main shared-Native compilation is not yet supported!")
project.tasks.getByName(compilation.target.artifactsTaskName).apply { project.tasks.getByName(compilation.target.artifactsTaskName).apply {
dependsOn(compileTask) dependsOn(compileTaskProvider)
} }
project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply { project.tasks.getByName(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).apply {
dependsOn(compileTask) dependsOn(compileTaskProvider)
} }
createRegularKlibArtifact(compilation, compileTask) createRegularKlibArtifact(compilation, compileTaskProvider)
} }
return compileTask
return compileTaskProvider
} }
private fun Project.createCInteropTasks(compilation: KotlinNativeCompilation) { private fun Project.createCInteropTasks(compilation: KotlinNativeCompilation) {
compilation.cinterops.all { interop -> compilation.cinterops.all { interop ->
val interopTask = tasks.create(interop.interopProcessingTaskName, CInteropProcess::class.java).apply { val interopTask = registerTask<CInteropProcess>(interop.interopProcessingTaskName) {
settings = interop it.settings = interop
destinationDir = provider { klibOutputDirectory(compilation) } it.destinationDir = provider { klibOutputDirectory(compilation) }
group = INTEROP_GROUP it.group = INTEROP_GROUP
description = "Generates Kotlin/Native interop library '${interop.name}' " + it.description = "Generates Kotlin/Native interop library '${interop.name}' " +
"for compilation '${compilation.name}'" + "for compilation '${compilation.name}'" +
"of target '${konanTarget.name}'." "of target '${it.konanTarget.name}'."
enabled = compilation.konanTarget.enabledOnCurrentHost it.enabled = compilation.konanTarget.enabledOnCurrentHost
}
val interopOutput = project.files(outputFileProvider).builtBy(this) val interopOutput = project.files(interopTask.map { it.outputFileProvider })
with(compilation) { with(compilation) {
// Register the interop library as a dependency of the compilation to make IDE happy. // Register the interop library as a dependency of the compilation to make IDE happy.
project.dependencies.add(compileDependencyConfigurationName, interopOutput) project.dependencies.add(compileDependencyConfigurationName, interopOutput)
if (isMain()) { if (isMain()) {
// Register the interop library as an outgoing klib to allow depending on projects with cinterops. // Register the interop library as an outgoing klib to allow depending on projects with cinterops.
project.dependencies.add(target.apiElementsConfigurationName, interopOutput) project.dependencies.add(target.apiElementsConfigurationName, interopOutput)
// Add the interop library in publication. // Add the interop library in publication.
createCInteropKlibArtifact(interop, this@apply) createCInteropKlibArtifact(interop, interopTask)
// We cannot add the interop library in an compilation output because in this case // We cannot add the interop library in an compilation output because in this case
// IDE doesn't see this library in module dependencies. So we have to manually add // IDE doesn't see this library in module dependencies. So we have to manually add
// main interop libraries in dependencies of the default test compilation. // main interop libraries in dependencies of the default test compilation.
target.compilations.findByName(TEST_COMPILATION_NAME)?.let { testCompilation -> target.compilations.findByName(TEST_COMPILATION_NAME)?.let { testCompilation ->
project.dependencies.add(testCompilation.compileDependencyConfigurationName, interopOutput) project.dependencies.add(testCompilation.compileDependencyConfigurationName, interopOutput)
testCompilation.cinterops.all { testCompilation.cinterops.all {
it.dependencyFiles += interopOutput it.dependencyFiles += interopOutput
}
} }
} }
} }
@@ -232,7 +230,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
} }
override fun configureArchivesAndComponent(target: T): Unit = with(target.project) { override fun configureArchivesAndComponent(target: T): Unit = with(target.project) {
tasks.create(target.artifactsTaskName) registerTask<DefaultTask>(target.artifactsTaskName) { }
target.compilations.all { target.compilations.all {
createKlibCompilationTask(it) createKlibCompilationTask(it)
} }
@@ -280,12 +278,14 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget>(
// Create an aggregate link task for each compilation. // Create an aggregate link task for each compilation.
target.compilations.all { target.compilations.all {
project.tasks.create(it.binariesTaskName) project.registerTask<DefaultTask>(it.binariesTaskName)
} }
project.whenEvaluated { project.whenEvaluated {
target.binaries.forEach { target.binaries.forEach { binary ->
project.tasks.getByName(it.compilation.binariesTaskName).dependsOn(it.linkTaskName) project.tasks.named(binary.compilation.binariesTaskName).configure { binariesTask ->
binariesTask.dependsOn(binary.linkTaskName)
}
} }
} }
@@ -13,6 +13,7 @@ import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency import org.gradle.api.artifacts.Dependency
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.tasks.AbstractExecTask import org.gradle.api.tasks.AbstractExecTask
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -79,7 +80,10 @@ sealed class NativeBinary(
get() = lowerCamelCaseName("link", name, target.targetName) get() = lowerCamelCaseName("link", name, target.targetName)
val linkTask: KotlinNativeLink val linkTask: KotlinNativeLink
get() = project.tasks.getByName(linkTaskName) as KotlinNativeLink get() = linkTaskProvider.get()
val linkTaskProvider: TaskProvider<out KotlinNativeLink>
get() = project.tasks.withType(KotlinNativeLink::class.java).named(linkTaskName)
// Output access. // Output access.
// TODO: Provide output configurations and integrate them with Gradle Native. // TODO: Provide output configurations and integrate them with Gradle Native.
@@ -9,7 +9,9 @@ package org.jetbrains.kotlin.gradle.plugin.cocoapods
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Sync import org.gradle.api.tasks.Sync
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
@@ -20,10 +22,7 @@ import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildSettingsProperti
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildTask import org.jetbrains.kotlin.gradle.targets.native.tasks.PodBuildTask
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodInstallTask import org.jetbrains.kotlin.gradle.targets.native.tasks.PodInstallTask
import org.jetbrains.kotlin.gradle.targets.native.tasks.PodSetupBuildTask import org.jetbrains.kotlin.gradle.targets.native.tasks.PodSetupBuildTask
import org.jetbrains.kotlin.gradle.tasks.DefFileTask import org.jetbrains.kotlin.gradle.tasks.*
import org.jetbrains.kotlin.gradle.tasks.DummyFrameworkTask
import org.jetbrains.kotlin.gradle.tasks.FatFrameworkTask
import org.jetbrains.kotlin.gradle.tasks.PodspecTask
import org.jetbrains.kotlin.gradle.utils.asValidTaskName import org.jetbrains.kotlin.gradle.utils.asValidTaskName
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
@@ -84,9 +83,8 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
} }
} }
private fun Project.createSyncFrameworkTask(originalDirectory: File, buildingTask: Task): Sync? { private fun Project.createSyncFrameworkTask(originalDirectory: Provider<File>, buildingTask: TaskProvider<*>) =
registerTask<Sync>(SYNC_TASK_NAME) {
return tasks.create(SYNC_TASK_NAME, Sync::class.java) {
it.group = TASK_GROUP it.group = TASK_GROUP
it.description = "Copies a framework for given platform and build type into the CocoaPods build directory" it.description = "Copies a framework for given platform and build type into the CocoaPods build directory"
@@ -94,7 +92,6 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
it.from(originalDirectory) it.from(originalDirectory)
it.destinationDir = cocoapodsBuildDirs.framework it.destinationDir = cocoapodsBuildDirs.framework
} }
}
private fun createSyncForFatFramework( private fun createSyncForFatFramework(
project: Project, project: Project,
@@ -114,7 +111,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
} }
} }
val fatFrameworkTask = project.tasks.create("fatFramework", FatFrameworkTask::class.java) { task -> val fatFrameworkTask = project.registerTask<FatFrameworkTask>("fatFramework") { task ->
task.group = TASK_GROUP task.group = TASK_GROUP
task.description = "Creates a fat framework for ARM32 and ARM64 architectures" task.description = "Creates a fat framework for ARM32 and ARM64 architectures"
task.destinationDir = project.cocoapodsBuildDirs.fatFramework(requestedBuildType) task.destinationDir = project.cocoapodsBuildDirs.fatFramework(requestedBuildType)
@@ -126,7 +123,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
} }
} }
project.createSyncFrameworkTask(fatFrameworkTask.destinationDir, fatFrameworkTask) project.createSyncFrameworkTask(fatFrameworkTask.map { it.destinationDir }, fatFrameworkTask)
} }
private fun createSyncForRegularFramework( private fun createSyncForRegularFramework(
@@ -140,8 +137,8 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
check(targets.isNotEmpty()) { "The project doesn't contain a target for the requested platform: `${requestedPlatform.visibleName}`" } check(targets.isNotEmpty()) { "The project doesn't contain a target for the requested platform: `${requestedPlatform.visibleName}`" }
check(targets.size == 1) { "The project has more than one target for the requested platform: `${requestedPlatform.visibleName}`" } check(targets.size == 1) { "The project has more than one target for the requested platform: `${requestedPlatform.visibleName}`" }
val frameworkLinkTask = targets.single().binaries.getFramework(requestedBuildType).linkTask val frameworkLinkTask = targets.single().binaries.getFramework(requestedBuildType).linkTaskProvider
project.createSyncFrameworkTask(frameworkLinkTask.destinationDir, frameworkLinkTask) project.createSyncFrameworkTask(frameworkLinkTask.map { it.destinationDir }, frameworkLinkTask)
} }
private fun createSyncTask( private fun createSyncTask(
@@ -183,10 +180,8 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
} }
moduleNames.add(pod.moduleName) moduleNames.add(pod.moduleName)
val defTask = project.tasks.create( val defTask = project.registerTask<DefFileTask>(
lowerCamelCaseName("generateDef", pod.moduleName).asValidTaskName(), lowerCamelCaseName("generateDef", pod.moduleName).asValidTaskName()) {
DefFileTask::class.java
) {
it.pod = pod it.pod = pod
it.description = "Generates a def file for CocoaPods dependencies with module ${pod.moduleName}" it.description = "Generates a def file for CocoaPods dependencies with module ${pod.moduleName}"
// This task is an implementation detail so we don't add it in any group // This task is an implementation detail so we don't add it in any group
@@ -200,7 +195,7 @@ open class KotlinCocoapodsPlugin : Plugin<Project> {
interopTask.dependsOn(defTask) interopTask.dependsOn(defTask)
interop.defFile = defTask.outputFile interop.defFile.set(defTask.map { it.outputFile })
interop.packageName = "cocoapods.${pod.moduleName}" interop.packageName = "cocoapods.${pod.moduleName}"
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.addExtension import org.jetbrains.kotlin.gradle.plugin.addExtension
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
import org.jetbrains.kotlin.gradle.targets.native.tasks.NativePerformanceReport import org.jetbrains.kotlin.gradle.targets.native.tasks.NativePerformanceReport
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import java.io.File import java.io.File
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@@ -68,17 +69,14 @@ open class KotlinPerformancePlugin : Plugin<Project> {
val timeListener = TaskTimerListener(project) val timeListener = TaskTimerListener(project)
project.gradle.addListener(timeListener) project.gradle.addListener(timeListener)
performanceExtension.trackedBinaries.forEach { binary -> performanceExtension.trackedBinaries.forEach { binary ->
project.tasks.create( val perfReport = project.registerTask<NativePerformanceReport>(binary.target.disambiguateName(lowerCamelCaseName("perfReport", binary.name))) {
binary.target.disambiguateName(lowerCamelCaseName("perfReport", binary.name)),
NativePerformanceReport::class.java
) {
it.binary = binary it.binary = binary
it.settings = performanceExtension it.settings = performanceExtension
it.timeListener = timeListener it.timeListener = timeListener
it.group = TASK_GROUP it.group = TASK_GROUP
it.description = "Report performance measurement results for binary '${binary.name}' of target '${binary.target.name}'." it.description = "Report performance measurement results for binary '${binary.name}' of target '${binary.target.name}'."
binary.linkTask.finalizedBy(it)
} }
binary.linkTaskProvider.configure { linkTask -> linkTask.finalizedBy(perfReport) }
} }
} }
@@ -966,7 +966,7 @@ open class CInteropProcess : DefaultTask() {
project.provider { destinationDir.get().resolve(outputFileName) } project.provider { destinationDir.get().resolve(outputFileName) }
val defFile: File val defFile: File
@InputFile get() = settings.defFile @InputFile get() = settings.defFile.get()
val packageName: String? val packageName: String?
@Optional @Input get() = settings.packageName @Optional @Input get() = settings.packageName
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.UnknownTaskException import org.gradle.api.UnknownTaskException
import org.gradle.api.tasks.TaskCollection
import org.gradle.api.tasks.TaskProvider import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties import org.jetbrains.kotlin.gradle.plugin.mapKotlinTaskProperties
@@ -39,7 +40,7 @@ internal fun <T : Task> registerTask(project: Project, name: String, type: Class
internal inline fun <reified T : Task> Project.registerTask( internal inline fun <reified T : Task> Project.registerTask(
name: String, name: String,
args: List<Any> = emptyList(), args: List<Any> = emptyList(),
noinline body: (T) -> (Unit) noinline body: ((T) -> (Unit))? = null
): TaskProvider<T> = ): TaskProvider<T> =
this@registerTask.registerTask(name, T::class.java, args, body) this@registerTask.registerTask(name, T::class.java, args, body)
@@ -47,11 +48,18 @@ internal fun <T : Task> Project.registerTask(
name: String, name: String,
type: Class<T>, type: Class<T>,
constructorArgs: List<Any> = emptyList(), constructorArgs: List<Any> = emptyList(),
body: (T) -> (Unit) body: ((T) -> (Unit))? = null
): TaskProvider<T> { ): TaskProvider<T> {
return project.tasks.register(name, type, *constructorArgs.toTypedArray()).apply { configure(body) } val resultProvider = project.tasks.register(name, type, *constructorArgs.toTypedArray())
if (body != null) {
resultProvider.configure(body)
}
return resultProvider
} }
internal fun TaskProvider<*>.dependsOn(other: TaskProvider<*>) = configure { it.dependsOn(other) }
internal inline fun <reified S : Task> TaskCollection<in S>.withType(): TaskCollection<S> = withType(S::class.java)
/** /**
* Locates a task by [name] and [type], without triggering its creation or configuration. * Locates a task by [name] and [type], without triggering its creation or configuration.