Make ClangFrontend cacheable

Co-authored-by: Alexander Shabalin <Alexander.Shabalin@jetbrains.com>


Merge-request: KT-MR-11479
Merged-by: Cristian Garcia <Cristian.Garcia-Marin@jetbrains.com>
This commit is contained in:
cristiangarcia
2023-10-24 09:50:02 +00:00
committed by Space Team
parent b3e13fb2c2
commit 03ad981dea
@@ -11,6 +11,7 @@ import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.ListProperty import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.gradle.kotlin.dsl.getByType import org.gradle.kotlin.dsl.getByType
import org.gradle.workers.WorkAction import org.gradle.workers.WorkAction
@@ -18,6 +19,8 @@ import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.ExecClang import org.jetbrains.kotlin.ExecClang
import org.jetbrains.kotlin.bitcode.CompileToBitcodePlugin import org.jetbrains.kotlin.bitcode.CompileToBitcodePlugin
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.PlatformManager import org.jetbrains.kotlin.konan.target.PlatformManager
import java.io.File import java.io.File
import javax.inject.Inject import javax.inject.Inject
@@ -57,13 +60,19 @@ private abstract class ClangFrontendJob : WorkAction<ClangFrontendJob.Parameters
* *
* @see CompileToBitcodePlugin * @see CompileToBitcodePlugin
*/ */
abstract class ClangFrontend : DefaultTask() { @CacheableTask
abstract class ClangFrontend @Inject constructor(
private val workerExecutor: WorkerExecutor,
private val objects: ObjectFactory,
private val layout: ProjectLayout,
providers: ProviderFactory,
) : DefaultTask() {
private data class WorkUnit( private data class WorkUnit(
val inputFile: File, val inputFile: File,
val outputFile: File, val outputFile: File,
) )
private val workUnits: Provider<List<WorkUnit>> = project.provider { private val workUnits: Provider<List<WorkUnit>> = providers.provider {
val result = mutableListOf<WorkUnit>() val result = mutableListOf<WorkUnit>()
inputFiles.visit { inputFiles.visit {
if (!isDirectory) { if (!isDirectory) {
@@ -87,13 +96,14 @@ abstract class ClangFrontend : DefaultTask() {
*/ */
@get:SkipWhenEmpty @get:SkipWhenEmpty
@get:InputFiles @get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val inputFiles: ConfigurableFileTree abstract val inputFiles: ConfigurableFileTree
/** /**
* Bitcode files generated by clang. * Bitcode files generated by clang.
*/ */
@get:OutputFiles @get:OutputFiles
val outputFiles: FileCollection = project.files(workUnits.map { it.map { workUnit -> workUnit.outputFile } }) val outputFiles: FileCollection = layout.files(workUnits.map { it.map { workUnit -> workUnit.outputFile } })
/** /**
* Will select the appropriate compiler and additional flags. * Will select the appropriate compiler and additional flags.
@@ -108,13 +118,12 @@ abstract class ClangFrontend : DefaultTask() {
* Currently only `clang` and `clang++` are supported. * Currently only `clang` and `clang++` are supported.
*/ */
@get:Input @get:Input
abstract val compiler: Property<String> val compiler: Property<String> = objects.property(String::class.java)
/** /**
* Extra arguments for [compiler]. * Extra arguments for [compiler].
*/ */
// Marked as input via [compilerFlags]. @get:Input
@get:Internal
abstract val arguments: ListProperty<String> abstract val arguments: ListProperty<String>
/** /**
@@ -122,15 +131,16 @@ abstract class ClangFrontend : DefaultTask() {
* *
* Will be passed to the compiler as `-I…` and will also be used to compute task dependencies: recompile if the headers change. * Will be passed to the compiler as `-I…` and will also be used to compute task dependencies: recompile if the headers change.
*/ */
// Marked as input via [headers] and [compilerFlags]. // Marked as input via [headers].
@get:Internal @get:Internal
abstract val headersDirs: ConfigurableFileCollection abstract val headersDirs: ConfigurableFileCollection
/** /**
* Final computed compiler arguments. * Final computed compiler arguments.
*/ */
@get:Input // Marked as input via [headers] and [arguments].
val compilerFlags: Provider<List<String>> = project.provider { @get:Internal
val compilerFlags: Provider<List<String>> = providers.provider {
listOfNotNull( listOfNotNull(
"-c", "-c",
"-emit-llvm" "-emit-llvm"
@@ -143,18 +153,19 @@ abstract class ClangFrontend : DefaultTask() {
* All inputs will be passed to the compiler as relative paths to this directory. * All inputs will be passed to the compiler as relative paths to this directory.
*/ */
@get:Internal @get:Internal
abstract val workingDirectory: DirectoryProperty val workingDirectory: DirectoryProperty = objects.directoryProperty()
@get:Input @get:Input
protected val workingDirectoryPath: Provider<String> = project.provider { protected val workingDirectoryPath: Provider<String> = workingDirectory.map {
workingDirectory.get().asFile.absolutePath it.asFile.toRelativeString(layout.projectDirectory.asFile)
} }
/** /**
* Computed header files used for task dependencies tracking. * Computed header files used for task dependencies tracking.
*/ */
@get:InputFiles @get:InputFiles
protected val headers: Provider<List<File>> = project.provider { @get:PathSensitive(PathSensitivity.RELATIVE)
protected val headers: Provider<FileTree> = providers.provider {
// Not using clang's -M* flags because there's a problem with our current include system: // Not using clang's -M* flags because there's a problem with our current include system:
// We allow includes relative to the current directory and also pass -I for each imported module // We allow includes relative to the current directory and also pass -I for each imported module
// Given file tree: // Given file tree:
@@ -177,17 +188,25 @@ abstract class ClangFrontend : DefaultTask() {
} }
// Now add manually given header dirs. // Now add manually given header dirs.
dirs.addAll(headersDirs.files) dirs.addAll(headersDirs.files)
dirs.flatMap { dir -> layout.files(dirs).asFileTree.matching {
project.fileTree(dir) { include("**/*.h", "**/*.hpp")
include("**/*.h", "**/*.hpp")
}.files
} }
} }
@get:Inject
protected abstract val workerExecutor: WorkerExecutor
private val platformManager = project.extensions.getByType<PlatformManager>() private val platformManager = project.extensions.getByType<PlatformManager>()
private val execClang by lazy { ExecClang.create(objects, platformManager) }
// TODO: Consider configuring full clang execution from the plugin instead.
@get:InputFile
@get:PathSensitive(PathSensitivity.NONE)
val executable: Provider<RegularFile> = layout.file(compiler.map {
val executable = execClang.resolveExecutable(it)
val executableSuffix = when (HostManager.host.family) {
Family.MINGW -> ".exe"
else -> ""
}
File("$executable$executableSuffix")
})
@TaskAction @TaskAction
fun compile() { fun compile() {