From ff2f163ac949623e4a47da56e020b779c9865416 Mon Sep 17 00:00:00 2001 From: Alexander Shabalin Date: Wed, 21 Dec 2022 22:30:25 +0000 Subject: [PATCH] [K/N] Extract Module in CompileToBitcodePlugin ^KT-53776 Merge-request: KT-MR-7960 Merged-by: Alexander Shabalin --- kotlin-native/backend.native/build.gradle | 22 +- .../kotlin/bitcode/CompileToBitcode.kt | 4 - .../kotlin/bitcode/CompileToBitcodePlugin.kt | 609 +++++++++++++----- .../kotlin/cpp/CompilationDatabasePlugin.kt | 14 +- .../jetbrains/kotlin/cpp/CppConsumerPlugin.kt | 53 ++ .../org/jetbrains/kotlin/cpp/CppUsage.kt | 24 + .../kotlin/cpp/DependencyHandlerEx.kt | 44 ++ .../testing/native/RuntimeTestingPlugin.kt | 46 +- kotlin-native/build.gradle | 4 +- kotlin-native/common/build.gradle.kts | 6 + kotlin-native/runtime/build.gradle.kts | 209 ++++-- 11 files changed, 761 insertions(+), 274 deletions(-) create mode 100644 kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppConsumerPlugin.kt create mode 100644 kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppUsage.kt create mode 100644 kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/DependencyHandlerEx.kt diff --git a/kotlin-native/backend.native/build.gradle b/kotlin-native/backend.native/build.gradle index 8dd7d47cc9e..fcfdab90efe 100644 --- a/kotlin-native/backend.native/build.gradle +++ b/kotlin-native/backend.native/build.gradle @@ -1,8 +1,7 @@ -import org.jetbrains.kotlin.CopyCommonSources -import org.jetbrains.kotlin.konan.target.* -import org.jetbrains.kotlin.* +import org.jetbrains.kotlin.cpp.CppConsumerPlugin +import org.jetbrains.kotlin.cpp.CppUsage +import org.jetbrains.kotlin.cpp.DependencyHandlerExKt import org.jetbrains.gradle.plugins.tools.* -import org.jetbrains.kotlin.bitcode.* /* * Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * that can be found in the LICENSE file. @@ -16,6 +15,7 @@ apply plugin: 'java' apply plugin: 'kotlin' apply plugin: org.jetbrains.kotlin.NativeInteropPlugin apply plugin: "maven-publish" +apply plugin: CppConsumerPlugin sourceSets { compiler { @@ -46,25 +46,23 @@ configurations { canBeConsumed = false canBeResolved = true attributes { - attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, CompileToBitcodeExtension.USAGE)) - attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, TargetWithSanitizer.host) - attribute(CompileToBitcodeExtension.MODULE_ATTRIBUTE, "files") + attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, CppUsage.LLVM_BITCODE)) } } commonEnvBitcode { canBeConsumed = false canBeResolved = true attributes { - attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, CompileToBitcodeExtension.USAGE)) - attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, TargetWithSanitizer.host) - attribute(CompileToBitcodeExtension.MODULE_ATTRIBUTE, "env") + attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, CppUsage.LLVM_BITCODE)) } } } dependencies { - commonFilesBitcode project(":kotlin-native:common") - commonEnvBitcode project(":kotlin-native:common") + use(DependencyHandlerExKt) { + commonFilesBitcode module(project(":kotlin-native:common"), "files") + commonEnvBitcode module(project(":kotlin-native:common"), "env") + } } kotlinNativeInterop { diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcode.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcode.kt index c7bbb2a2ec0..31fdd536595 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcode.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/bitcode/CompileToBitcode.kt @@ -142,10 +142,6 @@ abstract class CompileToBitcode @Inject constructor( @get:Internal abstract val headersDirs: ConfigurableFileCollection - // TODO: Move to module description. - @get:Internal - abstract val moduleName: Property - /** * Final computed compiler arguments. */ 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 0710e917970..467ce92ecf8 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 @@ -6,23 +6,27 @@ package org.jetbrains.kotlin.bitcode import kotlinBuildProperties -import org.gradle.api.Action -import org.gradle.api.Plugin -import org.gradle.api.Project -import org.gradle.api.attributes.Attribute +import org.gradle.api.* +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ConfigurationVariant import org.gradle.api.attributes.Usage +import org.gradle.api.file.* import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider import org.gradle.api.services.BuildService import org.gradle.api.services.BuildServiceParameters +import org.gradle.api.specs.Spec +import org.gradle.api.tasks.TaskProvider import org.gradle.kotlin.dsl.* import org.gradle.language.base.plugins.LifecycleBasePlugin import org.jetbrains.kotlin.ExecClang import org.jetbrains.kotlin.cpp.* -import org.jetbrains.kotlin.konan.target.* +import org.jetbrains.kotlin.konan.target.SanitizerKind +import org.jetbrains.kotlin.konan.target.TargetDomainObjectContainer +import org.jetbrains.kotlin.konan.target.TargetWithSanitizer import org.jetbrains.kotlin.testing.native.GoogleTestExtension import org.jetbrains.kotlin.utils.capitalized -import java.io.File import javax.inject.Inject private fun String.snakeCaseToUpperCamelCase() = split('_').joinToString(separator = "") { it.capitalized } @@ -36,13 +40,6 @@ private val SanitizerKind?.taskSuffix 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 -> "" @@ -50,6 +47,48 @@ private val SanitizerKind?.description SanitizerKind.THREAD -> " with TSAN" } +/** + * Adds new object named [name] and configure it with [action] or return already existing object with this name. + * + * Similar to [NamedDomainObjectContainer.maybeCreate] but with [action] argument that will be applied only if + * an object is being created. + */ +private fun NamedDomainObjectContainer.getOrCreate(name: String, action: Action): T = try { + this.create(name, action) +} catch (e: InvalidUserDataException) { + this.getByName(name) +} + +private fun Project.compileBitcodeElements(sourceSet: String, action: Action): Configuration = configurations.getOrCreate("compileBitcode${sourceSet.capitalized}Elements") { + description = "LLVM bitcode of all defined modules ($sourceSet sources)" + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(CppUsage.LLVM_BITCODE)) + } + action.execute(this) +} + +private fun Project.compileBitcodeElements(sourceSet: String) = compileBitcodeElements(sourceSet) {} + +private fun Project.moduleCompileBitcodeElements(moduleName: String, sourceSet: String, action: Action): Configuration = configurations.getOrCreate("${moduleName}CompileBitcode${sourceSet.capitalized}Elements") { + description = "LLVM bitcode of $moduleName module ($sourceSet sources)" + isCanBeConsumed = true + isCanBeResolved = false + attributes { + attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(CppUsage.LLVM_BITCODE)) + } + action.execute(this) +} + +private fun Project.moduleCompileBitcodeElements(moduleName: String, sourceSet: String) = moduleCompileBitcodeElements(moduleName, sourceSet) {} + +private fun Configuration.targetVariant(target: TargetWithSanitizer): ConfigurationVariant = outgoing.variants.getOrCreate("$target") { + attributes { + attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, target) + } +} + private abstract class RunGTestSemaphore : BuildService private abstract class CompileTestsSemaphore : BuildService @@ -60,12 +99,26 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : } } - val compileBitcodeMainElements by project.configurations.creating { - description = "LLVM bitcode of all defined modules (main sources)" - isCanBeConsumed = true - isCanBeResolved = false - attributes { - attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(USAGE)) + /** + * Outgoing configuration with `main` parts of all modules. + */ + val compileBitcodeMainElements = project.compileBitcodeElements(MAIN_SOURCE_SET_NAME) + + /** + * Outgoing configuration with `testFixtures` parts of all modules. + */ + val compileBitcodeTestFixturesElements = project.compileBitcodeElements(TEST_FIXTURES_SOURCE_SET_NAME) { + outgoing { + capability(CppConsumerPlugin.testFixturesCapability(project)) + } + } + + /** + * Outgoing configuration with `test` parts of all modules. + */ + val compileBitcodeTestElements = project.compileBitcodeElements(TEST_SOURCE_SET_NAME) { + outgoing { + capability(CppConsumerPlugin.testCapability(project)) } } @@ -95,6 +148,294 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : }) } + /** + * A group of source files that will be compiled together. + * + * There are 3 well known source sets: `main`, `testFixtures` and `test`. + */ + abstract class SourceSet @Inject constructor( + private val owner: CompileToBitcodeExtension, + private val module: Module, + private val name: String, + private val _target: TargetWithSanitizer, + ) : Named { + val target by _target::target + val sanitizer by _target::sanitizer + + override fun getName() = name + + private val project by owner::project + + /** + * Resulting single LLVM bitcode file. + */ + abstract val outputFile: RegularFileProperty + + /** + * Directory where LLVM bitcode files for each of the [inputFiles] is placed. + */ + abstract val outputDirectory: DirectoryProperty + + /** + * Header paths to use when compiling [inputFiles]. + */ + abstract val headersDirs: ConfigurableFileCollection + + /** + * Source files to compile. + */ + abstract val inputFiles: ConfigurableFileTree + + /** + * Additional task dependencies. + */ + abstract val dependencies: ListProperty> + + protected abstract val onlyIf: ListProperty> + + /** + * Builds this source set only if [spec] is satisfied. + */ + fun onlyIf(spec: Spec) { + this.onlyIf.add(spec) + } + + private val compilationDatabase = project.extensions.getByType() + private val execClang = project.extensions.getByType() + + /** + * Task that produces [outputFile]. + */ + val task = project.tasks.register("compileToBitcode${module.name.capitalized}${name.capitalized}${_target.toString().capitalized}", _target).apply { + configure { + this.description = "Compiles '${module.name}' (${this@SourceSet.name} sources) to bitcode for ${_target}" + this.outputFile.set(this@SourceSet.outputFile) + this.outputDirectory.set(this@SourceSet.outputDirectory) + this.compiler.set(module.compiler) + this.linkerArgs.set(module.linkerArgs) + this.compilerArgs.set(module.compilerArgs) + this.headersDirs.from(this@SourceSet.headersDirs) + this.inputFiles.from(this@SourceSet.inputFiles.dir) + this.inputFiles.setIncludes(this@SourceSet.inputFiles.includes) + this.inputFiles.setExcludes(this@SourceSet.inputFiles.excludes) + this.compilerWorkingDirectory.set(module.compilerWorkingDirectory) + // TODO: Should depend only on the toolchain needed to build for the _target + dependsOn(":kotlin-native:dependencies:update") + dependsOn(this@SourceSet.dependencies) + onlyIf { + this@SourceSet.onlyIf.get().all { it.isSatisfiedBy(this@SourceSet) } + } + } + compilationDatabase.target(_target) { + entry { + val compileTask = this@apply.get() + 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 }) + } + task.configure { + // Compile task depends on the toolchain (including headers) and on the source code (e.g. googletest). + // compdb task should also have these dependencies. This way the generated database will point to the + // code that actually exists. + // TODO: Should depend only on the toolchain needed to build for the _target + dependsOn(":kotlin-native:dependencies:update") + dependsOn(this@SourceSet.dependencies) + } + } + project.compileBitcodeElements(this@SourceSet.name).targetVariant(_target).artifact(this) + project.moduleCompileBitcodeElements(module.name, this@SourceSet.name).targetVariant(_target).artifact(this) + } + } + + // TODO: Consider putting each module in a gradle project of its own. Current project should be used for grouping (i.e. reexporting all + // compileBitcodeMainElements from subprojects under a single umbrella configuration) and integration testing. + abstract class Module @Inject constructor( + private val owner: CompileToBitcodeExtension, + private val name: String, + private val _target: TargetWithSanitizer, + ) : Named { + /** + * A container for [SourceSet]. + * + * 3 source sets are well known: [main], [testFixtures] and [test]. + */ + abstract class SourceSets @Inject constructor( + private val module: Module, + private val container: ExtensiblePolymorphicDomainObjectContainer + ) : NamedDomainObjectContainer by container { + private val project by module::project + + // googleTestExtension is only used if testFixtures or tests are used. + private val googleTestExtension by lazy { project.extensions.getByType() } + + /** + * Get `main` source set if it was configured. + */ + val main: Provider + get() = named(MAIN_SOURCE_SET_NAME) + + /** + * Configure `main` source set. Used for main module sources. Included into `compileBitcodeMainElements` configuration. + */ + fun main(action: Action): SourceSet = create(MAIN_SOURCE_SET_NAME) { + this.inputFiles.include("**/*.cpp", "**/*.mm") + this.inputFiles.exclude("**/*Test.cpp", "**/*TestSupport.cpp", "**/*Test.mm", "**/*TestSupport.mm") + task.configure { + this.group = BUILD_TASK_GROUP + } + action.execute(this) + } + + /** + * Get `testFixtures` source set if it was configured. + */ + val testFixtures: Provider + get() = named(TEST_FIXTURES_SOURCE_SET_NAME) + + /** + * Configure `testFixtures` source set. Used for testing API parts of module. Included into `compileBitcodeTestFixturesElements` configuration. + */ + fun testFixtures(action: Action): SourceSet = create(TEST_FIXTURES_SOURCE_SET_NAME) { + this.inputFiles.include("**/*TestSupport.cpp", "**/*TestSupport.mm") + this.headersDirs.from(googleTestExtension.headersDirs) + // TODO: Must generally depend on googletest module headers which must itself depend on sources being present. + dependencies.add(project.tasks.named("downloadGoogleTest")) + task.configure { + this.group = VERIFICATION_BUILD_TASK_GROUP + } + action.execute(this) + } + + /** + * Get `test` source set if it was configured. + */ + val test: Provider + get() = named(TEST_SOURCE_SET_NAME) + + /** + * Configure `test` source set. Used for test files of module. Included into `compileBitcodeTestElements` configuration. + */ + fun test(action: Action): SourceSet = create(TEST_SOURCE_SET_NAME) { + this.inputFiles.include("**/*Test.cpp", "**/*Test.mm") + this.headersDirs.from(googleTestExtension.headersDirs) + // TODO: Must generally depend on googletest module headers which must itself depend on sources being present. + dependencies.add(project.tasks.named("downloadGoogleTest")) + task.configure { + this.group = VERIFICATION_BUILD_TASK_GROUP + } + action.execute(this) + } + } + + val target by _target::target + val sanitizer by _target::sanitizer + + override fun getName() = name + + private val project by owner::project + + /** + * Outgoing configuration with `main` part of this module. + */ + val compileBitcodeMainElements = project.moduleCompileBitcodeElements(name, MAIN_SOURCE_SET_NAME) { + outgoing { + capability(CppConsumerPlugin.moduleCapability(project, this@Module.name)) + } + } + + /** + * Outgoing configuration with `testFixtures` part of this module. + */ + val compileBitcodeTestFixturesElements = project.moduleCompileBitcodeElements(name, TEST_FIXTURES_SOURCE_SET_NAME) { + outgoing { + capability(CppConsumerPlugin.moduleTestFixturesCapability(project, this@Module.name)) + } + } + + /** + * Outgoing configuration with `test` part of this module. + */ + val compileBitcodeTestElements = project.moduleCompileBitcodeElements(name, TEST_SOURCE_SET_NAME) { + outgoing { + capability(CppConsumerPlugin.moduleTestCapability(project, this@Module.name)) + } + } + + /** + * Directory where module sources are located. By default `src/`. + */ + abstract val srcRoot: DirectoryProperty + + // TODO: This is actually API dependency. Make it so. + /** + * Header directories to use for compilation of all [SourceSet]s. + */ + abstract val headersDirs: ConfigurableFileCollection + + /** + * Compiler to use. Either `clang` or `clang++`. + */ + abstract val compiler: Property + + /** + * Extra arguments to `llvm-link`. + */ + abstract val linkerArgs: ListProperty + + /** + * Extra arguments to [compiler]. + */ + abstract val compilerArgs: ListProperty + + /** + * Directory in which [compiler] will be executed. Important for macro evaluation like `__FILE__`. + */ + abstract val compilerWorkingDirectory: DirectoryProperty + + /** + * Extra tqsk dependencies to be used for all [SourceSet]s. + */ + abstract val dependencies: ListProperty> + protected abstract val onlyIf: ListProperty> + + /** + * Builds this module only if [spec] is satisfied. + */ + fun onlyIf(spec: Spec) { + this.onlyIf.add(spec) + } + + /** + * Container for [SourceSet]s. + */ + val sourceSets by lazy { + project.objects.newInstance(this, project.objects.polymorphicDomainObjectContainer(SourceSet::class.java).apply { + registerFactory(SourceSet::class.java) { + project.objects.newInstance(owner, this@Module, it, _target).apply { + this.outputFile.convention(project.layout.buildDirectory.file("bitcode/$name/$_target/${this@Module.name}.bc")) + this.outputDirectory.convention(project.layout.buildDirectory.dir("bitcode/$name/$_target/${this@Module.name}")) + this.inputFiles.from(this@Module.srcRoot.dir("cpp")) + this.headersDirs.setFrom(this@Module.headersDirs) + dependencies.set(this@Module.dependencies) + onlyIf { + this@Module.onlyIf.get().all { it.isSatisfiedBy(this@Module) } + } + } + } + }) + } + + /** + * Container for [SourceSet]s. + */ + fun sourceSets(action: Action) = sourceSets.apply { + action.execute(this) + } + } + abstract class TestsGroup @Inject constructor( private val _target: TargetWithSanitizer, ) { @@ -102,7 +443,6 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : val sanitizer by _target::sanitizer abstract val testedModules: ListProperty abstract val testSupportModules: ListProperty - abstract val testFrameworkModules: ListProperty abstract val testLauncherModule: Property } @@ -115,13 +455,6 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : private val project by owner::project - 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. @@ -133,158 +466,69 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : maxParallelUsages.set(5) } - private val compileBitcodeMainElements = owner.compileBitcodeMainElements.outgoing.variants.create("$_target") { - attributes { - attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, _target) - } - } - - private fun addToCompdb(compileTask: CompileToBitcode) { - compilationDatabase.target(_target) { - 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 }) - } - // Compile task depends on the toolchain (including headers) and on the source code (e.g. googletest). - // compdb task should also have these dependencies. This way the generated database will point to the - // code that actually exists. - // TODO: Probably module should know dependencies on its own. - task.configure { - dependsOn(compileTask.dependsOn) + private val modules: NamedDomainObjectContainer = project.objects.polymorphicDomainObjectContainer(Module::class.java).apply { + registerFactory(Module::class.java) { + project.objects.newInstance(owner, it, _target).apply { + this.srcRoot.convention(project.layout.projectDirectory.dir("src/$name")) + this.headersDirs.from(this.srcRoot.dir("cpp")) + this.compiler.convention("clang++") + this.compilerArgs.set(owner.DEFAULT_CPP_FLAGS) + this.compilerWorkingDirectory.set(project.layout.projectDirectory.dir("src")) } } } - fun module(name: String, srcRoot: File = project.file("src/$name"), outputGroup: String = "main", configurationBlock: CompileToBitcode.() -> Unit = {}) { - val targetName = target.name - val taskName = fullTaskName(name, targetName, sanitizer) - val task = project.tasks.register(taskName, _target) - task.configure { - 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.get()) // TODO: Do not force task configuration. - if (outputGroup == "main") { - compileBitcodeMainElements.artifact(task) - // TODO: This seems to go against gradle conventions. So, each module should probably be in - // a gradle project of its own. Current project should be used for grouping (i.e. reexporting all - // compileBitcodeMainElements from subprojects under a single umbrella configuration) and integration testing. - project.configurations.maybeCreate("${name}CompileBitcodeMainElements").apply { - description = "LLVM bitcode of $name module (main sources)" - isCanBeConsumed = true - isCanBeResolved = false - attributes { - attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(USAGE)) - attribute(MODULE_ATTRIBUTE, name) - } - outgoing { - variants { - create("$_target") { - attributes { - attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, _target) - } - artifact(task) - } - } - } - } - } + fun module( + name: String, + action: Action, + ): Module = modules.create(name) { + action.execute(this) } + fun module(name: String): Provider = modules.named(name) + fun testsGroup( testTaskName: String, action: Action, ) { val testsGroup = project.objects.newInstance(TestsGroup::class.java, _target).apply { - testFrameworkModules.convention(listOf("googletest", "googlemock")) + testSupportModules.set(listOf("googletest", "googlemock")) testLauncherModule.convention("test_support") action.execute(this) + testLauncherModule.finalizeValue() } val target = testsGroup.target val sanitizer = testsGroup.sanitizer val testName = fullTaskName(testTaskName, target.name, sanitizer) - val testedModulesMainTasks = testsGroup.testedModules.get().map { - val name = fullTaskName(it, target.name, sanitizer) - project.tasks.getByName(name) as CompileToBitcode - } - val testedModulesTestTasks = testedModulesMainTasks.mapNotNull { - val name = "${it.name}TestBitcode" - val task = project.tasks.findByName(name) as? CompileToBitcode - ?: project.tasks.create(name, CompileToBitcode::class.java, _target).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", "**/*Test.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) - } - task.takeUnless { t -> t.inputFiles.isEmpty } + val testLauncherConfiguration = project.configurations.create("${testTaskName}${_target.toString().capitalized}TestLauncher") { + isCanBeConsumed = false + isCanBeResolved = true + attributes { + attribute(CppUsage.USAGE_ATTRIBUTE, project.objects.named(CppUsage.LLVM_BITCODE)) + } } - val testSupportModulesMainTasks = testsGroup.testSupportModules.get().map { - val name = fullTaskName(it, target.name, sanitizer) - project.tasks.getByName(name) as CompileToBitcode + val testsGroupConfiguration = project.configurations.create("${testTaskName}${_target.toString().capitalized}") { + isCanBeConsumed = false + isCanBeResolved = true + attributes { + attribute(CppUsage.USAGE_ATTRIBUTE, project.objects.named(CppUsage.LLVM_BITCODE)) + } } - val testedAndTestSupportModulesTestSupportTasks = (testedModulesMainTasks + testSupportModulesMainTasks).mapNotNull { - val name = "${it.name}TestSupportBitcode" - val task = project.tasks.findByName(name) as? CompileToBitcode - ?: project.tasks.create(name, CompileToBitcode::class.java, _target).apply { - this.moduleName.set(it.moduleName) - this.outputFile.convention(moduleName.flatMap { project.layout.buildDirectory.file("bitcode/test/$target${sanitizer.dirSuffix}/${it}TestSupport.bc") }) - this.outputDirectory.convention(moduleName.flatMap { project.layout.buildDirectory.dir("bitcode/test/$target${sanitizer.dirSuffix}/${it}TestSupport") }) - this.compiler.convention("clang++") - this.compilerArgs.set(it.compilerArgs) - this.inputFiles.from(it.inputFiles.dir) - this.inputFiles.include("**/*TestSupport.cpp", "**/*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}' test support to bitcode for $target${sanitizer.description}" - - dependsOn(":kotlin-native:dependencies:update") - dependsOn("downloadGoogleTest") - - addToCompdb(this) - } - task.takeUnless { t -> t.inputFiles.isEmpty } - } - val testFrameworkMainTasks = testsGroup.testFrameworkModules.get().map { - val name = fullTaskName(it, target.name, sanitizer) - project.tasks.getByName(name) as CompileToBitcode - } - val testLauncherMainTask = testsGroup.testLauncherModule.get().let { - val name = fullTaskName(it, target.name, sanitizer) - project.tasks.getByName(name) as CompileToBitcode + project.dependencies { + testsGroup.testLauncherModule.get().let { moduleName -> + testLauncherConfiguration(module(project(project.path), moduleName)) + testLauncherConfiguration(moduleTestFixtures(project(project.path), moduleName)) + } + testsGroup.testedModules.get().forEach { moduleName -> + testsGroupConfiguration(module(project(project.path), moduleName)) + testsGroupConfiguration(moduleTestFixtures(project(project.path), moduleName)) + testsGroupConfiguration(moduleTest(project(project.path), moduleName)) + } + testsGroup.testSupportModules.get().forEach { moduleName -> + testsGroupConfiguration(module(project(project.path), moduleName)) + testsGroupConfiguration(moduleTestFixtures(project(project.path), moduleName)) + } } val compileTask = project.tasks.register("${testName}Compile") { @@ -296,11 +540,26 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : 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(testLauncherMainTask.outputFile) - val tasksToLink = (testedModulesTestTasks + testedModulesMainTasks + testFrameworkMainTasks + testSupportModulesMainTasks + testedAndTestSupportModulesTestSupportTasks) - this.inputFiles.setFrom(tasksToLink.map { it.outputFile }) + val allModules = listOf(testsGroup.testLauncherModule.get()) + testsGroup.testSupportModules.get() + testsGroup.testedModules.get() + // TODO: Superwrong. Module should carry dependencies to system libraries that are passed to the linker. + val mimallocEnabled = allModules.contains("mimalloc") + this.mimallocEnabled.set(mimallocEnabled) + val mainFileConfiguration = testLauncherConfiguration.incoming.artifactView { + attributes { + attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, _target) + } + }.files + // TODO: Check if this is still required. + this.mainFile.set(mainFileConfiguration.singleFile) + dependsOn(mainFileConfiguration) + val inputFilesConfiguration = testsGroupConfiguration.incoming.artifactView { + attributes { + attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, _target) + } + }.files + this.inputFiles.from(inputFilesConfiguration) + // Limit parallelism. usesService(compileTestsSemaphore) } @@ -330,11 +589,9 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : const val VERIFICATION_TASK_GROUP = LifecycleBasePlugin.VERIFICATION_GROUP const val VERIFICATION_BUILD_TASK_GROUP = "verification build" - @JvmField - val USAGE = "llvm-bitcode" - - @JvmField - val MODULE_ATTRIBUTE = Attribute.of("org.jetbrains.kotlin.bitcode.module", String::class.java) + const val MAIN_SOURCE_SET_NAME = "main" + const val TEST_FIXTURES_SOURCE_SET_NAME = "testFixtures" + const val TEST_SOURCE_SET_NAME = "test" } } @@ -344,24 +601,22 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : * Creates [CompileToBitcodeExtension] extension named `bitcode`. * * Creates the following [configurations][org.gradle.api.artifacts.Configuration]: - * * `compileBitcodeMainElements` - like `apiElements` (sort of) from java plugin, or `{variant}LinkElements` from C++ plugin. - * Contains bitcode produced from main sources of all defined modules. - * * `{module}CompileBitcodeMainElements` - like `compileBitcodeMainElements` but for a single `module`. + * * `compileBitcode{sourceSet}Elements` - like `apiElements` (sort of) from java plugin, or `{variant}LinkElements` from C++ plugin. + * Contains bitcode produced from `sourceSet` sources of all defined modules. + * * `{module}CompileBitcode{sourceSet}Elements` - like `compileBitcode{sourceSet}Elements` but for a single `module`. * - * Each of the defined configuration has [Usage attribute][Usage] set to [CompileToBitcodeExtension.USAGE]. Module-specific configurations - * additionally have a [CompileToBitcodeExtension.MODULE_ATTRIBUTE] set to the module name. + * Each of the defined configuration has [Usage attribute][Usage] set to [CppUsage.LLVM_BITCODE]. * Each `*Elements` configuration has variants with [TargetWithSanitizer.TARGET_ATTRIBUTE] values. * + * To depend on a specific module, use [module][org.jetbrains.kotlin.cpp.module] and [moduleTestFixtures][org.jetbrains.kotlin.cpp.moduleTestFixtures]. + * * @see CompileToBitcodeExtension extension that this plugin creates. */ open class CompileToBitcodePlugin : Plugin { override fun apply(project: Project) { + project.apply() project.apply() project.apply() - project.dependencies.attributesSchema { - attribute(TargetWithSanitizer.TARGET_ATTRIBUTE) - attribute(CompileToBitcodeExtension.MODULE_ATTRIBUTE) - } project.extensions.create("bitcode", project) } } \ No newline at end of file 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 d16f17db88a..806043ccc2f 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 @@ -9,7 +9,6 @@ import org.gradle.api.Action import org.gradle.api.Plugin import org.gradle.api.Project import org.gradle.api.artifacts.Configuration -import org.gradle.api.attributes.Usage import org.gradle.api.file.ConfigurableFileCollection import org.gradle.api.file.DirectoryProperty import org.gradle.api.provider.ListProperty @@ -56,7 +55,7 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj isCanBeConsumed = false isCanBeResolved = false attributes { - attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(USAGE)) + attribute(CppUsage.USAGE_ATTRIBUTE, project.objects.named(CppUsage.COMPILATION_DATABASE)) } } @@ -68,7 +67,7 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj isCanBeConsumed = false isCanBeResolved = true attributes { - attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(USAGE)) + attribute(CppUsage.USAGE_ATTRIBUTE, project.objects.named(CppUsage.COMPILATION_DATABASE)) } extendsFrom(compilationDatabase) } @@ -81,7 +80,7 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj isCanBeConsumed = true isCanBeResolved = false attributes { - attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(USAGE)) + attribute(CppUsage.USAGE_ATTRIBUTE, project.objects.named(CppUsage.COMPILATION_DATABASE)) } } @@ -202,9 +201,6 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj companion object { @JvmStatic val TASK_GROUP = "development support" - - @JvmStatic - val USAGE = "compilationDatabase" } } @@ -221,9 +217,7 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj */ open class CompilationDatabasePlugin : Plugin { override fun apply(project: Project) { - project.dependencies.attributesSchema { - attribute(TargetWithSanitizer.TARGET_ATTRIBUTE) - } + project.apply() project.extensions.create("compilationDatabase", project) } } diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppConsumerPlugin.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppConsumerPlugin.kt new file mode 100644 index 00000000000..35ef1bc6680 --- /dev/null +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppConsumerPlugin.kt @@ -0,0 +1,53 @@ +/* + * 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.cpp + +import org.gradle.api.Plugin +import org.gradle.api.Project +import org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.AttributeDisambiguationRule +import org.gradle.api.attributes.MultipleCandidatesDetails +import org.jetbrains.kotlin.bitcode.CompileToBitcodePlugin +import org.jetbrains.kotlin.konan.target.TargetWithSanitizer + +private class TargetDisambiguationRule : AttributeDisambiguationRule { + override fun execute(details: MultipleCandidatesDetails) = details.run { + if (consumerValue == null) { + // If the consumer didn't want a specific target, provide host target if it's available. + val default = TargetWithSanitizer.host + if (candidateValues.contains(default)) { + closestMatch(default) + } + } + } +} + +/** + * Plugin for projects that depend upon C++-built projects. + * + * For building C++ use [CompileToBitcodePlugin]. + * + * @see CompileToBitcodePlugin + */ +// TODO: Consider doing CppBasePlugin like standard gradle plugins that also +// creates default configurations and lifecycle tasks. +class CppConsumerPlugin : Plugin { + override fun apply(project: Project) { + project.dependencies.attributesSchema { + attribute(TargetWithSanitizer.TARGET_ATTRIBUTE) { + disambiguationRules.add(TargetDisambiguationRule::class.java) + } + } + } + + companion object { + internal fun moduleCapability(project: Project, moduleName: String) = "${project.group}:${project.name}-${moduleName}:${project.version}" + internal fun testFixturesCapability(project: Project) = "${project.group}:${project.name}-test-fixtures:${project.version}" + internal fun moduleTestFixturesCapability(project: Project, moduleName: String) = "${project.group}:${project.name}-${moduleName}-test-fixtures:${project.version}" + internal fun testCapability(project: Project) = "${project.group}:${project.name}-test:${project.version}" + internal fun moduleTestCapability(project: Project, moduleName: String) = "${project.group}:${project.name}-${moduleName}-test:${project.version}" + } +} \ No newline at end of file diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppUsage.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppUsage.kt new file mode 100644 index 00000000000..75239452b16 --- /dev/null +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/CppUsage.kt @@ -0,0 +1,24 @@ +package org.jetbrains.kotlin.cpp + +import org.gradle.api.attributes.Attribute +import org.gradle.api.attributes.Usage + +/** + * Extending [Usage] constants for C++ projects. + */ +object CppUsage { + /** + * LLVM bitcode of a component. + */ + @JvmField + val LLVM_BITCODE = "llvm-bitcode" + + /** + * [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html) of a component. + */ + @JvmField + val COMPILATION_DATABASE = "llvm-compilation-database" + + @JvmField + val USAGE_ATTRIBUTE: Attribute = Usage.USAGE_ATTRIBUTE +} \ No newline at end of file diff --git a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/DependencyHandlerEx.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/DependencyHandlerEx.kt new file mode 100644 index 00000000000..a764e2a9d3c --- /dev/null +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/cpp/DependencyHandlerEx.kt @@ -0,0 +1,44 @@ +/* + * 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.cpp + +import org.gradle.api.Project +import org.gradle.api.artifacts.ProjectDependency +import org.gradle.api.artifacts.dsl.DependencyHandler +import org.jetbrains.kotlin.bitcode.CompileToBitcodePlugin + +/** + * Depend on [CompileToBitcodePlugin]'s module named [moduleName] defined in [dependency]. + */ +fun DependencyHandler.module(dependency: ProjectDependency, moduleName: String): ProjectDependency = dependency.copy().apply { + capabilities { + requireCapability(CppConsumerPlugin.moduleCapability(dependencyProject, moduleName)) + } +} + +/** + * Depend on [CompileToBitcodePlugin]'s module (testFixtures part) named [moduleName] defined in [dependency]. + */ +fun DependencyHandler.moduleTestFixtures(dependency: ProjectDependency, moduleName: String): ProjectDependency = dependency.copy().apply { + capabilities { + requireCapability(CppConsumerPlugin.moduleTestFixturesCapability(dependencyProject, moduleName)) + } +} + +/** + * Depend on [CompileToBitcodePlugin]'s module (test part) named [moduleName] defined in [dependency]. + */ +fun DependencyHandler.moduleTest(dependency: ProjectDependency, moduleName: String): ProjectDependency = dependency.copy().apply { + capabilities { + requireCapability(CppConsumerPlugin.moduleTestCapability(dependencyProject, moduleName)) + } +} + +// TODO: Remove when .gradle is gone from K/N build. +fun DependencyHandler.module(project: Project, moduleName: String): ProjectDependency = module( + dependency = this.project(mapOf("path" to project.path)) as ProjectDependency, + moduleName +) \ 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 dffdcdbb547..b441b172ed2 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 @@ -55,29 +55,37 @@ open class RuntimeTestingPlugin : Plugin { val bitcodeExtension = project.extensions.getByType() 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") - ) + module("googletest") { + sourceSets { + testFixtures { + inputFiles.from(googleTestRoot.resolve("googletest/src")) + inputFiles.include("*.cc") + inputFiles.exclude("gtest-all.cc", "gtest_main.cc") + headersDirs.setFrom( + googleTestRoot.resolve("googletest/include"), + googleTestRoot.resolve("googletest") + ) + } + } compilerArgs.set(listOf("-std=c++17", "-O2")) - dependsOn(dependencies) + this.dependencies.addAll(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"), - ) + module("googlemock") { + sourceSets { + testFixtures { + inputFiles.from(googleTestRoot.resolve("googlemock/src")) + inputFiles.include("*.cc") + inputFiles.exclude("gmock-all.cc", "gmock_main.cc") + headersDirs.setFrom( + googleTestRoot.resolve("googlemock"), + googleTestRoot.resolve("googlemock/include"), + googleTestRoot.resolve("googletest/include"), + ) + } + } compilerArgs.set(listOf("-std=c++17", "-O2")) - dependsOn(dependencies) + this.dependencies.addAll(dependencies) } } } diff --git a/kotlin-native/build.gradle b/kotlin-native/build.gradle index 35168b2cfcf..68ef2824ba7 100644 --- a/kotlin-native/build.gradle +++ b/kotlin-native/build.gradle @@ -20,8 +20,8 @@ import org.jetbrains.kotlin.CopySamples import org.jetbrains.kotlin.CopyCommonSources import org.jetbrains.kotlin.PlatformInfo import org.jetbrains.kotlin.KotlinBuildPusher -import org.jetbrains.kotlin.bitcode.CompileToBitcodeExtension import org.jetbrains.kotlin.cpp.CompilationDatabasePlugin +import org.jetbrains.kotlin.cpp.CppUsage import org.jetbrains.kotlin.cpp.GitClangFormatPlugin import org.jetbrains.kotlin.CompareDistributionSignatures import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar @@ -146,7 +146,7 @@ configurations { canBeConsumed = false canBeResolved = true attributes { - attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, CompileToBitcodeExtension.USAGE)) + attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, CppUsage.LLVM_BITCODE)) } } } diff --git a/kotlin-native/common/build.gradle.kts b/kotlin-native/common/build.gradle.kts index 345c9b2c8c9..61af9206b62 100644 --- a/kotlin-native/common/build.gradle.kts +++ b/kotlin-native/common/build.gradle.kts @@ -12,9 +12,15 @@ bitcode { hostTarget { module("files") { headersDirs.from(layout.projectDirectory.dir("src/files/headers")) + sourceSets { + main {} + } } module("env") { headersDirs.from(layout.projectDirectory.dir("src/env/headers")) + sourceSets { + main {} + } } } } diff --git a/kotlin-native/runtime/build.gradle.kts b/kotlin-native/runtime/build.gradle.kts index 68842316a23..44e0be9957e 100644 --- a/kotlin-native/runtime/build.gradle.kts +++ b/kotlin-native/runtime/build.gradle.kts @@ -4,6 +4,7 @@ */ import org.jetbrains.kotlin.* import org.jetbrains.kotlin.bitcode.CompileToBitcodeExtension +import org.jetbrains.kotlin.cpp.CppUsage import org.jetbrains.kotlin.gradle.plugin.konan.tasks.KonanCacheTask import org.jetbrains.kotlin.konan.properties.loadProperties import org.jetbrains.kotlin.konan.properties.saveProperties @@ -38,14 +39,28 @@ val targetList: List by project bitcode { 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")) + sourceSets { + 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")) + } + } + testFixtures {} + test {} } } module("mimalloc") { - val srcRoot = file("src/mimalloc") + sourceSets { + main { + inputFiles.from(srcRoot.dir("c")) + inputFiles.include("**/*.c") + inputFiles.exclude("**/alloc-override*.c", "**/page-queue.c", "**/static.c", "**/bitmap.inc.c") + headersDirs.setFrom(srcRoot.dir("c/include")) + } + } + compiler.set("clang") compilerArgs.set(listOfNotNull( "-std=gnu11", @@ -58,16 +73,11 @@ bitcode { "-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) } + onlyIf { target.supportsMimallocAllocator() } } module("libbacktrace") { - val srcRoot = file("src/libbacktrace") val elfSize = when (target.architecture) { TargetArchitecture.X64, TargetArchitecture.ARM64 -> 64 TargetArchitecture.X86, TargetArchitecture.ARM32, @@ -76,6 +86,29 @@ bitcode { } val useMachO = target.family.isAppleFamily val useElf = target.family in listOf(Family.LINUX, Family.ANDROID) + + sourceSets { + main { + inputFiles.from(srcRoot.dir("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.dir("c/include")) + } + } + compiler.set("clang") compilerArgs.set(listOfNotNull( "-std=gnu11", @@ -92,117 +125,193 @@ bitcode { "-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) } + onlyIf { target.supportsLibBacktrace() } } module("compiler_interface") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } module("launcher") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } module("debug") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } module("std_alloc") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } module("custom_alloc") { headersDirs.from(files("src/main/cpp", "src/mm/cpp", "src/gc/common/cpp", "src/gc/cms/cpp")) + sourceSets { + main {} + test {} + } + compilerArgs.add("-DCUSTOM_ALLOCATOR") + // Directly depends on cms which is only supported with threads. - onlyIf { targetSupportsThreads(target.name) } + onlyIf { target.supportsThreads() } } module("opt_alloc") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } - module("exceptionsSupport", file("src/exceptions_support")) { + module("exceptionsSupport") { + srcRoot.set(layout.projectDirectory.dir("src/exceptions_support")) headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } - module("source_info_core_symbolication", file("src/source_info/core_symbolication")) { + module("source_info_core_symbolication") { + srcRoot.set(layout.projectDirectory.dir("src/source_info/core_symbolication")) headersDirs.from(files("src/main/cpp")) - onlyIf { targetSupportsCoreSymbolication(target.name) } + sourceSets { + main {} + } + + onlyIf { target.supportsCoreSymbolication() } } - module("source_info_libbacktrace", file("src/source_info/libbacktrace")) { + module("source_info_libbacktrace") { + srcRoot.set(layout.projectDirectory.dir("src/source_info/libbacktrace")) headersDirs.from(files("src/main/cpp", "src/libbacktrace/c/include")) - onlyIf { targetSupportsLibBacktrace(target.name) } + sourceSets { + main {} + } + + onlyIf { target.supportsLibBacktrace() } } module("strict") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } module("relaxed") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } - module("profileRuntime", file("src/profile_runtime")) + module("profileRuntime") { + srcRoot.set(layout.projectDirectory.dir("src/profile_runtime")) + sourceSets { + main {} + } + } module("objc") { headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + } } - module("test_support", outputGroup = "test") { - headersDirs.from(files("src/main/cpp"), googletest.headersDirs) - dependsOn("downloadGoogleTest") - } - - module("legacy_memory_manager", file("src/legacymm")) { + module("test_support") { headersDirs.from(files("src/main/cpp")) + sourceSets { + testFixtures { + inputFiles.include("**/*.cpp", "**/*.mm") + } + } } - module("experimental_memory_manager", file("src/mm")) { + module("legacy_memory_manager") { + srcRoot.set(layout.projectDirectory.dir("src/legacymm")) + headersDirs.from(files("src/main/cpp")) + sourceSets { + main {} + testFixtures {} + } + } + + module("experimental_memory_manager") { + srcRoot.set(layout.projectDirectory.dir("src/mm")) headersDirs.from(files("src/gc/common/cpp", "src/main/cpp")) + sourceSets { + main {} + testFixtures {} + test {} + } } - module("common_gc", file("src/gc/common")) { + module("common_gc") { + srcRoot.set(layout.projectDirectory.dir("src/gc/common")) headersDirs.from(files("src/mm/cpp", "src/main/cpp")) + sourceSets { + main {} + test {} + } } - module("noop_gc", file("src/gc/noop")) { + module("noop_gc") { + srcRoot.set(layout.projectDirectory.dir("src/gc/noop")) headersDirs.from(files("src/gc/noop/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp")) + sourceSets { + main {} + testFixtures {} + } } - module("same_thread_ms_gc", file("src/gc/stms")) { + module("same_thread_ms_gc") { + srcRoot.set(layout.projectDirectory.dir("src/gc/stms")) headersDirs.from(files("src/gc/stms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp")) + sourceSets { + main {} + testFixtures {} + test {} + } } - module("concurrent_ms_gc", file("src/gc/cms")) { + module("concurrent_ms_gc") { + srcRoot.set(layout.projectDirectory.dir("src/gc/cms")) headersDirs.from(files("src/gc/cms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp")) + sourceSets { + main {} + testFixtures {} + test {} + } - onlyIf { targetSupportsThreads(target.name) } + onlyIf { target.supportsThreads() } } - module("concurrent_ms_gc_custom", file("src/gc/cms")) { + module("concurrent_ms_gc_custom") { + srcRoot.set(layout.projectDirectory.dir("src/gc/cms")) headersDirs.from(files("src/gc/cms/cpp", "src/gc/common/cpp", "src/mm/cpp", "src/main/cpp", "src/custom_alloc/cpp")) + sourceSets { + main {} + testFixtures {} + test {} + } + compilerArgs.add("-DCUSTOM_ALLOCATOR") - onlyIf { targetSupportsThreads(target.name) } + onlyIf { target.supportsThreads() } } testsGroup("std_alloc_runtime_tests") { @@ -248,7 +357,7 @@ val runtimeBitcode by configurations.creating { isCanBeConsumed = false isCanBeResolved = true attributes { - attribute(Usage.USAGE_ATTRIBUTE, objects.named(CompileToBitcodeExtension.USAGE)) + attribute(CppUsage.USAGE_ATTRIBUTE, objects.named(CppUsage.LLVM_BITCODE)) } }