[K/N] Use TargetDomainObjectContainer ^KT-53776
Merge-request: KT-MR-7110 Merged-by: Alexander Shabalin <Alexander.Shabalin@jetbrains.com>
This commit is contained in:
committed by
Space
parent
ad9de1f8c4
commit
529a29ae52
+184
-197
@@ -23,13 +23,42 @@ import org.jetbrains.kotlin.cpp.RunGTest
|
|||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import org.jetbrains.kotlin.konan.target.PlatformManager
|
import org.jetbrains.kotlin.konan.target.PlatformManager
|
||||||
import org.jetbrains.kotlin.konan.target.SanitizerKind
|
import org.jetbrains.kotlin.konan.target.SanitizerKind
|
||||||
import org.jetbrains.kotlin.konan.target.supportedSanitizers
|
import org.jetbrains.kotlin.konan.target.TargetDomainObjectContainer
|
||||||
import org.jetbrains.kotlin.testing.native.GoogleTestExtension
|
import org.jetbrains.kotlin.testing.native.GoogleTestExtension
|
||||||
import org.jetbrains.kotlin.utils.Maybe
|
import org.jetbrains.kotlin.utils.Maybe
|
||||||
import org.jetbrains.kotlin.utils.asMaybe
|
import org.jetbrains.kotlin.utils.asMaybe
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@OptIn(ExperimentalStdlibApi::class)
|
||||||
|
private val String.capitalized: String
|
||||||
|
get() = replaceFirstChar { it.uppercase() }
|
||||||
|
|
||||||
|
private fun String.snakeCaseToUpperCamelCase() = split('_').joinToString(separator = "") { it.capitalized }
|
||||||
|
|
||||||
|
private fun fullTaskName(name: String, targetName: String, sanitizer: SanitizerKind?) = "${targetName}${name.snakeCaseToUpperCamelCase()}${sanitizer.taskSuffix}"
|
||||||
|
|
||||||
|
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 -> ""
|
||||||
|
SanitizerKind.ADDRESS -> " with ASAN"
|
||||||
|
SanitizerKind.THREAD -> " with TSAN"
|
||||||
|
}
|
||||||
|
|
||||||
private abstract class RunGTestSemaphore : BuildService<BuildServiceParameters.None>
|
private abstract class RunGTestSemaphore : BuildService<BuildServiceParameters.None>
|
||||||
private abstract class CompileTestsSemaphore : BuildService<BuildServiceParameters.None>
|
private abstract class CompileTestsSemaphore : BuildService<BuildServiceParameters.None>
|
||||||
|
|
||||||
@@ -47,7 +76,13 @@ open class CompileToBitcodePlugin : Plugin<Project> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
open class CompileToBitcodeExtension @Inject constructor(val project: Project) : TargetDomainObjectContainer<CompileToBitcodeExtension.Target>(project) {
|
||||||
|
init {
|
||||||
|
this.factory = { target, sanitizer ->
|
||||||
|
project.objects.newInstance<Target>(this, target, sanitizer.asMaybe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// TODO: These should be set by the plugin users.
|
// TODO: These should be set by the plugin users.
|
||||||
private val DEFAULT_CPP_FLAGS = listOfNotNull(
|
private val DEFAULT_CPP_FLAGS = listOfNotNull(
|
||||||
"-gdwarf-2".takeIf { project.kotlinBuildProperties.getBoolean("kotlin.native.isNativeRuntimeDebugInfoEnabled", false) },
|
"-gdwarf-2".takeIf { project.kotlinBuildProperties.getBoolean("kotlin.native.isNativeRuntimeDebugInfoEnabled", false) },
|
||||||
@@ -60,24 +95,6 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
|||||||
"-Wno-unused-parameter", // False positives with polymorphic functions.
|
"-Wno-unused-parameter", // False positives with polymorphic functions.
|
||||||
)
|
)
|
||||||
|
|
||||||
private val compilationDatabase = project.extensions.getByType<CompilationDatabaseExtension>()
|
|
||||||
private val execClang = project.extensions.getByType<ExecClang>()
|
|
||||||
private val platformManager = project.extensions.getByType<PlatformManager>()
|
|
||||||
|
|
||||||
// googleTestExtension is only used if testsGroup is used.
|
|
||||||
private val googleTestExtension by lazy { project.extensions.getByType<GoogleTestExtension>() }
|
|
||||||
|
|
||||||
// A shared service used to limit parallel execution of test binaries.
|
|
||||||
private val runGTestSemaphore = project.gradle.sharedServices.registerIfAbsent("runGTestSemaphore", RunGTestSemaphore::class.java) {
|
|
||||||
// Probably can be made configurable if test reporting moves away from simple gtest stdout dumping.
|
|
||||||
maxParallelUsages.set(1)
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO: remove when tests compilation does not consume so much memory.
|
|
||||||
private val compileTestsSemaphore = project.gradle.sharedServices.registerIfAbsent("compileTestsSemaphore", CompileTestsSemaphore::class.java) {
|
|
||||||
maxParallelUsages.set(5)
|
|
||||||
}
|
|
||||||
|
|
||||||
private val targetList = with(project) {
|
private val targetList = with(project) {
|
||||||
provider { (rootProject.project(":kotlin-native").property("targetList") as? List<*>)?.filterIsInstance<String>() ?: emptyList() } // TODO: Can we make it better?
|
provider { (rootProject.project(":kotlin-native").property("targetList") as? List<*>)?.filterIsInstance<String>() ?: emptyList() } // TODO: Can we make it better?
|
||||||
}
|
}
|
||||||
@@ -102,59 +119,6 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addToCompdb(compileTask: CompileToBitcode, konanTarget: KonanTarget) {
|
|
||||||
// No need to generate compdb entry for sanitizers.
|
|
||||||
if (compileTask.sanitizer != null) {
|
|
||||||
return
|
|
||||||
}
|
|
||||||
compilationDatabase.target(konanTarget) {
|
|
||||||
entry {
|
|
||||||
val args = listOf(execClang.resolveExecutable(compileTask.compiler.get())) + compileTask.compilerFlags.get() + execClang.clangArgsForCppRuntime(konanTarget.name)
|
|
||||||
directory.set(compileTask.compilerWorkingDirectory)
|
|
||||||
files.setFrom(compileTask.inputFiles)
|
|
||||||
arguments.set(args)
|
|
||||||
// Only the location of output file matters, compdb does not depend on the compilation result.
|
|
||||||
output.set(compileTask.outputFile.locationOnly.map { it.asFile.absolutePath })
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun module(name: String, srcRoot: File = project.file("src/$name"), outputGroup: String = "main", configurationBlock: CompileToBitcode.() -> Unit = {}) {
|
|
||||||
targetList.get().forEach { targetName ->
|
|
||||||
val target = platformManager.targetByName(targetName)
|
|
||||||
val sanitizers: List<SanitizerKind?> = target.supportedSanitizers() + listOf(null)
|
|
||||||
val allMainModulesTask = allMainModulesTasks[targetName]!!
|
|
||||||
sanitizers.forEach { sanitizer ->
|
|
||||||
val taskName = fullTaskName(name, targetName, 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)
|
|
||||||
this.compilerWorkingDirectory.set(project.layout.projectDirectory.dir("src"))
|
|
||||||
when (outputGroup) {
|
|
||||||
"test" -> this.group = VERIFICATION_BUILD_TASK_GROUP
|
|
||||||
"main" -> this.group = BUILD_TASK_GROUP
|
|
||||||
}
|
|
||||||
this.description = "Compiles '$name' to bitcode for $targetName${sanitizer.description}"
|
|
||||||
dependsOn(":kotlin-native:dependencies:update")
|
|
||||||
configurationBlock()
|
|
||||||
}
|
|
||||||
addToCompdb(task, target)
|
|
||||||
if (outputGroup == "main" && sanitizer == null) {
|
|
||||||
allMainModulesTask.configure {
|
|
||||||
dependsOn(taskName)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
abstract class TestsGroup @Inject constructor(
|
abstract class TestsGroup @Inject constructor(
|
||||||
val target: KonanTarget,
|
val target: KonanTarget,
|
||||||
private val _sanitizer: Maybe<SanitizerKind>,
|
private val _sanitizer: Maybe<SanitizerKind>,
|
||||||
@@ -166,145 +130,168 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) {
|
|||||||
abstract val testLauncherModule: Property<String>
|
abstract val testLauncherModule: Property<String>
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun createTestTask(
|
abstract class Target @Inject constructor(
|
||||||
testTaskName: String,
|
private val owner: CompileToBitcodeExtension,
|
||||||
testsGroup: TestsGroup,
|
val target: KonanTarget,
|
||||||
|
_sanitizer: Maybe<SanitizerKind>,
|
||||||
) {
|
) {
|
||||||
val target = testsGroup.target
|
val sanitizer = _sanitizer.orNull
|
||||||
val sanitizer = testsGroup.sanitizer
|
|
||||||
val testName = fullTaskName(testTaskName, target.name, sanitizer)
|
|
||||||
val testedTasks = testsGroup.testedModules.get().map {
|
|
||||||
val name = fullTaskName(it, target.name, sanitizer)
|
|
||||||
project.tasks.getByName(name) as CompileToBitcode
|
|
||||||
}
|
|
||||||
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.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.compilerWorkingDirectory.set(it.compilerWorkingDirectory)
|
|
||||||
this.group = VERIFICATION_BUILD_TASK_GROUP
|
|
||||||
this.description = "Compiles '${it.name}' tests to bitcode for $target${sanitizer.description}"
|
|
||||||
|
|
||||||
dependsOn(":kotlin-native:dependencies:update")
|
private val project by owner::project
|
||||||
dependsOn("downloadGoogleTest")
|
|
||||||
|
|
||||||
addToCompdb(this, target)
|
private val compilationDatabase = project.extensions.getByType<CompilationDatabaseExtension>()
|
||||||
}
|
private val execClang = project.extensions.getByType<ExecClang>()
|
||||||
if (task.inputFiles.count() == 0) null
|
private val platformManager = project.extensions.getByType<PlatformManager>()
|
||||||
else task
|
|
||||||
}
|
// googleTestExtension is only used if testsGroup is used.
|
||||||
val testFrameworkTasks = testsGroup.testSupportModules.get().map {
|
private val googleTestExtension by lazy { project.extensions.getByType<GoogleTestExtension>() }
|
||||||
val name = fullTaskName(it, target.name, sanitizer)
|
|
||||||
project.tasks.getByName(name) as CompileToBitcode
|
// A shared service used to limit parallel execution of test binaries.
|
||||||
|
private val runGTestSemaphore = project.gradle.sharedServices.registerIfAbsent("runGTestSemaphore", RunGTestSemaphore::class.java) {
|
||||||
|
// Probably can be made configurable if test reporting moves away from simple gtest stdout dumping.
|
||||||
|
maxParallelUsages.set(1)
|
||||||
}
|
}
|
||||||
|
|
||||||
val testSupportTask = testsGroup.testLauncherModule.get().let {
|
// TODO: remove when tests compilation does not consume so much memory.
|
||||||
val name = fullTaskName(it, target.name, sanitizer)
|
private val compileTestsSemaphore = project.gradle.sharedServices.registerIfAbsent("compileTestsSemaphore", CompileTestsSemaphore::class.java) {
|
||||||
project.tasks.getByName(name) as CompileToBitcode
|
maxParallelUsages.set(5)
|
||||||
}
|
}
|
||||||
|
|
||||||
val compileTask = project.tasks.register<CompileToExecutable>("${testName}Compile") {
|
private fun addToCompdb(compileTask: CompileToBitcode) {
|
||||||
description = "Compile tests group '$testTaskName' for $target${sanitizer.description}"
|
compilationDatabase.target(target, sanitizer) {
|
||||||
group = VERIFICATION_BUILD_TASK_GROUP
|
entry {
|
||||||
this.target.set(target)
|
val args = listOf(execClang.resolveExecutable(compileTask.compiler.get())) + compileTask.compilerFlags.get() + execClang.clangArgsForCppRuntime(target.name)
|
||||||
this.sanitizer.set(sanitizer)
|
directory.set(compileTask.compilerWorkingDirectory)
|
||||||
this.outputFile.set(project.layout.buildDirectory.file("bin/test/${target}/$testName${target.executableExtension}"))
|
files.setFrom(compileTask.inputFiles)
|
||||||
this.llvmLinkFirstStageOutputFile.set(project.layout.buildDirectory.file("bitcode/test/$target/$testName-firstStage.bc"))
|
arguments.set(args)
|
||||||
this.llvmLinkOutputFile.set(project.layout.buildDirectory.file("bitcode/test/$target/$testName.bc"))
|
// Only the location of output file matters, compdb does not depend on the compilation result.
|
||||||
this.compilerOutputFile.set(project.layout.buildDirectory.file("obj/$target/$testName.o"))
|
output.set(compileTask.outputFile.locationOnly.map { it.asFile.absolutePath })
|
||||||
this.mimallocEnabled.set(testsGroup.testedModules.get().any { it.contains("mimalloc") })
|
|
||||||
this.mainFile.set(testSupportTask.outputFile)
|
|
||||||
val tasksToLink = (compileToBitcodeTasks + testedTasks + testFrameworkTasks)
|
|
||||||
this.inputFiles.setFrom(tasksToLink.map { it.outputFile })
|
|
||||||
|
|
||||||
usesService(compileTestsSemaphore)
|
|
||||||
}
|
|
||||||
|
|
||||||
val runTask = project.tasks.register<RunGTest>(testName) {
|
|
||||||
description = "Runs tests group '$testTaskName' for $target${sanitizer.description}"
|
|
||||||
group = VERIFICATION_TASK_GROUP
|
|
||||||
this.testName.set(testName)
|
|
||||||
executable.set(compileTask.flatMap { it.outputFile })
|
|
||||||
dependsOn(compileTask)
|
|
||||||
reportFileUnprocessed.set(project.layout.buildDirectory.file("testReports/$testName/report.xml"))
|
|
||||||
reportFile.set(project.layout.buildDirectory.file("testReports/$testName/report-with-prefixes.xml"))
|
|
||||||
filter.set(project.findProperty("gtest_filter") as? String)
|
|
||||||
tsanSuppressionsFile.set(project.layout.projectDirectory.file("tsan_suppressions.txt"))
|
|
||||||
|
|
||||||
usesService(runGTestSemaphore)
|
|
||||||
}
|
|
||||||
|
|
||||||
allTestsTasks[target.name]!!.configure {
|
|
||||||
dependsOn(runTask)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fun testsGroup(
|
|
||||||
testTaskName: String,
|
|
||||||
action: Action<in TestsGroup>,
|
|
||||||
) {
|
|
||||||
platformManager.enabled.forEach { target ->
|
|
||||||
val sanitizers: List<SanitizerKind?> = target.supportedSanitizers() + listOf(null)
|
|
||||||
sanitizers.forEach { sanitizer ->
|
|
||||||
val instance = project.objects.newInstance(TestsGroup::class.java, target, sanitizer.asMaybe).apply {
|
|
||||||
testSupportModules.convention(listOf("googletest", "googlemock"))
|
|
||||||
testLauncherModule.convention("test_support")
|
|
||||||
action.execute(this)
|
|
||||||
}
|
}
|
||||||
createTestTask(testTaskName, instance)
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun module(name: String, srcRoot: File = project.file("src/$name"), outputGroup: String = "main", configurationBlock: CompileToBitcode.() -> Unit = {}) {
|
||||||
|
val targetName = target.name
|
||||||
|
val allMainModulesTask = owner.allMainModulesTasks[targetName]!!
|
||||||
|
val taskName = fullTaskName(name, targetName, 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(owner.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)
|
||||||
|
this.compilerWorkingDirectory.set(project.layout.projectDirectory.dir("src"))
|
||||||
|
when (outputGroup) {
|
||||||
|
"test" -> this.group = VERIFICATION_BUILD_TASK_GROUP
|
||||||
|
"main" -> this.group = BUILD_TASK_GROUP
|
||||||
|
}
|
||||||
|
this.description = "Compiles '$name' to bitcode for $targetName${sanitizer.description}"
|
||||||
|
dependsOn(":kotlin-native:dependencies:update")
|
||||||
|
configurationBlock()
|
||||||
|
}
|
||||||
|
addToCompdb(task)
|
||||||
|
if (outputGroup == "main" && sanitizer == null) {
|
||||||
|
allMainModulesTask.configure {
|
||||||
|
dependsOn(taskName)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun testsGroup(
|
||||||
|
testTaskName: String,
|
||||||
|
action: Action<in TestsGroup>,
|
||||||
|
) {
|
||||||
|
val testsGroup = project.objects.newInstance(TestsGroup::class.java, target, sanitizer.asMaybe).apply {
|
||||||
|
testSupportModules.convention(listOf("googletest", "googlemock"))
|
||||||
|
testLauncherModule.convention("test_support")
|
||||||
|
action.execute(this)
|
||||||
|
}
|
||||||
|
val target = testsGroup.target
|
||||||
|
val sanitizer = testsGroup.sanitizer
|
||||||
|
val testName = fullTaskName(testTaskName, target.name, sanitizer)
|
||||||
|
val testedTasks = testsGroup.testedModules.get().map {
|
||||||
|
val name = fullTaskName(it, target.name, sanitizer)
|
||||||
|
project.tasks.getByName(name) as CompileToBitcode
|
||||||
|
}
|
||||||
|
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.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.compilerWorkingDirectory.set(it.compilerWorkingDirectory)
|
||||||
|
this.group = VERIFICATION_BUILD_TASK_GROUP
|
||||||
|
this.description = "Compiles '${it.name}' tests to bitcode for $target${sanitizer.description}"
|
||||||
|
|
||||||
|
dependsOn(":kotlin-native:dependencies:update")
|
||||||
|
dependsOn("downloadGoogleTest")
|
||||||
|
|
||||||
|
addToCompdb(this)
|
||||||
|
}
|
||||||
|
if (task.inputFiles.count() == 0) null
|
||||||
|
else task
|
||||||
|
}
|
||||||
|
val testFrameworkTasks = testsGroup.testSupportModules.get().map {
|
||||||
|
val name = fullTaskName(it, target.name, sanitizer)
|
||||||
|
project.tasks.getByName(name) as CompileToBitcode
|
||||||
|
}
|
||||||
|
|
||||||
|
val testSupportTask = testsGroup.testLauncherModule.get().let {
|
||||||
|
val name = fullTaskName(it, target.name, sanitizer)
|
||||||
|
project.tasks.getByName(name) as CompileToBitcode
|
||||||
|
}
|
||||||
|
|
||||||
|
val compileTask = project.tasks.register<CompileToExecutable>("${testName}Compile") {
|
||||||
|
description = "Compile tests group '$testTaskName' for $target${sanitizer.description}"
|
||||||
|
group = VERIFICATION_BUILD_TASK_GROUP
|
||||||
|
this.target.set(target)
|
||||||
|
this.sanitizer.set(sanitizer)
|
||||||
|
this.outputFile.set(project.layout.buildDirectory.file("bin/test/${target}/$testName.${target.family.exeSuffix}"))
|
||||||
|
this.llvmLinkFirstStageOutputFile.set(project.layout.buildDirectory.file("bitcode/test/$target/$testName-firstStage.bc"))
|
||||||
|
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.outputFile)
|
||||||
|
val tasksToLink = (compileToBitcodeTasks + testedTasks + testFrameworkTasks)
|
||||||
|
this.inputFiles.setFrom(tasksToLink.map { it.outputFile })
|
||||||
|
|
||||||
|
usesService(compileTestsSemaphore)
|
||||||
|
}
|
||||||
|
|
||||||
|
val runTask = project.tasks.register<RunGTest>(testName) {
|
||||||
|
description = "Runs tests group '$testTaskName' for $target${sanitizer.description}"
|
||||||
|
group = VERIFICATION_TASK_GROUP
|
||||||
|
this.testName.set(testName)
|
||||||
|
executable.set(compileTask.flatMap { it.outputFile })
|
||||||
|
dependsOn(compileTask)
|
||||||
|
reportFileUnprocessed.set(project.layout.buildDirectory.file("testReports/$testName/report.xml"))
|
||||||
|
reportFile.set(project.layout.buildDirectory.file("testReports/$testName/report-with-prefixes.xml"))
|
||||||
|
filter.set(project.findProperty("gtest_filter") as? String)
|
||||||
|
tsanSuppressionsFile.set(project.layout.projectDirectory.file("tsan_suppressions.txt"))
|
||||||
|
|
||||||
|
usesService(runGTestSemaphore)
|
||||||
|
}
|
||||||
|
|
||||||
|
owner.allTestsTasks[target.name]!!.configure {
|
||||||
|
dependsOn(runTask)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
|
||||||
const val BUILD_TASK_GROUP = LifecycleBasePlugin.BUILD_GROUP
|
const val BUILD_TASK_GROUP = LifecycleBasePlugin.BUILD_GROUP
|
||||||
const val VERIFICATION_TASK_GROUP = LifecycleBasePlugin.VERIFICATION_GROUP
|
const val VERIFICATION_TASK_GROUP = LifecycleBasePlugin.VERIFICATION_GROUP
|
||||||
const val VERIFICATION_BUILD_TASK_GROUP = "verification build"
|
const val VERIFICATION_BUILD_TASK_GROUP = "verification build"
|
||||||
|
|
||||||
@OptIn(ExperimentalStdlibApi::class)
|
|
||||||
private val String.capitalized: String
|
|
||||||
get() = replaceFirstChar { it.uppercase() }
|
|
||||||
|
|
||||||
private fun String.snakeCaseToUpperCamelCase() = split('_').joinToString(separator = "") { it.capitalized }
|
|
||||||
|
|
||||||
private fun fullTaskName(name: String, targetName: String, sanitizer: SanitizerKind?) = "${targetName}${name.snakeCaseToUpperCamelCase()}${sanitizer.taskSuffix}"
|
|
||||||
|
|
||||||
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 -> ""
|
|
||||||
SanitizerKind.ADDRESS -> " with ASAN"
|
|
||||||
SanitizerKind.THREAD -> " with TSAN"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val KonanTarget.executableExtension
|
|
||||||
get() = when (this) {
|
|
||||||
is KonanTarget.MINGW_X64 -> ".exe"
|
|
||||||
is KonanTarget.MINGW_X86 -> ".exe"
|
|
||||||
else -> ""
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+34
-67
@@ -11,13 +11,18 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.api.file.ConfigurableFileCollection
|
import org.gradle.api.file.ConfigurableFileCollection
|
||||||
import org.gradle.api.file.DirectoryProperty
|
import org.gradle.api.file.DirectoryProperty
|
||||||
import org.gradle.api.provider.ListProperty
|
import org.gradle.api.provider.ListProperty
|
||||||
import org.gradle.api.provider.MapProperty
|
|
||||||
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.kotlin.dsl.*
|
import org.gradle.kotlin.dsl.create
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.gradle.kotlin.dsl.getByType
|
||||||
|
import org.gradle.kotlin.dsl.newInstance
|
||||||
|
import org.gradle.kotlin.dsl.register
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
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.konan.target.TargetDomainObjectContainer
|
||||||
|
import org.jetbrains.kotlin.konan.target.targetSuffix
|
||||||
|
import org.jetbrains.kotlin.utils.Maybe
|
||||||
|
import org.jetbrains.kotlin.utils.asMaybe
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -40,10 +45,12 @@ import javax.inject.Inject
|
|||||||
*
|
*
|
||||||
* @see CompilationDatabasePlugin gradle plugin that creates this extension.
|
* @see CompilationDatabasePlugin gradle plugin that creates this extension.
|
||||||
*/
|
*/
|
||||||
abstract class CompilationDatabaseExtension @Inject constructor(private val project: Project) {
|
abstract class CompilationDatabaseExtension @Inject constructor(private val project: Project) : TargetDomainObjectContainer<CompilationDatabaseExtension.Target>(project) {
|
||||||
// TODO: This platformManager should acquired be from something service-ish.
|
init {
|
||||||
// But for usefulness this service should be accessible from WorkAction.
|
this.factory = { target, sanitizer ->
|
||||||
private val platformManager = project.extensions.getByType<PlatformManager>()
|
project.objects.newInstance<Target>(project, target, sanitizer.asMaybe)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Entries in the compilation database.
|
* Entries in the compilation database.
|
||||||
@@ -51,8 +58,14 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
|
|||||||
* Single [Entry] generates a number of compilation database entries: one for each file in [files].
|
* Single [Entry] generates a number of compilation database entries: one for each file in [files].
|
||||||
*
|
*
|
||||||
* @property target target for which this [Entry] is generated.
|
* @property target target for which this [Entry] is generated.
|
||||||
|
* @property sanitizer optional sanitizer for [target].
|
||||||
*/
|
*/
|
||||||
abstract class Entry @Inject constructor(val target: KonanTarget) {
|
abstract class Entry @Inject constructor(
|
||||||
|
val target: KonanTarget,
|
||||||
|
_sanitizer: Maybe<SanitizerKind>,
|
||||||
|
) {
|
||||||
|
val sanitizer = _sanitizer.orNull
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* **directory** from the [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html#format).
|
* **directory** from the [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html#format).
|
||||||
*
|
*
|
||||||
@@ -92,34 +105,38 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
|
|||||||
* [task] is the gradle task for compilation database generation.
|
* [task] is the gradle task for compilation database generation.
|
||||||
*
|
*
|
||||||
* @property target target for which compilation database is generated.
|
* @property target target for which compilation database is generated.
|
||||||
|
* @property sanitizer optional sanitizer for which compilation database is generated.
|
||||||
*/
|
*/
|
||||||
abstract class Target @Inject constructor(
|
abstract class Target @Inject constructor(
|
||||||
private val project: Project,
|
private val project: Project,
|
||||||
val target: KonanTarget,
|
val target: KonanTarget,
|
||||||
|
_sanitizer: Maybe<SanitizerKind>,
|
||||||
) {
|
) {
|
||||||
|
val sanitizer = _sanitizer.orNull
|
||||||
|
|
||||||
protected abstract val mergeFrom: ListProperty<GenerateCompilationDatabase>
|
protected abstract val mergeFrom: ListProperty<GenerateCompilationDatabase>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Merge compilation database generated for [from] project for [target].
|
* Merge compilation database generated for [from] project for [target] with optional [sanitizer].
|
||||||
*
|
*
|
||||||
* @param from project with applied [CompilationDatabasePlugin] to merge compilation database from.
|
* @param from project with applied [CompilationDatabasePlugin] to merge compilation database from.
|
||||||
*/
|
*/
|
||||||
fun mergeFrom(from: Provider<Project>) {
|
fun mergeFrom(from: Provider<Project>) {
|
||||||
mergeFrom.add(from.flatMap { project ->
|
mergeFrom.add(from.flatMap { project ->
|
||||||
project.extensions.getByType<CompilationDatabaseExtension>().target(target).task
|
project.extensions.getByType<CompilationDatabaseExtension>().target(target, sanitizer).task
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract val entries: ListProperty<GenerateCompilationDatabase.Entry>
|
protected abstract val entries: ListProperty<GenerateCompilationDatabase.Entry>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Add an entry to the compilation database for [target].
|
* Add an entry to the compilation database for [target] with optional [sanitizer].
|
||||||
*
|
*
|
||||||
* @param action configure [Entry]
|
* @param action configure [Entry]
|
||||||
*/
|
*/
|
||||||
fun entry(action: Action<in Entry>) {
|
fun entry(action: Action<in Entry>) {
|
||||||
entries.add(project.provider {
|
entries.add(project.provider {
|
||||||
val instance = project.objects.newInstance<Entry>(target).apply {
|
val instance = project.objects.newInstance<Entry>(target, sanitizer.asMaybe).apply {
|
||||||
action.execute(this)
|
action.execute(this)
|
||||||
}
|
}
|
||||||
project.objects.newInstance<GenerateCompilationDatabase.Entry>().apply {
|
project.objects.newInstance<GenerateCompilationDatabase.Entry>().apply {
|
||||||
@@ -132,67 +149,17 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gradle task that generates compilation database for [target].
|
* Gradle task that generates compilation database for [target] with optional [sanitizer].
|
||||||
*/
|
*/
|
||||||
val task = project.tasks.register<GenerateCompilationDatabase>("${target}CompilationDatabase") {
|
val task = project.tasks.register<GenerateCompilationDatabase>("${target}${sanitizer.targetSuffix}CompilationDatabase") {
|
||||||
description = "Generate compilation database for $target"
|
description = "Generate compilation database for $target${sanitizer.targetSuffix}"
|
||||||
group = TASK_GROUP
|
group = TASK_GROUP
|
||||||
mergeFiles.from(mergeFrom)
|
mergeFiles.from(mergeFrom)
|
||||||
entries.set(this@Target.entries)
|
entries.set(this@Target.entries)
|
||||||
outputFile.set(project.layout.buildDirectory.file("${target}/compile_commands.json"))
|
outputFile.set(project.layout.buildDirectory.file("${target}${sanitizer.targetSuffix}/compile_commands.json"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected abstract val targets: MapProperty<KonanTarget, Target>
|
|
||||||
|
|
||||||
private fun targetGetOrPut(target: KonanTarget) = targets.getting(target).orNull
|
|
||||||
?: project.objects.newInstance<Target>(project, target).apply {
|
|
||||||
targets.put(target, this)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get [compilation database configuration][Target] for [target] and apply [action] to it.
|
|
||||||
*
|
|
||||||
* @param target target to configure.
|
|
||||||
* @param action action to apply to configuration.
|
|
||||||
*/
|
|
||||||
fun target(target: KonanTarget, action: Action<in Target>) = targetGetOrPut(target).apply {
|
|
||||||
action.execute(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get [compilation database configuration][Target] for [target].
|
|
||||||
*
|
|
||||||
* @param target target to configure.
|
|
||||||
*/
|
|
||||||
fun target(target: KonanTarget) = this.target(target) {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get [compilation database configurations][Target] for all known targets and apply [action] to each.
|
|
||||||
*
|
|
||||||
* @param action action to apply to configurations.
|
|
||||||
*/
|
|
||||||
fun allTargets(action: Action<in Target>) = platformManager.enabled.map { target(it, action) }
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get [compilation database configurations][Target] for all known targets.
|
|
||||||
*/
|
|
||||||
val allTargets
|
|
||||||
get() = allTargets {}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get [compilation database configuration][Target] for [host target][HostManager.host] and apply [action] to it.
|
|
||||||
*
|
|
||||||
* @param action action to apply to configuration.
|
|
||||||
*/
|
|
||||||
fun hostTarget(action: Action<in Target>) = target(HostManager.host, action)
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Get [compilation database configuration][Target] for [host target][HostManager.host].
|
|
||||||
*/
|
|
||||||
val hostTarget
|
|
||||||
get() = hostTarget {}
|
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic
|
||||||
val TASK_GROUP = "development support"
|
val TASK_GROUP = "development support"
|
||||||
|
|||||||
+146
@@ -0,0 +1,146 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2022 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.konan.target
|
||||||
|
|
||||||
|
import org.gradle.api.Action
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.gradle.api.UnknownDomainObjectException
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
|
import org.gradle.api.provider.ProviderFactory
|
||||||
|
import org.gradle.kotlin.dsl.getByType
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Associative container from a [KonanTarget] with optional [SanitizerKind] to [T].
|
||||||
|
*
|
||||||
|
* Serves similar purpose to [NamedDomainObjectContainer][org.gradle.api.NamedDomainObjectContainer]
|
||||||
|
* except this is keyed on a target instead of a name. Also this implementation does not support lazy
|
||||||
|
* creation.
|
||||||
|
*
|
||||||
|
* Plugin extensions can inherit from this to automatically get API suitable for `build.gradle.kts`.
|
||||||
|
* The extension must set [factory] field for [T].
|
||||||
|
*
|
||||||
|
* Example usage:
|
||||||
|
* ```
|
||||||
|
* someExtension {
|
||||||
|
* allTargets {
|
||||||
|
* // This is a lambda inside of a T scope. Called once for each known target with their respective sanitizer.
|
||||||
|
* }
|
||||||
|
* target(someTarget) {
|
||||||
|
* // This is a lambda inside of a T scope. Called for `someTarget` without any sanitizer.
|
||||||
|
* }
|
||||||
|
* target(someTarget, someSanitizer) {
|
||||||
|
* // This is a lambda inside of a T scope. Called for `someTarget` with `someSanitizer`.
|
||||||
|
* }
|
||||||
|
* hostTarget {
|
||||||
|
* // This is a lambda inside of a T scope. Called for the host target without any sanitizer.
|
||||||
|
* }
|
||||||
|
* hostTarget(someSanitizer) {
|
||||||
|
* // This is a lambda inside of a T scope. Called for the host target with `someSanitizer`.
|
||||||
|
* }
|
||||||
|
* }
|
||||||
|
*
|
||||||
|
* someExtension.target(someTarget) // returns T if `someTarget` was configured. Otherwise fails with UnknownDomainObjectException.
|
||||||
|
* someExtension.allTargets // returns a Provider<List<T>> of all created configurations.
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
// TODO: Consider splitting out interface and the default implementation. Plugins will inherit from the interface via delegation to the implementation.
|
||||||
|
// TODO: Consider implementing everything from `NamedDomainObjectContainer` but keyed on a target instead of a name.
|
||||||
|
open class TargetDomainObjectContainer<T> constructor(
|
||||||
|
private val providerFactory: ProviderFactory,
|
||||||
|
private val platformManager: PlatformManager,
|
||||||
|
) {
|
||||||
|
constructor(project: Project) : this(project.providers, project.extensions.getByType<PlatformManager>())
|
||||||
|
|
||||||
|
/**
|
||||||
|
* How to create [T]. Must be set before using the rest of API.
|
||||||
|
*/
|
||||||
|
lateinit var factory: (KonanTarget, SanitizerKind?) -> T
|
||||||
|
|
||||||
|
private val targets: MutableMap<Pair<KonanTarget, SanitizerKind?>, T> = mutableMapOf()
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create or update configuration [T] for [target] with optional [sanitizer] and apply [action] to it.
|
||||||
|
*
|
||||||
|
* @param target target of the configuration
|
||||||
|
* @param sanitizer optional sanitizer for [target]
|
||||||
|
* @param action action to apply to the configuration
|
||||||
|
* @return resulting configuration
|
||||||
|
*/
|
||||||
|
fun target(target: KonanTarget, sanitizer: SanitizerKind? = null, action: Action<in T>): T {
|
||||||
|
val key = target to sanitizer
|
||||||
|
val element = targets.getOrPut(key) { factory(target, sanitizer) }
|
||||||
|
action.execute(element)
|
||||||
|
return element
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get configuration [T] for [target] with optional [sanitizer].
|
||||||
|
*
|
||||||
|
* @param target target of the configuration
|
||||||
|
* @param sanitizer optional sanitizer for [target]
|
||||||
|
* @return resulting configuration
|
||||||
|
* @throws UnknownDomainObjectException if configuration for [target] and [sanitizer] does not exist
|
||||||
|
*/
|
||||||
|
fun target(target: KonanTarget, sanitizer: SanitizerKind? = null): T {
|
||||||
|
val key = target to sanitizer
|
||||||
|
return targets.get(key) ?: throw UnknownDomainObjectException("Configuration for $target${sanitizer.targetSuffix} does not exists")
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create or update configurations [T] for all known targets with their sanitizers and apply [action] to each of it.
|
||||||
|
*
|
||||||
|
* @param action action to apply to the configuration
|
||||||
|
* @return list of configurations
|
||||||
|
*/
|
||||||
|
fun allTargets(action: Action<in T>): List<T> {
|
||||||
|
return platformManager.enabled.flatMap { target ->
|
||||||
|
val sanitizers = target.supportedSanitizers() + listOf(null)
|
||||||
|
sanitizers.map { sanitizer ->
|
||||||
|
this.target(target, sanitizer, action)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get all created configurations [T].
|
||||||
|
*
|
||||||
|
* @return [Provider] with list of all created configurations
|
||||||
|
*/
|
||||||
|
val allTargets: Provider<List<T>> = providerFactory.provider {
|
||||||
|
targets.values.toList()
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create or update configuration [T] for [host target][HostManager.host] with optional [sanitizer] and apply [action] to it.
|
||||||
|
*
|
||||||
|
* @param sanitizer optional sanitizer for [host target][HostManager.host]
|
||||||
|
* @param action action to apply to the configuration
|
||||||
|
* @return resulting configuration
|
||||||
|
*/
|
||||||
|
fun hostTarget(sanitizer: SanitizerKind? = null, action: Action<in T>): T {
|
||||||
|
return target(HostManager.host, sanitizer, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get configuration [T] for [host target][HostManager.host] with optional [sanitizer].
|
||||||
|
*
|
||||||
|
* @param sanitizer optional sanitizer for [host target][HostManager.host]
|
||||||
|
* @return resulting configuration
|
||||||
|
* @throws UnknownDomainObjectException if configuration for [host target][HostManager.host] and [sanitizer] does not exist
|
||||||
|
*/
|
||||||
|
fun hostTarget(sanitizer: SanitizerKind? = null): T {
|
||||||
|
return target(HostManager.host, sanitizer)
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Get configuration [T] for [host target][HostManager.host] without sanitizer.
|
||||||
|
*
|
||||||
|
* @return resulting configuration
|
||||||
|
* @throws UnknownDomainObjectException if configuration for [host target][HostManager.host] without sanitizer does not exist
|
||||||
|
*/
|
||||||
|
val hostTarget: T
|
||||||
|
get() = hostTarget()
|
||||||
|
}
|
||||||
+26
-24
@@ -11,6 +11,7 @@ import org.gradle.api.Project
|
|||||||
import org.gradle.api.file.FileCollection
|
import org.gradle.api.file.FileCollection
|
||||||
import org.gradle.api.provider.Provider
|
import org.gradle.api.provider.Provider
|
||||||
import org.gradle.api.tasks.TaskProvider
|
import org.gradle.api.tasks.TaskProvider
|
||||||
|
import org.gradle.kotlin.dsl.getByType
|
||||||
import org.jetbrains.kotlin.bitcode.CompileToBitcodeExtension
|
import org.jetbrains.kotlin.bitcode.CompileToBitcodeExtension
|
||||||
import org.jetbrains.kotlin.bitcode.CompileToBitcodePlugin
|
import org.jetbrains.kotlin.bitcode.CompileToBitcodePlugin
|
||||||
import org.jetbrains.kotlin.resolve
|
import org.jetbrains.kotlin.resolve
|
||||||
@@ -51,32 +52,33 @@ open class RuntimeTestingPlugin : Plugin<Project> {
|
|||||||
dependencies: Iterable<TaskProvider<*>>
|
dependencies: Iterable<TaskProvider<*>>
|
||||||
) {
|
) {
|
||||||
pluginManager.withPlugin("compile-to-bitcode") {
|
pluginManager.withPlugin("compile-to-bitcode") {
|
||||||
val bitcodeExtension =
|
val bitcodeExtension = project.extensions.getByType<CompileToBitcodeExtension>()
|
||||||
project.extensions.getByName(CompileToBitcodePlugin.EXTENSION_NAME) as CompileToBitcodeExtension
|
|
||||||
|
|
||||||
bitcodeExtension.module("googletest", outputGroup = "test") {
|
bitcodeExtension.allTargets {
|
||||||
inputFiles.from(googleTestRoot.resolve("googletest/src"))
|
module("googletest", outputGroup = "test") {
|
||||||
inputFiles.include("*.cc")
|
inputFiles.from(googleTestRoot.resolve("googletest/src"))
|
||||||
inputFiles.exclude("gtest-all.cc", "gtest_main.cc")
|
inputFiles.include("*.cc")
|
||||||
headersDirs.from(
|
inputFiles.exclude("gtest-all.cc", "gtest_main.cc")
|
||||||
googleTestRoot.resolve("googletest/include"),
|
headersDirs.from(
|
||||||
googleTestRoot.resolve("googletest")
|
googleTestRoot.resolve("googletest/include"),
|
||||||
)
|
googleTestRoot.resolve("googletest")
|
||||||
compilerArgs.set(listOf("-std=c++17", "-O2"))
|
)
|
||||||
dependsOn(dependencies)
|
compilerArgs.set(listOf("-std=c++17", "-O2"))
|
||||||
}
|
dependsOn(dependencies)
|
||||||
|
}
|
||||||
|
|
||||||
bitcodeExtension.module("googlemock", outputGroup = "test") {
|
module("googlemock", outputGroup = "test") {
|
||||||
inputFiles.from(googleTestRoot.resolve("googlemock/src"))
|
inputFiles.from(googleTestRoot.resolve("googlemock/src"))
|
||||||
inputFiles.include("*.cc")
|
inputFiles.include("*.cc")
|
||||||
inputFiles.exclude("gmock-all.cc", "gmock_main.cc")
|
inputFiles.exclude("gmock-all.cc", "gmock_main.cc")
|
||||||
headersDirs.from(
|
headersDirs.from(
|
||||||
googleTestRoot.resolve("googlemock"),
|
googleTestRoot.resolve("googlemock"),
|
||||||
googleTestRoot.resolve("googlemock/include"),
|
googleTestRoot.resolve("googlemock/include"),
|
||||||
googleTestRoot.resolve("googletest/include"),
|
googleTestRoot.resolve("googletest/include"),
|
||||||
)
|
)
|
||||||
compilerArgs.set(listOf("-std=c++17", "-O2"))
|
compilerArgs.set(listOf("-std=c++17", "-O2"))
|
||||||
dependsOn(dependencies)
|
dependsOn(dependencies)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,11 +8,14 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
bitcode {
|
bitcode {
|
||||||
module("files") {
|
// These are only used in kotlin-native/backend.native/build.gradle where only the host target is needed.
|
||||||
headersDirs.from(layout.projectDirectory.dir("src/files/headers"))
|
hostTarget {
|
||||||
}
|
module("files") {
|
||||||
module("env") {
|
headersDirs.from(layout.projectDirectory.dir("src/files/headers"))
|
||||||
headersDirs.from(layout.projectDirectory.dir("src/env/headers"))
|
}
|
||||||
|
module("env") {
|
||||||
|
headersDirs.from(layout.projectDirectory.dir("src/env/headers"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -37,190 +37,192 @@ val hostName: String by project
|
|||||||
val targetList: List<String> by project
|
val targetList: List<String> by project
|
||||||
|
|
||||||
bitcode {
|
bitcode {
|
||||||
module("main") {
|
allTargets {
|
||||||
// TODO: Split out out `base` module and merge it together with `main` into `runtime.bc`
|
module("main") {
|
||||||
if (sanitizer == null) {
|
// TODO: Split out out `base` module and merge it together with `main` into `runtime.bc`
|
||||||
outputFile.set(layout.buildDirectory.file("bitcode/main/$target/runtime.bc"))
|
if (sanitizer == null) {
|
||||||
|
outputFile.set(layout.buildDirectory.file("bitcode/main/$target/runtime.bc"))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module("mimalloc") {
|
module("mimalloc") {
|
||||||
val srcRoot = file("src/mimalloc")
|
val srcRoot = file("src/mimalloc")
|
||||||
compiler.set("clang")
|
compiler.set("clang")
|
||||||
compilerArgs.set(listOfNotNull(
|
compilerArgs.set(listOfNotNull(
|
||||||
"-std=gnu11",
|
"-std=gnu11",
|
||||||
if (sanitizer == SanitizerKind.THREAD) { "-O1" } else { "-O3" },
|
if (sanitizer == SanitizerKind.THREAD) { "-O1" } else { "-O3" },
|
||||||
"-DKONAN_MI_MALLOC=1",
|
"-DKONAN_MI_MALLOC=1",
|
||||||
"-Wno-unknown-pragmas",
|
"-Wno-unknown-pragmas",
|
||||||
"-ftls-model=initial-exec",
|
"-ftls-model=initial-exec",
|
||||||
"-Wno-unused-function",
|
"-Wno-unused-function",
|
||||||
"-Wno-error=atomic-alignment",
|
"-Wno-error=atomic-alignment",
|
||||||
"-Wno-unused-parameter", /* for windows 32 */
|
"-Wno-unused-parameter", /* for windows 32 */
|
||||||
"-DMI_TSAN=1".takeIf { sanitizer == SanitizerKind.THREAD },
|
"-DMI_TSAN=1".takeIf { sanitizer == SanitizerKind.THREAD },
|
||||||
))
|
))
|
||||||
inputFiles.from("$srcRoot/c")
|
inputFiles.from("$srcRoot/c")
|
||||||
inputFiles.include("**/*.c")
|
inputFiles.include("**/*.c")
|
||||||
inputFiles.exclude("**/alloc-override*.c", "**/page-queue.c", "**/static.c", "**/bitmap.inc.c")
|
inputFiles.exclude("**/alloc-override*.c", "**/page-queue.c", "**/static.c", "**/bitmap.inc.c")
|
||||||
headersDirs.setFrom("$srcRoot/c/include")
|
headersDirs.setFrom("$srcRoot/c/include")
|
||||||
|
|
||||||
onlyIf { targetSupportsMimallocAllocator(target.name) }
|
onlyIf { targetSupportsMimallocAllocator(target.name) }
|
||||||
}
|
|
||||||
|
|
||||||
module("libbacktrace") {
|
|
||||||
val srcRoot = file("src/libbacktrace")
|
|
||||||
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",
|
|
||||||
"elf.c".takeIf { useElf },
|
|
||||||
"fileline.c",
|
|
||||||
"macho.c".takeIf { useMachO },
|
|
||||||
"mmap.c",
|
|
||||||
"mmapio.c",
|
|
||||||
"posix.c",
|
|
||||||
"print.c",
|
|
||||||
"simple.c",
|
|
||||||
"sort.c",
|
|
||||||
"state.c"
|
|
||||||
))
|
|
||||||
headersDirs.setFrom("$srcRoot/c/include")
|
|
||||||
|
|
||||||
onlyIf { targetSupportsLibBacktrace(target.name) }
|
module("libbacktrace") {
|
||||||
}
|
val srcRoot = file("src/libbacktrace")
|
||||||
|
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",
|
||||||
|
"elf.c".takeIf { useElf },
|
||||||
|
"fileline.c",
|
||||||
|
"macho.c".takeIf { useMachO },
|
||||||
|
"mmap.c",
|
||||||
|
"mmapio.c",
|
||||||
|
"posix.c",
|
||||||
|
"print.c",
|
||||||
|
"simple.c",
|
||||||
|
"sort.c",
|
||||||
|
"state.c"
|
||||||
|
))
|
||||||
|
headersDirs.setFrom("$srcRoot/c/include")
|
||||||
|
|
||||||
module("compiler_interface") {
|
onlyIf { targetSupportsLibBacktrace(target.name) }
|
||||||
headersDirs.from(files("src/main/cpp"))
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module("launcher") {
|
module("compiler_interface") {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("debug") {
|
module("launcher") {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("std_alloc") {
|
module("debug") {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("opt_alloc") {
|
module("std_alloc") {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("exceptionsSupport", file("src/exceptions_support")) {
|
module("opt_alloc") {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("source_info_core_symbolication", file("src/source_info/core_symbolication")) {
|
module("exceptionsSupport", file("src/exceptions_support")) {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
onlyIf { targetSupportsCoreSymbolication(target.name) }
|
}
|
||||||
}
|
|
||||||
module("source_info_libbacktrace", file("src/source_info/libbacktrace")) {
|
|
||||||
headersDirs.from(files("src/main/cpp", "src/libbacktrace/c/include"))
|
|
||||||
onlyIf { targetSupportsLibBacktrace(target.name) }
|
|
||||||
}
|
|
||||||
|
|
||||||
module("strict") {
|
module("source_info_core_symbolication", file("src/source_info/core_symbolication")) {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
onlyIf { targetSupportsCoreSymbolication(target.name) }
|
||||||
|
}
|
||||||
|
module("source_info_libbacktrace", file("src/source_info/libbacktrace")) {
|
||||||
|
headersDirs.from(files("src/main/cpp", "src/libbacktrace/c/include"))
|
||||||
|
onlyIf { targetSupportsLibBacktrace(target.name) }
|
||||||
|
}
|
||||||
|
|
||||||
module("relaxed") {
|
module("strict") {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("profileRuntime", file("src/profile_runtime"))
|
module("relaxed") {
|
||||||
|
headersDirs.from(files("src/main/cpp"))
|
||||||
|
}
|
||||||
|
|
||||||
module("objc") {
|
module("profileRuntime", file("src/profile_runtime"))
|
||||||
headersDirs.from(files("src/main/cpp"))
|
|
||||||
}
|
|
||||||
|
|
||||||
module("test_support", outputGroup = "test") {
|
module("objc") {
|
||||||
headersDirs.from(files("src/main/cpp"), googletest.headersDirs)
|
headersDirs.from(files("src/main/cpp"))
|
||||||
dependsOn("downloadGoogleTest")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
module("legacy_memory_manager", file("src/legacymm")) {
|
module("test_support", outputGroup = "test") {
|
||||||
headersDirs.from(files("src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"), googletest.headersDirs)
|
||||||
}
|
dependsOn("downloadGoogleTest")
|
||||||
|
}
|
||||||
|
|
||||||
module("experimental_memory_manager", file("src/mm")) {
|
module("legacy_memory_manager", file("src/legacymm")) {
|
||||||
headersDirs.from(files("src/gc/common/cpp", "src/main/cpp"))
|
headersDirs.from(files("src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("common_gc", file("src/gc/common")) {
|
module("experimental_memory_manager", file("src/mm")) {
|
||||||
headersDirs.from(files("src/mm/cpp", "src/main/cpp"))
|
headersDirs.from(files("src/gc/common/cpp", "src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("noop_gc", file("src/gc/noop")) {
|
module("common_gc", file("src/gc/common")) {
|
||||||
headersDirs.from(files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
headersDirs.from(files("src/mm/cpp", "src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("same_thread_ms_gc", file("src/gc/stms")) {
|
module("noop_gc", file("src/gc/noop")) {
|
||||||
headersDirs.from(files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
headersDirs.from(files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
||||||
}
|
}
|
||||||
|
|
||||||
module("concurrent_ms_gc", file("src/gc/cms")) {
|
module("same_thread_ms_gc", file("src/gc/stms")) {
|
||||||
headersDirs.from(files("src/gc/cms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
headersDirs.from(files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
||||||
|
}
|
||||||
|
|
||||||
onlyIf { targetSupportsThreads(target.name) }
|
module("concurrent_ms_gc", file("src/gc/cms")) {
|
||||||
}
|
headersDirs.from(files("src/gc/cms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp"))
|
||||||
|
|
||||||
testsGroup("std_alloc_runtime_tests") {
|
onlyIf { targetSupportsThreads(target.name) }
|
||||||
testedModules.addAll("main", "legacy_memory_manager", "strict", "std_alloc", "objc")
|
}
|
||||||
}
|
|
||||||
|
|
||||||
testsGroup("mimalloc_runtime_tests") {
|
testsGroup("std_alloc_runtime_tests") {
|
||||||
testedModules.addAll("main", "legacy_memory_manager", "strict", "mimalloc", "opt_alloc", "objc")
|
testedModules.addAll("main", "legacy_memory_manager", "strict", "std_alloc", "objc")
|
||||||
}
|
}
|
||||||
|
|
||||||
testsGroup("experimentalMM_mimalloc_runtime_tests") {
|
testsGroup("mimalloc_runtime_tests") {
|
||||||
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "mimalloc", "opt_alloc", "objc")
|
testedModules.addAll("main", "legacy_memory_manager", "strict", "mimalloc", "opt_alloc", "objc")
|
||||||
}
|
}
|
||||||
|
|
||||||
testsGroup("experimentalMM_std_alloc_runtime_tests") {
|
testsGroup("experimentalMM_mimalloc_runtime_tests") {
|
||||||
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "std_alloc", "objc")
|
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "mimalloc", "opt_alloc", "objc")
|
||||||
}
|
}
|
||||||
|
|
||||||
testsGroup("experimentalMM_cms_mimalloc_runtime_tests") {
|
testsGroup("experimentalMM_std_alloc_runtime_tests") {
|
||||||
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "mimalloc", "opt_alloc", "objc")
|
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "std_alloc", "objc")
|
||||||
}
|
}
|
||||||
|
|
||||||
testsGroup("experimentalMM_cms_std_alloc_runtime_tests") {
|
testsGroup("experimentalMM_cms_mimalloc_runtime_tests") {
|
||||||
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "std_alloc", "objc")
|
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "mimalloc", "opt_alloc", "objc")
|
||||||
}
|
}
|
||||||
|
|
||||||
testsGroup("experimentalMM_noop_mimalloc_runtime_tests") {
|
testsGroup("experimentalMM_cms_std_alloc_runtime_tests") {
|
||||||
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "noop_gc", "mimalloc", "opt_alloc", "objc")
|
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "std_alloc", "objc")
|
||||||
}
|
}
|
||||||
|
|
||||||
testsGroup("experimentalMM_noop_std_alloc_runtime_tests") {
|
testsGroup("experimentalMM_noop_mimalloc_runtime_tests") {
|
||||||
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "noop_gc", "std_alloc", "objc")
|
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "noop_gc", "mimalloc", "opt_alloc", "objc")
|
||||||
|
}
|
||||||
|
|
||||||
|
testsGroup("experimentalMM_noop_std_alloc_runtime_tests") {
|
||||||
|
testedModules.addAll("main", "experimental_memory_manager", "common_gc", "noop_gc", "std_alloc", "objc")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -9,3 +9,18 @@ enum class SanitizerKind {
|
|||||||
ADDRESS,
|
ADDRESS,
|
||||||
THREAD,
|
THREAD,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Suffix for [KonanTarget] name.
|
||||||
|
*
|
||||||
|
* In string interpolation use
|
||||||
|
* ```
|
||||||
|
* "… ${target}${sanitizer.targetSuffix} …"
|
||||||
|
* ```
|
||||||
|
*/
|
||||||
|
val SanitizerKind?.targetSuffix: String
|
||||||
|
get() = when (this) {
|
||||||
|
null -> ""
|
||||||
|
SanitizerKind.THREAD -> "_tsan"
|
||||||
|
SanitizerKind.ADDRESS -> "_asan"
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user