diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcodePlugin.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcodePlugin.kt index d5b2ad4897b..5e1a52e1710 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcodePlugin.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcodePlugin.kt @@ -23,13 +23,42 @@ import org.jetbrains.kotlin.cpp.RunGTest 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.supportedSanitizers +import org.jetbrains.kotlin.konan.target.TargetDomainObjectContainer import org.jetbrains.kotlin.testing.native.GoogleTestExtension import org.jetbrains.kotlin.utils.Maybe import org.jetbrains.kotlin.utils.asMaybe import java.io.File 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 private abstract class CompileTestsSemaphore : BuildService @@ -47,7 +76,13 @@ open class CompileToBitcodePlugin : Plugin { } } -open class CompileToBitcodeExtension @Inject constructor(val project: Project) { +open class CompileToBitcodeExtension @Inject constructor(val project: Project) : TargetDomainObjectContainer(project) { + init { + this.factory = { target, sanitizer -> + project.objects.newInstance(this, target, sanitizer.asMaybe) + } + } + // 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) }, @@ -60,24 +95,6 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) { "-Wno-unused-parameter", // False positives with polymorphic functions. ) - private val compilationDatabase = project.extensions.getByType() - private val execClang = project.extensions.getByType() - private val platformManager = project.extensions.getByType() - - // googleTestExtension is only used if testsGroup is used. - private val googleTestExtension by lazy { project.extensions.getByType() } - - // 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) { provider { (rootProject.project(":kotlin-native").property("targetList") as? List<*>)?.filterIsInstance() ?: 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 = 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( val target: KonanTarget, private val _sanitizer: Maybe, @@ -166,145 +130,168 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) { abstract val testLauncherModule: Property } - private fun createTestTask( - testTaskName: String, - testsGroup: TestsGroup, + abstract class Target @Inject constructor( + private val owner: CompileToBitcodeExtension, + val target: KonanTarget, + _sanitizer: Maybe, ) { - 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}" + val sanitizer = _sanitizer.orNull - dependsOn(":kotlin-native:dependencies:update") - dependsOn("downloadGoogleTest") + private val project by owner::project - addToCompdb(this, target) - } - 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 + private val compilationDatabase = project.extensions.getByType() + private val execClang = project.extensions.getByType() + private val platformManager = project.extensions.getByType() + + // googleTestExtension is only used if testsGroup is used. + private val googleTestExtension by lazy { project.extensions.getByType() } + + // 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 { - val name = fullTaskName(it, target.name, sanitizer) - project.tasks.getByName(name) as CompileToBitcode + // 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) } - val compileTask = project.tasks.register("${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.executableExtension}")) - 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(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, - ) { - platformManager.enabled.forEach { target -> - val sanitizers: List = 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) + private fun addToCompdb(compileTask: CompileToBitcode) { + compilationDatabase.target(target, sanitizer) { + entry { + val args = listOf(execClang.resolveExecutable(compileTask.compiler.get())) + compileTask.compilerFlags.get() + execClang.clangArgsForCppRuntime(target.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 }) } - 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, + ) { + 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("${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(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 { - const val BUILD_TASK_GROUP = LifecycleBasePlugin.BUILD_GROUP const val VERIFICATION_TASK_GROUP = LifecycleBasePlugin.VERIFICATION_GROUP 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 -> "" - } } } diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CompilationDatabasePlugin.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CompilationDatabasePlugin.kt index d61ab14c5b1..c3dff9d2c24 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CompilationDatabasePlugin.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CompilationDatabasePlugin.kt @@ -11,13 +11,18 @@ import org.gradle.api.Project import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.ListProperty -import org.gradle.api.provider.MapProperty import org.gradle.api.provider.Property import org.gradle.api.provider.Provider -import org.gradle.kotlin.dsl.* -import org.jetbrains.kotlin.konan.target.HostManager +import org.gradle.kotlin.dsl.create +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.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 /** @@ -40,10 +45,12 @@ import javax.inject.Inject * * @see CompilationDatabasePlugin gradle plugin that creates this extension. */ -abstract class CompilationDatabaseExtension @Inject constructor(private val project: Project) { - // TODO: This platformManager should acquired be from something service-ish. - // But for usefulness this service should be accessible from WorkAction. - private val platformManager = project.extensions.getByType() +abstract class CompilationDatabaseExtension @Inject constructor(private val project: Project) : TargetDomainObjectContainer(project) { + init { + this.factory = { target, sanitizer -> + project.objects.newInstance(project, target, sanitizer.asMaybe) + } + } /** * 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]. * * @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, + ) { + val sanitizer = _sanitizer.orNull + /** * **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. * * @property target target for which compilation database is generated. + * @property sanitizer optional sanitizer for which compilation database is generated. */ abstract class Target @Inject constructor( private val project: Project, val target: KonanTarget, + _sanitizer: Maybe, ) { + val sanitizer = _sanitizer.orNull + protected abstract val mergeFrom: ListProperty /** - * 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. */ fun mergeFrom(from: Provider) { mergeFrom.add(from.flatMap { project -> - project.extensions.getByType().target(target).task + project.extensions.getByType().target(target, sanitizer).task }) } protected abstract val entries: ListProperty /** - * 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] */ fun entry(action: Action) { entries.add(project.provider { - val instance = project.objects.newInstance(target).apply { + val instance = project.objects.newInstance(target, sanitizer.asMaybe).apply { action.execute(this) } project.objects.newInstance().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("${target}CompilationDatabase") { - description = "Generate compilation database for $target" + val task = project.tasks.register("${target}${sanitizer.targetSuffix}CompilationDatabase") { + description = "Generate compilation database for $target${sanitizer.targetSuffix}" group = TASK_GROUP mergeFiles.from(mergeFrom) 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 - - private fun targetGetOrPut(target: KonanTarget) = targets.getting(target).orNull - ?: project.objects.newInstance(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) = 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) = 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) = target(HostManager.host, action) - - /** - * Get [compilation database configuration][Target] for [host target][HostManager.host]. - */ - val hostTarget - get() = hostTarget {} - companion object { @JvmStatic val TASK_GROUP = "development support" diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/konan/target/TargetDomainObjectContainer.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/konan/target/TargetDomainObjectContainer.kt new file mode 100644 index 00000000000..31373b49f77 --- /dev/null +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/konan/target/TargetDomainObjectContainer.kt @@ -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> 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 constructor( + private val providerFactory: ProviderFactory, + private val platformManager: PlatformManager, +) { + constructor(project: Project) : this(project.providers, project.extensions.getByType()) + + /** + * How to create [T]. Must be set before using the rest of API. + */ + lateinit var factory: (KonanTarget, SanitizerKind?) -> T + + private val targets: MutableMap, 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): 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): List { + 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> = 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): 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() +} \ No newline at end of file diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/testing/native/RuntimeTestingPlugin.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/testing/native/RuntimeTestingPlugin.kt index 4fee05529de..dffdcdbb547 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/testing/native/RuntimeTestingPlugin.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/testing/native/RuntimeTestingPlugin.kt @@ -11,6 +11,7 @@ import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider import org.gradle.api.tasks.TaskProvider +import org.gradle.kotlin.dsl.getByType import org.jetbrains.kotlin.bitcode.CompileToBitcodeExtension import org.jetbrains.kotlin.bitcode.CompileToBitcodePlugin import org.jetbrains.kotlin.resolve @@ -51,32 +52,33 @@ open class RuntimeTestingPlugin : Plugin { dependencies: Iterable> ) { pluginManager.withPlugin("compile-to-bitcode") { - val bitcodeExtension = - project.extensions.getByName(CompileToBitcodePlugin.EXTENSION_NAME) as CompileToBitcodeExtension + val bitcodeExtension = project.extensions.getByType() - bitcodeExtension.module("googletest", outputGroup = "test") { - 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") - ) - compilerArgs.set(listOf("-std=c++17", "-O2")) - dependsOn(dependencies) - } + bitcodeExtension.allTargets { + module("googletest", outputGroup = "test") { + 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") + ) + compilerArgs.set(listOf("-std=c++17", "-O2")) + dependsOn(dependencies) + } - bitcodeExtension.module("googlemock", outputGroup = "test") { - 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"), - ) - compilerArgs.set(listOf("-std=c++17", "-O2")) - dependsOn(dependencies) + module("googlemock", outputGroup = "test") { + 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"), + ) + compilerArgs.set(listOf("-std=c++17", "-O2")) + dependsOn(dependencies) + } } } } diff --git a/kotlin-native/common/build.gradle.kts b/kotlin-native/common/build.gradle.kts index 4c25e7af1bc..345c9b2c8c9 100644 --- a/kotlin-native/common/build.gradle.kts +++ b/kotlin-native/common/build.gradle.kts @@ -8,11 +8,14 @@ plugins { } bitcode { - module("files") { - headersDirs.from(layout.projectDirectory.dir("src/files/headers")) - } - module("env") { - headersDirs.from(layout.projectDirectory.dir("src/env/headers")) + // These are only used in kotlin-native/backend.native/build.gradle where only the host target is needed. + hostTarget { + module("files") { + headersDirs.from(layout.projectDirectory.dir("src/files/headers")) + } + module("env") { + headersDirs.from(layout.projectDirectory.dir("src/env/headers")) + } } } diff --git a/kotlin-native/runtime/build.gradle.kts b/kotlin-native/runtime/build.gradle.kts index ca770cc49b8..5a68bf1725f 100644 --- a/kotlin-native/runtime/build.gradle.kts +++ b/kotlin-native/runtime/build.gradle.kts @@ -37,190 +37,192 @@ val hostName: String by project val targetList: List by project bitcode { - module("main") { - // 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")) + allTargets { + module("main") { + // 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") - 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") + module("mimalloc") { + val srcRoot = file("src/mimalloc") + 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.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 + onlyIf { targetSupportsMimallocAllocator(target.name) } } - 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") { - headersDirs.from(files("src/main/cpp")) - } + onlyIf { targetSupportsLibBacktrace(target.name) } + } - module("launcher") { - headersDirs.from(files("src/main/cpp")) - } + module("compiler_interface") { + headersDirs.from(files("src/main/cpp")) + } - module("debug") { - headersDirs.from(files("src/main/cpp")) - } + module("launcher") { + headersDirs.from(files("src/main/cpp")) + } - module("std_alloc") { - headersDirs.from(files("src/main/cpp")) - } + module("debug") { + headersDirs.from(files("src/main/cpp")) + } - module("opt_alloc") { - headersDirs.from(files("src/main/cpp")) - } + module("std_alloc") { + headersDirs.from(files("src/main/cpp")) + } - module("exceptionsSupport", file("src/exceptions_support")) { - headersDirs.from(files("src/main/cpp")) - } + module("opt_alloc") { + headersDirs.from(files("src/main/cpp")) + } - module("source_info_core_symbolication", file("src/source_info/core_symbolication")) { - 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("exceptionsSupport", file("src/exceptions_support")) { + headersDirs.from(files("src/main/cpp")) + } - module("strict") { - headersDirs.from(files("src/main/cpp")) - } + module("source_info_core_symbolication", file("src/source_info/core_symbolication")) { + 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") { - headersDirs.from(files("src/main/cpp")) - } + module("strict") { + headersDirs.from(files("src/main/cpp")) + } - module("profileRuntime", file("src/profile_runtime")) + module("relaxed") { + headersDirs.from(files("src/main/cpp")) + } - module("objc") { - headersDirs.from(files("src/main/cpp")) - } + module("profileRuntime", file("src/profile_runtime")) - module("test_support", outputGroup = "test") { - headersDirs.from(files("src/main/cpp"), googletest.headersDirs) - dependsOn("downloadGoogleTest") - } + module("objc") { + headersDirs.from(files("src/main/cpp")) + } - module("legacy_memory_manager", file("src/legacymm")) { - headersDirs.from(files("src/main/cpp")) - } + module("test_support", outputGroup = "test") { + headersDirs.from(files("src/main/cpp"), googletest.headersDirs) + dependsOn("downloadGoogleTest") + } - module("experimental_memory_manager", file("src/mm")) { - headersDirs.from(files("src/gc/common/cpp", "src/main/cpp")) - } + module("legacy_memory_manager", file("src/legacymm")) { + headersDirs.from(files("src/main/cpp")) + } - module("common_gc", file("src/gc/common")) { - headersDirs.from(files("src/mm/cpp", "src/main/cpp")) - } + module("experimental_memory_manager", file("src/mm")) { + headersDirs.from(files("src/gc/common/cpp", "src/main/cpp")) + } - module("noop_gc", file("src/gc/noop")) { - headersDirs.from(files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp")) - } + module("common_gc", file("src/gc/common")) { + headersDirs.from(files("src/mm/cpp", "src/main/cpp")) + } - module("same_thread_ms_gc", file("src/gc/stms")) { - headersDirs.from(files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp")) - } + module("noop_gc", file("src/gc/noop")) { + 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")) { - headersDirs.from(files("src/gc/cms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp")) + module("same_thread_ms_gc", file("src/gc/stms")) { + 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") { - testedModules.addAll("main", "legacy_memory_manager", "strict", "std_alloc", "objc") - } + onlyIf { targetSupportsThreads(target.name) } + } - testsGroup("mimalloc_runtime_tests") { - testedModules.addAll("main", "legacy_memory_manager", "strict", "mimalloc", "opt_alloc", "objc") - } + testsGroup("std_alloc_runtime_tests") { + testedModules.addAll("main", "legacy_memory_manager", "strict", "std_alloc", "objc") + } - testsGroup("experimentalMM_mimalloc_runtime_tests") { - testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "mimalloc", "opt_alloc", "objc") - } + testsGroup("mimalloc_runtime_tests") { + testedModules.addAll("main", "legacy_memory_manager", "strict", "mimalloc", "opt_alloc", "objc") + } - testsGroup("experimentalMM_std_alloc_runtime_tests") { - testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "std_alloc", "objc") - } + testsGroup("experimentalMM_mimalloc_runtime_tests") { + testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "mimalloc", "opt_alloc", "objc") + } - testsGroup("experimentalMM_cms_mimalloc_runtime_tests") { - testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "mimalloc", "opt_alloc", "objc") - } + testsGroup("experimentalMM_std_alloc_runtime_tests") { + testedModules.addAll("main", "experimental_memory_manager", "common_gc", "same_thread_ms_gc", "std_alloc", "objc") + } - testsGroup("experimentalMM_cms_std_alloc_runtime_tests") { - testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "std_alloc", "objc") - } + testsGroup("experimentalMM_cms_mimalloc_runtime_tests") { + testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "mimalloc", "opt_alloc", "objc") + } - testsGroup("experimentalMM_noop_mimalloc_runtime_tests") { - testedModules.addAll("main", "experimental_memory_manager", "common_gc", "noop_gc", "mimalloc", "opt_alloc", "objc") - } + testsGroup("experimentalMM_cms_std_alloc_runtime_tests") { + testedModules.addAll("main", "experimental_memory_manager", "common_gc", "concurrent_ms_gc", "std_alloc", "objc") + } - testsGroup("experimentalMM_noop_std_alloc_runtime_tests") { - testedModules.addAll("main", "experimental_memory_manager", "common_gc", "noop_gc", "std_alloc", "objc") + testsGroup("experimentalMM_noop_mimalloc_runtime_tests") { + 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") + } } } diff --git a/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Sanitizer.kt b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Sanitizer.kt index 3ab83ccfaed..aa30b9e9641 100644 --- a/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Sanitizer.kt +++ b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Sanitizer.kt @@ -9,3 +9,18 @@ enum class SanitizerKind { ADDRESS, 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" + }