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.Property
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.*
import org.gradle.kotlin.dsl.getByType
import org.gradle.workers.WorkAction
@@ -18,6 +19,8 @@ import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.ExecClang
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 java.io.File
import javax.inject.Inject
@@ -57,13 +60,19 @@ private abstract class ClangFrontendJob : WorkAction<ClangFrontendJob.Parameters
*
* @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(
val inputFile: File,
val outputFile: File,
)
private val workUnits: Provider<List<WorkUnit>> = project.provider {
private val workUnits: Provider<List<WorkUnit>> = providers.provider {
val result = mutableListOf<WorkUnit>()
inputFiles.visit {
if (!isDirectory) {
@@ -87,13 +96,14 @@ abstract class ClangFrontend : DefaultTask() {
*/
@get:SkipWhenEmpty
@get:InputFiles
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val inputFiles: ConfigurableFileTree
/**
* Bitcode files generated by clang.
*/
@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.
@@ -108,13 +118,12 @@ abstract class ClangFrontend : DefaultTask() {
* Currently only `clang` and `clang++` are supported.
*/
@get:Input
abstract val compiler: Property<String>
val compiler: Property<String> = objects.property(String::class.java)
/**
* Extra arguments for [compiler].
*/
// Marked as input via [compilerFlags].
@get:Internal
@get:Input
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.
*/
// Marked as input via [headers] and [compilerFlags].
// Marked as input via [headers].
@get:Internal
abstract val headersDirs: ConfigurableFileCollection
/**
* Final computed compiler arguments.
*/
@get:Input
val compilerFlags: Provider<List<String>> = project.provider {
// Marked as input via [headers] and [arguments].
@get:Internal
val compilerFlags: Provider<List<String>> = providers.provider {
listOfNotNull(
"-c",
"-emit-llvm"
@@ -143,18 +153,19 @@ abstract class ClangFrontend : DefaultTask() {
* All inputs will be passed to the compiler as relative paths to this directory.
*/
@get:Internal
abstract val workingDirectory: DirectoryProperty
val workingDirectory: DirectoryProperty = objects.directoryProperty()
@get:Input
protected val workingDirectoryPath: Provider<String> = project.provider {
workingDirectory.get().asFile.absolutePath
protected val workingDirectoryPath: Provider<String> = workingDirectory.map {
it.asFile.toRelativeString(layout.projectDirectory.asFile)
}
/**
* Computed header files used for task dependencies tracking.
*/
@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:
// We allow includes relative to the current directory and also pass -I for each imported module
// Given file tree:
@@ -177,17 +188,25 @@ abstract class ClangFrontend : DefaultTask() {
}
// Now add manually given header dirs.
dirs.addAll(headersDirs.files)
dirs.flatMap { dir ->
project.fileTree(dir) {
include("**/*.h", "**/*.hpp")
}.files
layout.files(dirs).asFileTree.matching {
include("**/*.h", "**/*.hpp")
}
}
@get:Inject
protected abstract val workerExecutor: WorkerExecutor
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
fun compile() {