[K/N] Modernize CompileToBitcode
Merge-request: KT-MR-6367 Merged-by: Alexander Shabalin <Alexander.Shabalin@jetbrains.com>
This commit is contained in:
committed by
Space
parent
8d79fab109
commit
bfe0d4108b
+162
-183
@@ -6,34 +6,43 @@
|
||||
package org.jetbrains.kotlin.bitcode
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.ConfigurableFileCollection
|
||||
import org.gradle.api.file.ConfigurableFileTree
|
||||
import org.gradle.api.file.DirectoryProperty
|
||||
import org.gradle.api.file.RegularFileProperty
|
||||
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.tasks.*
|
||||
import org.gradle.kotlin.dsl.getByType
|
||||
import org.jetbrains.kotlin.ExecClang
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
import kotlinBuildProperties
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.process.ExecOperations
|
||||
import org.gradle.workers.WorkAction
|
||||
import org.gradle.workers.WorkParameters
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.ExecClang
|
||||
import org.jetbrains.kotlin.execLlvmUtility
|
||||
import org.jetbrains.kotlin.konan.target.*
|
||||
import org.jetbrains.kotlin.platformManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.PlatformManager
|
||||
import org.jetbrains.kotlin.konan.target.SanitizerKind
|
||||
import org.jetbrains.kotlin.utils.Maybe
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
interface CompileToBitcodeParameters : WorkParameters {
|
||||
var objDir: File
|
||||
var target: String
|
||||
var compilerExecutable: String
|
||||
var compilerArgs: List<String>
|
||||
var llvmLinkArgs: List<String>
|
||||
val platformManager: Property<PlatformManager>
|
||||
}
|
||||
private abstract class CompileToBitcodeJob : WorkAction<CompileToBitcodeJob.Parameters> {
|
||||
interface Parameters : WorkParameters {
|
||||
val workingDirectory: DirectoryProperty
|
||||
// TODO: Figure out a way to pass KonanTarget, but it is used as a key into PlatformManager,
|
||||
// so object identity matters, and platform managers are different between project and worker sides.
|
||||
val targetName: Property<String>
|
||||
val compilerExecutable: Property<String>
|
||||
val compilerInputFiles: ConfigurableFileCollection
|
||||
val compilerArgs: ListProperty<String>
|
||||
val llvmLinkOutputFile: RegularFileProperty
|
||||
val llvmLinkArgs: ListProperty<String>
|
||||
val platformManager: Property<PlatformManager>
|
||||
}
|
||||
|
||||
abstract class CompileToBitcodeJob : WorkAction<CompileToBitcodeParameters> {
|
||||
@get:Inject
|
||||
abstract val objects: ObjectFactory
|
||||
|
||||
@@ -42,199 +51,169 @@ abstract class CompileToBitcodeJob : WorkAction<CompileToBitcodeParameters> {
|
||||
|
||||
override fun execute() {
|
||||
with(parameters) {
|
||||
objDir.mkdirs()
|
||||
workingDirectory.asFile.get().mkdirs()
|
||||
|
||||
val execClang = ExecClang.create(objects, platformManager.get())
|
||||
|
||||
execClang.execKonanClang(target) {
|
||||
workingDir = objDir
|
||||
executable = compilerExecutable
|
||||
args = compilerArgs
|
||||
// TODO: Compile each input separately and make workingDir point to src root.
|
||||
execClang.execKonanClang(targetName.get()) {
|
||||
workingDir = workingDirectory.asFile.get()
|
||||
executable = compilerExecutable.get()
|
||||
args = compilerArgs.get() + compilerInputFiles.map { it.absolutePath }
|
||||
}
|
||||
|
||||
val compilerOutputFiles = compilerInputFiles.map { workingDirectory.file("${it.nameWithoutExtension}.bc").get().asFile }
|
||||
|
||||
// TODO: Extract llvm-link out. This will allow parallelizing clang compilation.
|
||||
execOperations.execLlvmUtility(platformManager.get(), "llvm-link") {
|
||||
args = llvmLinkArgs
|
||||
args = listOf("-o", llvmLinkOutputFile.asFile.get().absolutePath) + llvmLinkArgs.get() + compilerOutputFiles.map { it.absolutePath }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Compiling files with clang into LLVM bitcode.
|
||||
*
|
||||
* Compiles [inputFiles] into [outputFile] with [compiler] and `llvm-link`.
|
||||
*
|
||||
* @property target target for which to compile
|
||||
* @see CompileToBitcodePlugin
|
||||
*/
|
||||
abstract class CompileToBitcode @Inject constructor(
|
||||
@Input val folderName: String,
|
||||
@Input val target: String,
|
||||
@Input val outputGroup: String
|
||||
@Input val target: KonanTarget,
|
||||
private val _sanitizer: Maybe<SanitizerKind>,
|
||||
) : DefaultTask() {
|
||||
|
||||
enum class Language {
|
||||
C, CPP
|
||||
/**
|
||||
* Compile with sanitizer enabled.
|
||||
*/
|
||||
@get:Input
|
||||
@get:Optional
|
||||
val sanitizer
|
||||
get() = _sanitizer.orNull
|
||||
|
||||
/**
|
||||
* Final output file.
|
||||
*/
|
||||
@get:OutputFile
|
||||
abstract val outputFile: RegularFileProperty
|
||||
|
||||
/**
|
||||
* Where to put bitcode files generated by clang.
|
||||
*/
|
||||
// TODO: Generate output files for this.
|
||||
@get:Internal
|
||||
abstract val outputDirectory: DirectoryProperty
|
||||
|
||||
/**
|
||||
* The compiler to be used.
|
||||
*
|
||||
* Currently only `clang` and `clang++` are supported.
|
||||
*/
|
||||
@get:Input
|
||||
abstract val compiler: Property<String>
|
||||
|
||||
/**
|
||||
* Extra arguments for `llvm-link`.
|
||||
*/
|
||||
@get:Input
|
||||
abstract val linkerArgs: ListProperty<String>
|
||||
|
||||
/**
|
||||
* Extra arguments for [compiler].
|
||||
*/
|
||||
// Marked as input via [compilerFlags].
|
||||
@get:Internal
|
||||
abstract val compilerArgs: ListProperty<String>
|
||||
|
||||
/**
|
||||
* Locations to search for headers.
|
||||
*
|
||||
* 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].
|
||||
@get:Internal
|
||||
abstract val headersDirs: ConfigurableFileCollection
|
||||
|
||||
// TODO: Move to module description.
|
||||
@get:Internal
|
||||
abstract val moduleName: Property<String>
|
||||
|
||||
/**
|
||||
* Final computed compiler arguments.
|
||||
*/
|
||||
@get:Input
|
||||
val compilerFlags: Provider<List<String>> = project.provider {
|
||||
listOfNotNull(
|
||||
"-c",
|
||||
"-emit-llvm"
|
||||
) + headersDirs.map { "-I${it.absolutePath}" } + when (sanitizer) {
|
||||
null -> listOf()
|
||||
SanitizerKind.ADDRESS -> listOf("-fsanitize=address")
|
||||
SanitizerKind.THREAD -> listOf("-fsanitize=thread")
|
||||
} + compilerArgs.get()
|
||||
}
|
||||
|
||||
// Compiler args are part of compilerFlags so we don't register them as an input.
|
||||
@Internal
|
||||
val compilerArgs = mutableListOf<String>()
|
||||
@Input
|
||||
val linkerArgs = mutableListOf<String>()
|
||||
@Input
|
||||
var excludeFiles: List<String> = listOf(
|
||||
"**/*Test.cpp",
|
||||
"**/*TestSupport.cpp",
|
||||
"**/*Test.mm",
|
||||
"**/*TestSupport.mm"
|
||||
)
|
||||
@Input
|
||||
var includeFiles: List<String> = listOf(
|
||||
"**/*.cpp",
|
||||
"**/*.mm"
|
||||
)
|
||||
|
||||
// Source files and headers are registered as inputs by the `inputFiles` and `headers` properties.
|
||||
@Internal
|
||||
var srcDirs: FileCollection = project.files()
|
||||
@Internal
|
||||
var headersDirs: FileCollection = project.files()
|
||||
|
||||
@Input
|
||||
var language = Language.CPP
|
||||
|
||||
@Input @Optional
|
||||
var sanitizer: SanitizerKind? = null
|
||||
|
||||
@Input @Optional
|
||||
val extraSanitizerArgs = mutableMapOf<SanitizerKind, List<String>>()
|
||||
|
||||
private val targetDir: File
|
||||
get() {
|
||||
val sanitizerSuffix = when (sanitizer) {
|
||||
null -> ""
|
||||
SanitizerKind.ADDRESS -> "-asan"
|
||||
SanitizerKind.THREAD -> "-tsan"
|
||||
}
|
||||
return project.buildDir.resolve("bitcode/$outputGroup/$target$sanitizerSuffix")
|
||||
}
|
||||
|
||||
@get:Internal
|
||||
val objDir
|
||||
get() = File(targetDir, folderName)
|
||||
|
||||
private val KonanTarget.isMINGW
|
||||
get() = this.family == Family.MINGW
|
||||
|
||||
@get:Internal
|
||||
val executable
|
||||
get() = when (language) {
|
||||
Language.C -> "clang"
|
||||
Language.CPP -> "clang++"
|
||||
}
|
||||
|
||||
@get:Input
|
||||
val compilerFlags: List<String>
|
||||
get() {
|
||||
val commonFlags = listOfNotNull(
|
||||
"-gdwarf-2".takeIf { project.kotlinBuildProperties.getBoolean("kotlin.native.isNativeRuntimeDebugInfoEnabled", false) },
|
||||
"-c", "-emit-llvm") + headersDirs.map { "-I$it" }
|
||||
val sanitizerFlags = when (sanitizer) {
|
||||
null -> listOf()
|
||||
SanitizerKind.ADDRESS -> listOf("-fsanitize=address")
|
||||
SanitizerKind.THREAD -> listOf("-fsanitize=thread")
|
||||
} + (extraSanitizerArgs[sanitizer] ?: emptyList())
|
||||
val languageFlags = when (language) {
|
||||
Language.C -> {
|
||||
listOf("-std=gnu11", "-Wall", "-Wextra", "-Werror") +
|
||||
if (sanitizer != SanitizerKind.THREAD) {
|
||||
// Used flags provided by original build of allocator C code.
|
||||
listOf("-O3")
|
||||
} else {
|
||||
// Building with TSAN needs turning off extra optimizations.
|
||||
listOf("-O1")
|
||||
}
|
||||
}
|
||||
Language.CPP ->
|
||||
listOfNotNull("-std=c++17", "-Werror", "-O2",
|
||||
"-fno-aligned-allocation", // TODO: Remove when all targets support aligned allocation in C++ runtime.
|
||||
"-Wall", "-Wextra",
|
||||
"-Wno-unused-parameter" // False positives with polymorphic functions.
|
||||
)
|
||||
}
|
||||
return commonFlags + sanitizerFlags + languageFlags + compilerArgs
|
||||
}
|
||||
|
||||
/**
|
||||
* Source files to compile from.
|
||||
*/
|
||||
@get:SkipWhenEmpty
|
||||
@get:InputFiles
|
||||
val inputFiles: Iterable<File>
|
||||
get() {
|
||||
return srcDirs.flatMap { srcDir ->
|
||||
project.fileTree(srcDir) {
|
||||
include(includeFiles)
|
||||
exclude(excludeFiles)
|
||||
}.files
|
||||
}
|
||||
}
|
||||
|
||||
private fun outputFileForInputFile(file: File, extension: String) = objDir.resolve("${file.nameWithoutExtension}.${extension}")
|
||||
private fun bitcodeFileForInputFile(file: File) = outputFileForInputFile(file, "bc")
|
||||
abstract val inputFiles: ConfigurableFileTree
|
||||
|
||||
/**
|
||||
* Computed header files used for task dependencies tracking.
|
||||
*/
|
||||
@get:InputFiles
|
||||
protected val headers: Iterable<File>
|
||||
get() {
|
||||
// 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:
|
||||
// a:
|
||||
// header.hpp
|
||||
// b:
|
||||
// impl.cpp
|
||||
// Assume module b adds a to its include path.
|
||||
// If b/impl.cpp has #include "header.hpp", it'll be included from a/header.hpp. If we add another file
|
||||
// header.hpp into b/, the next compilation of b/impl.cpp will include b/header.hpp. -M flags, however,
|
||||
// won't generate a dependency on b/header.hpp, so incremental compilation will be broken.
|
||||
// TODO: Apart from dependency generation this also makes it awkward to have two files with
|
||||
// the same name (e.g. Utils.h) in directories a/ and b/: For the b/impl.cpp to include a/header.hpp
|
||||
// it needs to have #include "../a/header.hpp"
|
||||
protected val headers: Provider<List<File>> = project.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:
|
||||
// a:
|
||||
// header.hpp
|
||||
// b:
|
||||
// impl.cpp
|
||||
// Assume module b adds a to its include path.
|
||||
// If b/impl.cpp has #include "header.hpp", it'll be included from a/header.hpp. If we add another file
|
||||
// header.hpp into b/, the next compilation of b/impl.cpp will include b/header.hpp. -M flags, however,
|
||||
// won't generate a dependency on b/header.hpp, so incremental compilation will be broken.
|
||||
// TODO: Apart from dependency generation this also makes it awkward to have two files with
|
||||
// the same name (e.g. Utils.h) in directories a/ and b/: For the b/impl.cpp to include a/header.hpp
|
||||
// it needs to have #include "../a/header.hpp"
|
||||
|
||||
val dirs = mutableSetOf<File>()
|
||||
// First add dirs with sources, as clang by default adds directory with the source to the include path.
|
||||
inputFiles.forEach {
|
||||
dirs.add(it.parentFile)
|
||||
}
|
||||
// Now add manually given header dirs.
|
||||
dirs.addAll(headersDirs.files)
|
||||
return dirs.flatMap { dir ->
|
||||
project.fileTree(dir) {
|
||||
val includePatterns = when (language) {
|
||||
Language.C -> arrayOf("**/.h")
|
||||
Language.CPP -> arrayOf("**/*.h", "**/*.hpp")
|
||||
}
|
||||
include(*includePatterns)
|
||||
}.files
|
||||
}
|
||||
val dirs = mutableSetOf<File>()
|
||||
// First add dirs with sources, as clang by default adds directory with the source to the include path.
|
||||
inputFiles.forEach {
|
||||
dirs.add(it.parentFile)
|
||||
}
|
||||
|
||||
@Input
|
||||
var outputName = "${folderName}.bc"
|
||||
|
||||
@get:OutputFile
|
||||
val outFile: File
|
||||
get() = File(targetDir, outputName)
|
||||
// Now add manually given header dirs.
|
||||
dirs.addAll(headersDirs.files)
|
||||
dirs.flatMap { dir ->
|
||||
project.fileTree(dir) {
|
||||
include("**/*.h", "**/*.hpp")
|
||||
}.files
|
||||
}
|
||||
}
|
||||
|
||||
@get:Inject
|
||||
abstract val workerExecutor: WorkerExecutor
|
||||
protected abstract val workerExecutor: WorkerExecutor
|
||||
|
||||
private val platformManager = project.extensions.getByType<PlatformManager>()
|
||||
|
||||
@TaskAction
|
||||
fun compile() {
|
||||
val workQueue = workerExecutor.noIsolation()
|
||||
|
||||
val parameters = { it: CompileToBitcodeParameters ->
|
||||
it.objDir = objDir
|
||||
it.target = target
|
||||
it.compilerExecutable = executable
|
||||
it.compilerArgs = compilerFlags + inputFiles.map { it.absolutePath }
|
||||
it.llvmLinkArgs = listOf("-o", outFile.absolutePath) + linkerArgs +
|
||||
inputFiles.map {
|
||||
bitcodeFileForInputFile(it).absolutePath
|
||||
}
|
||||
it.platformManager.set(project.platformManager)
|
||||
workQueue.submit(CompileToBitcodeJob::class.java) {
|
||||
workingDirectory.set(this@CompileToBitcode.outputDirectory)
|
||||
targetName.set(this@CompileToBitcode.target.name)
|
||||
compilerExecutable.set(this@CompileToBitcode.compiler)
|
||||
compilerArgs.set(this@CompileToBitcode.compilerFlags)
|
||||
compilerInputFiles.from(this@CompileToBitcode.inputFiles)
|
||||
llvmLinkOutputFile.set(this@CompileToBitcode.outputFile)
|
||||
llvmLinkArgs.set(this@CompileToBitcode.linkerArgs)
|
||||
platformManager.set(this@CompileToBitcode.platformManager)
|
||||
}
|
||||
|
||||
workQueue.submit(CompileToBitcodeJob::class.java, parameters)
|
||||
}
|
||||
}
|
||||
|
||||
+51
-27
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.bitcode
|
||||
|
||||
import kotlinBuildProperties
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Plugin
|
||||
import org.gradle.api.Project
|
||||
@@ -47,6 +48,17 @@ open class CompileToBitcodePlugin : Plugin<Project> {
|
||||
}
|
||||
|
||||
open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
||||
// TODO: These should be set by the plugin users.
|
||||
private val DEFAULT_CPP_FLAGS = listOfNotNull(
|
||||
"-gdwarf-2".takeIf { project.kotlinBuildProperties.getBoolean("kotlin.native.isNativeRuntimeDebugInfoEnabled", false) },
|
||||
"-std=c++17",
|
||||
"-Werror",
|
||||
"-O2",
|
||||
"-fno-aligned-allocation", // TODO: Remove when all targets support aligned allocation in C++ runtime.
|
||||
"-Wall",
|
||||
"-Wextra",
|
||||
"-Wno-unused-parameter", // False positives with polymorphic functions.
|
||||
)
|
||||
|
||||
private val compilationDatabase = project.extensions.getByType<CompilationDatabaseExtension>()
|
||||
private val execClang = project.extensions.getByType<ExecClang>()
|
||||
@@ -97,11 +109,11 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
||||
}
|
||||
compilationDatabase.target(konanTarget) {
|
||||
entry {
|
||||
val args = listOf(execClang.resolveExecutable(compileTask.executable)) + compileTask.compilerFlags + execClang.clangArgsForCppRuntime(konanTarget.name)
|
||||
directory.set(compileTask.objDir)
|
||||
val args = listOf(execClang.resolveExecutable(compileTask.compiler.get())) + compileTask.compilerFlags.get() + execClang.clangArgsForCppRuntime(konanTarget.name)
|
||||
directory.set(compileTask.outputDirectory)
|
||||
files.setFrom(compileTask.inputFiles)
|
||||
arguments.set(args)
|
||||
output.set(compileTask.outFile.absolutePath)
|
||||
output.set(compileTask.outputFile.asFile.map { it.absolutePath })
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -113,16 +125,21 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
||||
val allMainModulesTask = allMainModulesTasks[targetName]!!
|
||||
sanitizers.forEach { sanitizer ->
|
||||
val taskName = fullTaskName(name, targetName, sanitizer)
|
||||
val task = project.tasks.create(taskName, CompileToBitcode::class.java, name, targetName, outputGroup).apply {
|
||||
srcDirs = project.files(srcRoot.resolve("cpp"))
|
||||
headersDirs = srcDirs + project.files(srcRoot.resolve("headers"))
|
||||
|
||||
this.sanitizer = sanitizer
|
||||
val task = project.tasks.create(taskName, CompileToBitcode::class.java, target, sanitizer.asMaybe).apply {
|
||||
this.moduleName.set(name)
|
||||
this.outputFile.convention(moduleName.flatMap { project.layout.buildDirectory.file("bitcode/$outputGroup/$target${sanitizer.dirSuffix}/$it.bc") })
|
||||
this.outputDirectory.convention(moduleName.flatMap { project.layout.buildDirectory.dir("bitcode/$outputGroup/$target${sanitizer.dirSuffix}/$it") })
|
||||
this.compiler.convention("clang++")
|
||||
this.compilerArgs.set(DEFAULT_CPP_FLAGS)
|
||||
this.inputFiles.from(srcRoot.resolve("cpp"))
|
||||
this.inputFiles.include("**/*.cpp", "**/*.mm")
|
||||
this.inputFiles.exclude("**/*Test.cpp", "**/*TestSupport.cpp", "**/*Test.mm", "**/*TestSupport.mm")
|
||||
this.headersDirs.from(this.inputFiles.dir)
|
||||
when (outputGroup) {
|
||||
"test" -> group = VERIFICATION_BUILD_TASK_GROUP
|
||||
"main" -> group = BUILD_TASK_GROUP
|
||||
"test" -> this.group = VERIFICATION_BUILD_TASK_GROUP
|
||||
"main" -> this.group = BUILD_TASK_GROUP
|
||||
}
|
||||
description = "Compiles '$name' to bitcode for $targetName${sanitizer.description}"
|
||||
this.description = "Compiles '$name' to bitcode for $targetName${sanitizer.description}"
|
||||
dependsOn(":kotlin-native:dependencies:update")
|
||||
configurationBlock()
|
||||
}
|
||||
@@ -161,19 +178,21 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
||||
val compileToBitcodeTasks = testedTasks.mapNotNull {
|
||||
val name = "${it.name}TestBitcode"
|
||||
val task = project.tasks.findByName(name) as? CompileToBitcode
|
||||
?: project.tasks.create(name, CompileToBitcode::class.java, "${it.folderName}Tests", target.name, "test").apply {
|
||||
srcDirs = it.srcDirs
|
||||
headersDirs = it.headersDirs + googleTestExtension.headersDirs
|
||||
?: project.tasks.create(name, CompileToBitcode::class.java, it.target, it.sanitizer.asMaybe).apply {
|
||||
this.moduleName.set(it.moduleName)
|
||||
this.outputFile.convention(moduleName.flatMap { project.layout.buildDirectory.file("bitcode/test/$target${sanitizer.dirSuffix}/${it}Tests.bc") })
|
||||
this.outputDirectory.convention(moduleName.flatMap { project.layout.buildDirectory.dir("bitcode/test/$target${sanitizer.dirSuffix}/${it}Tests") })
|
||||
this.compiler.convention("clang++")
|
||||
this.compilerArgs.set(it.compilerArgs)
|
||||
this.inputFiles.from(it.inputFiles.dir)
|
||||
this.inputFiles.include("**/*Test.cpp", "**/*TestSupport.cpp", "**/*Test.mm", "**/*TestSupport.mm")
|
||||
this.headersDirs.setFrom(it.headersDirs)
|
||||
this.headersDirs.from(googleTestExtension.headersDirs)
|
||||
this.group = VERIFICATION_BUILD_TASK_GROUP
|
||||
this.description = "Compiles '${it.name}' tests to bitcode for $target${sanitizer.description}"
|
||||
|
||||
group = VERIFICATION_BUILD_TASK_GROUP
|
||||
description = "Compiles '${it.name}' tests to bitcode for $target${sanitizer.description}"
|
||||
|
||||
this.sanitizer = sanitizer
|
||||
excludeFiles = emptyList()
|
||||
includeFiles = listOf("**/*Test.cpp", "**/*TestSupport.cpp", "**/*Test.mm", "**/*TestSupport.mm")
|
||||
dependsOn(":kotlin-native:dependencies:update")
|
||||
dependsOn("downloadGoogleTest")
|
||||
compilerArgs.addAll(it.compilerArgs)
|
||||
|
||||
addToCompdb(this, target)
|
||||
}
|
||||
@@ -200,11 +219,9 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
||||
this.llvmLinkOutputFile.set(project.layout.buildDirectory.file("bitcode/test/$target/$testName.bc"))
|
||||
this.compilerOutputFile.set(project.layout.buildDirectory.file("obj/$target/$testName.o"))
|
||||
this.mimallocEnabled.set(testsGroup.testedModules.get().any { it.contains("mimalloc") })
|
||||
this.mainFile.set(testSupportTask.outFile)
|
||||
dependsOn(testSupportTask)
|
||||
this.mainFile.set(testSupportTask.outputFile)
|
||||
val tasksToLink = (compileToBitcodeTasks + testedTasks + testFrameworkTasks)
|
||||
this.inputFiles.setFrom(tasksToLink.map { it.outFile })
|
||||
dependsOn(tasksToLink)
|
||||
this.inputFiles.setFrom(tasksToLink.map { it.outputFile })
|
||||
|
||||
usesService(compileTestsSemaphore)
|
||||
}
|
||||
@@ -257,15 +274,22 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
||||
|
||||
private fun String.snakeCaseToUpperCamelCase() = split('_').joinToString(separator = "") { it.capitalized }
|
||||
|
||||
private fun fullTaskName(name: String, targetName: String, sanitizer: SanitizerKind?) = "${targetName}${name.snakeCaseToUpperCamelCase()}${sanitizer.suffix}"
|
||||
private fun fullTaskName(name: String, targetName: String, sanitizer: SanitizerKind?) = "${targetName}${name.snakeCaseToUpperCamelCase()}${sanitizer.taskSuffix}"
|
||||
|
||||
private val SanitizerKind?.suffix
|
||||
private val SanitizerKind?.taskSuffix
|
||||
get() = when (this) {
|
||||
null -> ""
|
||||
SanitizerKind.ADDRESS -> "_ASAN"
|
||||
SanitizerKind.THREAD -> "_TSAN"
|
||||
}
|
||||
|
||||
private val SanitizerKind?.dirSuffix
|
||||
get() = when (this) {
|
||||
null -> ""
|
||||
SanitizerKind.ADDRESS -> "-asan"
|
||||
SanitizerKind.THREAD -> "-tsan"
|
||||
}
|
||||
|
||||
private val SanitizerKind?.description
|
||||
get() = when (this) {
|
||||
null -> ""
|
||||
|
||||
+11
-15
@@ -55,31 +55,27 @@ open class RuntimeTestingPlugin : Plugin<Project> {
|
||||
project.extensions.getByName(CompileToBitcodePlugin.EXTENSION_NAME) as CompileToBitcodeExtension
|
||||
|
||||
bitcodeExtension.module("googletest", outputGroup = "test") {
|
||||
srcDirs = project.files(
|
||||
googleTestRoot.resolve("googletest/src")
|
||||
)
|
||||
headersDirs = project.files(
|
||||
inputFiles.from(googleTestRoot.resolve("googletest/src"))
|
||||
inputFiles.include("*.cc")
|
||||
inputFiles.exclude("gtest-all.cc", "gtest_main.cc")
|
||||
headersDirs.from(
|
||||
googleTestRoot.resolve("googletest/include"),
|
||||
googleTestRoot.resolve("googletest")
|
||||
)
|
||||
includeFiles = listOf("*.cc")
|
||||
excludeFiles = listOf("gtest-all.cc", "gtest_main.cc")
|
||||
// Original GTest sources contain an unused variable on Windows (kAlternatePathSeparatorString).
|
||||
compilerArgs.add("-Wno-unused")
|
||||
compilerArgs.set(listOf("-std=c++17", "-O2"))
|
||||
dependsOn(dependencies)
|
||||
}
|
||||
|
||||
bitcodeExtension.module("googlemock", outputGroup = "test") {
|
||||
srcDirs = project.files(
|
||||
googleTestRoot.resolve("googlemock/src")
|
||||
)
|
||||
headersDirs = project.files(
|
||||
inputFiles.from(googleTestRoot.resolve("googlemock/src"))
|
||||
inputFiles.include("*.cc")
|
||||
inputFiles.exclude("gmock-all.cc", "gmock_main.cc")
|
||||
headersDirs.from(
|
||||
googleTestRoot.resolve("googlemock"),
|
||||
googleTestRoot.resolve("googlemock/include"),
|
||||
googleTestRoot.resolve("googletest/include")
|
||||
googleTestRoot.resolve("googletest/include"),
|
||||
)
|
||||
includeFiles = listOf("*.cc")
|
||||
excludeFiles = listOf("gmock-all.cc", "gmock_main.cc")
|
||||
compilerArgs.set(listOf("-std=c++17", "-O2"))
|
||||
dependsOn(dependencies)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,8 +8,12 @@ plugins {
|
||||
}
|
||||
|
||||
bitcode {
|
||||
module("files")
|
||||
module("env")
|
||||
module("files") {
|
||||
headersDirs.from(layout.projectDirectory.dir("src/files/headers"))
|
||||
}
|
||||
module("env") {
|
||||
headersDirs.from(layout.projectDirectory.dir("src/env/headers"))
|
||||
}
|
||||
}
|
||||
|
||||
val hostName: String by project
|
||||
|
||||
@@ -33,42 +33,67 @@ googletest {
|
||||
refresh = project.hasProperty("refresh-gtest")
|
||||
}
|
||||
|
||||
fun CompileToBitcode.includeRuntime() {
|
||||
headersDirs += files("src/main/cpp")
|
||||
}
|
||||
|
||||
val hostName: String by project
|
||||
val targetList: List<String> by project
|
||||
|
||||
bitcode {
|
||||
module("main") {
|
||||
includeRuntime()
|
||||
|
||||
outputName = "runtime.bc"
|
||||
// TODO: Split out out `base` module and merge it together with `main` into `runtime.bc`
|
||||
if (sanitizer == null) {
|
||||
outputFile.set(layout.buildDirectory.file("bitcode/main/$target/runtime.bc"))
|
||||
}
|
||||
}
|
||||
|
||||
module("mimalloc") {
|
||||
val srcRoot = file("src/mimalloc")
|
||||
language = CompileToBitcode.Language.C
|
||||
includeFiles = listOf("**/*.c")
|
||||
excludeFiles += listOf("**/alloc-override*.c", "**/page-queue.c", "**/static.c", "**/bitmap.inc.c")
|
||||
srcDirs = files("$srcRoot/c")
|
||||
compilerArgs.addAll(listOf("-DKONAN_MI_MALLOC=1", "-Wno-unknown-pragmas", "-ftls-model=initial-exec",
|
||||
"-Wno-unused-function", "-Wno-error=atomic-alignment",
|
||||
"-Wno-unused-parameter" /* for windows 32*/))
|
||||
extraSanitizerArgs[SanitizerKind.THREAD] = listOf("-DMI_TSAN=1")
|
||||
headersDirs = files("$srcRoot/c/include")
|
||||
compiler.set("clang")
|
||||
compilerArgs.set(listOfNotNull(
|
||||
"-std=gnu11",
|
||||
if (sanitizer == SanitizerKind.THREAD) { "-O1" } else { "-O3" },
|
||||
"-DKONAN_MI_MALLOC=1",
|
||||
"-Wno-unknown-pragmas",
|
||||
"-ftls-model=initial-exec",
|
||||
"-Wno-unused-function",
|
||||
"-Wno-error=atomic-alignment",
|
||||
"-Wno-unused-parameter", /* for windows 32 */
|
||||
"-DMI_TSAN=1".takeIf { sanitizer == SanitizerKind.THREAD },
|
||||
))
|
||||
inputFiles.from("$srcRoot/c")
|
||||
inputFiles.include("**/*.c")
|
||||
inputFiles.exclude("**/alloc-override*.c", "**/page-queue.c", "**/static.c", "**/bitmap.inc.c")
|
||||
headersDirs.setFrom("$srcRoot/c/include")
|
||||
|
||||
onlyIf { targetSupportsMimallocAllocator(target) }
|
||||
onlyIf { targetSupportsMimallocAllocator(target.name) }
|
||||
}
|
||||
|
||||
module("libbacktrace") {
|
||||
val srcRoot = file("src/libbacktrace")
|
||||
val targetInfo = HostManager().targetByName(target)
|
||||
language = CompileToBitcode.Language.C
|
||||
val useMachO = targetInfo.family.isAppleFamily
|
||||
val useElf = targetInfo.family in listOf(Family.LINUX, Family.ANDROID)
|
||||
includeFiles = listOfNotNull(
|
||||
val elfSize = when (target.architecture) {
|
||||
TargetArchitecture.X64, TargetArchitecture.ARM64 -> 64
|
||||
TargetArchitecture.X86, TargetArchitecture.ARM32,
|
||||
TargetArchitecture.MIPS32, TargetArchitecture.MIPSEL32,
|
||||
TargetArchitecture.WASM32 -> 32
|
||||
}
|
||||
val useMachO = target.family.isAppleFamily
|
||||
val useElf = target.family in listOf(Family.LINUX, Family.ANDROID)
|
||||
compiler.set("clang")
|
||||
compilerArgs.set(listOfNotNull(
|
||||
"-std=gnu11",
|
||||
"-funwind-tables",
|
||||
"-W",
|
||||
"-Wall",
|
||||
"-Wwrite-strings",
|
||||
"-Wstrict-prototypes",
|
||||
"-Wmissing-prototypes",
|
||||
"-Wold-style-definition",
|
||||
"-Wmissing-format-attribute",
|
||||
"-Wcast-qual",
|
||||
"-O2",
|
||||
"-DBACKTRACE_ELF_SIZE=$elfSize".takeIf { useElf },
|
||||
"-Wno-atomic-alignment"
|
||||
))
|
||||
inputFiles.from("$srcRoot/c")
|
||||
inputFiles.include(listOfNotNull(
|
||||
"atomic.c",
|
||||
"backtrace.c",
|
||||
"dwarf.c",
|
||||
@@ -82,105 +107,84 @@ bitcode {
|
||||
"simple.c",
|
||||
"sort.c",
|
||||
"state.c"
|
||||
)
|
||||
srcDirs = files("$srcRoot/c")
|
||||
val elfSize = when (targetInfo.architecture) {
|
||||
TargetArchitecture.X64, TargetArchitecture.ARM64 -> 64
|
||||
TargetArchitecture.X86, TargetArchitecture.ARM32,
|
||||
TargetArchitecture.MIPS32, TargetArchitecture.MIPSEL32,
|
||||
TargetArchitecture.WASM32 -> 32
|
||||
}
|
||||
compilerArgs.addAll(listOfNotNull(
|
||||
"-funwind-tables",
|
||||
"-W", "-Wall", "-Wwrite-strings", "-Wstrict-prototypes", "-Wmissing-prototypes",
|
||||
"-Wold-style-definition", "-Wmissing-format-attribute", "-Wcast-qual", "-O2",
|
||||
"-DBACKTRACE_ELF_SIZE=$elfSize".takeIf { useElf }, "-Wno-atomic-alignment"
|
||||
))
|
||||
headersDirs = files("$srcRoot/c/include")
|
||||
headersDirs.setFrom("$srcRoot/c/include")
|
||||
|
||||
onlyIf { targetSupportsLibBacktrace(target) }
|
||||
onlyIf { targetSupportsLibBacktrace(target.name) }
|
||||
}
|
||||
|
||||
|
||||
module("launcher") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("debug") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("std_alloc") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("opt_alloc") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("exceptionsSupport", file("src/exceptions_support")) {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("source_info_core_symbolication", file("src/source_info/core_symbolication")) {
|
||||
includeRuntime()
|
||||
onlyIf { targetSupportsCoreSymbolication(target) }
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
onlyIf { targetSupportsCoreSymbolication(target.name) }
|
||||
}
|
||||
module("source_info_libbacktrace", file("src/source_info/libbacktrace")) {
|
||||
includeRuntime()
|
||||
headersDirs += files("src/libbacktrace/c/include")
|
||||
onlyIf { targetSupportsLibBacktrace(target) }
|
||||
headersDirs.from(files("src/main/cpp", "src/libbacktrace/c/include"))
|
||||
onlyIf { targetSupportsLibBacktrace(target.name) }
|
||||
}
|
||||
|
||||
module("strict") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("relaxed") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("profileRuntime", file("src/profile_runtime"))
|
||||
|
||||
module("objc") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("test_support", outputGroup = "test") {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"), googletest.headersDirs)
|
||||
dependsOn("downloadGoogleTest")
|
||||
headersDirs += googletest.headersDirs
|
||||
}
|
||||
|
||||
module("legacy_memory_manager", file("src/legacymm")) {
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/main/cpp"))
|
||||
}
|
||||
|
||||
module("experimental_memory_manager", file("src/mm")) {
|
||||
headersDirs += files("src/gc/common/cpp")
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/gc/common/cpp", "src/main/cpp"))
|
||||
}
|
||||
|
||||
module("common_gc", file("src/gc/common")) {
|
||||
headersDirs += files("src/mm/cpp")
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/mm/cpp", "src/main/cpp"))
|
||||
}
|
||||
|
||||
module("noop_gc", file("src/gc/noop")) {
|
||||
headersDirs += files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp")
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
||||
}
|
||||
|
||||
module("same_thread_ms_gc", file("src/gc/stms")) {
|
||||
headersDirs += files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp")
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
||||
}
|
||||
|
||||
module("concurrent_ms_gc", file("src/gc/cms")) {
|
||||
headersDirs += files("src/gc/cms/cpp", "src/gc/common/cpp", "src/mm/cpp")
|
||||
includeRuntime()
|
||||
headersDirs.from(files("src/gc/cms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
||||
|
||||
onlyIf { targetSupportsThreads(target) }
|
||||
onlyIf { targetSupportsThreads(target.name) }
|
||||
}
|
||||
|
||||
testsGroup("std_alloc_runtime_tests") {
|
||||
|
||||
Reference in New Issue
Block a user