diff --git a/kotlin-native/backend.native/build.gradle b/kotlin-native/backend.native/build.gradle index ff611e0ea49..8dd7d47cc9e 100644 --- a/kotlin-native/backend.native/build.gradle +++ b/kotlin-native/backend.native/build.gradle @@ -1,7 +1,8 @@ import org.jetbrains.kotlin.CopyCommonSources -import org.jetbrains.kotlin.konan.target.HostManager +import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.* 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. @@ -40,6 +41,32 @@ compileCli_bcKotlin { kotlinOptions.freeCompilerArgs += ['-Xskip-prerelease-check'] } +configurations { + commonFilesBitcode { + 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") + } + } + 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") + } + } +} + +dependencies { + commonFilesBitcode project(":kotlin-native:common") + commonEnvBitcode project(":kotlin-native:common") +} + kotlinNativeInterop { llvm { @@ -63,8 +90,9 @@ kotlinNativeInterop { files { linker 'clang++' - linkOutputs ":kotlin-native:common:${hostName}Files" + link configurations.commonFilesBitcode + // TODO: These should come from some sort of commonFilesApi configuration headers fileTree('../common/src/files/headers') { include '**/*.h' include '**/*.hpp' @@ -76,8 +104,9 @@ kotlinNativeInterop { env { linker 'clang++' - linkOutputs ":kotlin-native:common:${hostName}Env" + link configurations.commonEnvBitcode + // TODO: These should come from some sort of commonEnvApi configuration headers fileTree('../common/src/env/headers') { include '**/*.h' include '**/*.hpp' @@ -155,7 +184,7 @@ jar { sourceSets.envInteropStubs.output, sourceSets.llvmInteropStubs.output - dependsOn ':kotlin-native:runtime:hostRuntime', 'external_jars' + dependsOn 'external_jars' } def externalJars = ['compiler', 'stdlib', 'reflect', 'script_runtime'] 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 e7f8596fcbc..0710e917970 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 @@ -9,6 +9,8 @@ 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.attributes.Usage import org.gradle.api.provider.ListProperty import org.gradle.api.provider.Property import org.gradle.api.services.BuildService @@ -51,21 +53,6 @@ private val SanitizerKind?.description private abstract class RunGTestSemaphore : BuildService private abstract class CompileTestsSemaphore : BuildService -/** - * A plugin creating extensions to compile - */ -open class CompileToBitcodePlugin : Plugin { - override fun apply(target: Project) { - target.apply() - target.apply() - target.extensions.create(EXTENSION_NAME, target) - } - - companion object { - const val EXTENSION_NAME = "bitcode" - } -} - open class CompileToBitcodeExtension @Inject constructor(val project: Project) : TargetDomainObjectContainer(project) { init { this.factory = { target -> @@ -73,6 +60,15 @@ 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)) + } + } + // 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) }, @@ -89,16 +85,6 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : provider { (rootProject.project(":kotlin-native").property("targetList") as? List<*>)?.filterIsInstance() ?: emptyList() } // TODO: Can we make it better? } - private val allMainModulesTasks by lazy { - val name = project.name.capitalized - targetList.get().associateBy(keySelector = { it }, valueTransform = { - project.tasks.register("${it}$name") { - description = "Build all main modules of $name for $it" - group = BUILD_TASK_GROUP - } - }) - } - private val allTestsTasks by lazy { val name = project.name.capitalized targetList.get().associateBy(keySelector = { it }, valueTransform = { @@ -147,6 +133,12 @@ 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 { @@ -169,9 +161,9 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : 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).apply { + 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") }) @@ -190,10 +182,30 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : dependsOn(":kotlin-native:dependencies:update") configurationBlock() } - addToCompdb(task) - if (outputGroup == "main" && sanitizer == null) { - allMainModulesTask.configure { - dependsOn(taskName) + 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) + } + } + } } } } @@ -317,5 +329,39 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) : const val BUILD_TASK_GROUP = LifecycleBasePlugin.BUILD_GROUP 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) } } + +/** + * Compiling C and C++ modules into LLVM bitcode. + * + * 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`. + * + * 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 `*Elements` configuration has variants with [TargetWithSanitizer.TARGET_ATTRIBUTE] values. + * + * @see CompileToBitcodeExtension extension that this plugin creates. + */ +open class CompileToBitcodePlugin : Plugin { + override fun apply(project: Project) { + 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/konan/target/TargetWithSanitizer.kt b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/konan/target/TargetWithSanitizer.kt index a0084d3563e..533e8992926 100644 --- a/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/konan/target/TargetWithSanitizer.kt +++ b/kotlin-native/build-tools/src/main/kotlin/org/jetbrains/kotlin/konan/target/TargetWithSanitizer.kt @@ -32,8 +32,11 @@ class TargetWithSanitizer( } companion object { - @JvmStatic + @JvmField val TARGET_ATTRIBUTE = Attribute.of("org.jetbrains.kotlin.target", TargetWithSanitizer::class.java) + + @JvmField + val host = TargetWithSanitizer(HostManager.host, null) } } diff --git a/kotlin-native/build.gradle b/kotlin-native/build.gradle index 6f86ddf1199..fdf5e483ab2 100644 --- a/kotlin-native/build.gradle +++ b/kotlin-native/build.gradle @@ -20,6 +20,7 @@ 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.GitClangFormatPlugin import org.jetbrains.kotlin.CompareDistributionSignatures @@ -140,6 +141,14 @@ configurations { ftpAntTask distPack commonSources + + runtimeBitcode { + canBeConsumed = false + canBeResolved = true + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(Usage, CompileToBitcodeExtension.USAGE)) + } + } } apply plugin: CompilationDatabasePlugin @@ -161,6 +170,7 @@ dependencies { commonSources project(path: ':kotlin-test:kotlin-test-annotations-common', configuration: 'sources') compilationDatabase project(":kotlin-native:common") compilationDatabase project(":kotlin-native:runtime") + runtimeBitcode project(":kotlin-native:runtime") } apply plugin: GitClangFormatPlugin @@ -438,11 +448,15 @@ targetList.each { target -> } task("${target}CrossDistBitcodeCopy", type: Copy) { - dependsOn ":kotlin-native:runtime:${target}Runtime" + def bitcodeFiles = configurations.runtimeBitcode.incoming.artifactView { + attributes { + attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, new TargetWithSanitizer(platformManager.targetByName(target), null)) + } + }.files destinationDir project.file("$distDir/konan/targets/") - from(project(':kotlin-native:runtime').file("build/bitcode/main/$target")) { + from(bitcodeFiles) { include("*.bc") exclude("runtime.bc") into("$target/native") @@ -450,7 +464,6 @@ targetList.each { target -> } task("${target}CrossDistRuntime", type: Copy) { - dependsOn ":kotlin-native:runtime:${target}Runtime" dependsOn ":kotlin-native:${target}CrossDistStdlib" dependsOn "${target}CrossDistBitcodeCopy" diff --git a/kotlin-native/runtime/build.gradle.kts b/kotlin-native/runtime/build.gradle.kts index 7ef6a5507d7..68842316a23 100644 --- a/kotlin-native/runtime/build.gradle.kts +++ b/kotlin-native/runtime/build.gradle.kts @@ -244,6 +244,33 @@ bitcode { } } +val runtimeBitcode by configurations.creating { + isCanBeConsumed = false + isCanBeResolved = true + attributes { + attribute(Usage.USAGE_ATTRIBUTE, objects.named(CompileToBitcodeExtension.USAGE)) + } +} + +dependencies { + runtimeBitcode(project(":kotlin-native:runtime")) +} + +targetList.forEach { targetName -> + // TODO: replace with a more convenient user-facing task that can build for a specific target. + // like compileToBitcode with optional argument --target. + tasks.register("${targetName}Runtime") { + description = "Build all main runtime modules for $targetName" + group = CompileToBitcodeExtension.BUILD_TASK_GROUP + val dependencies = runtimeBitcode.incoming.artifactView { + attributes { + attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, project.platformManager.targetByName(targetName).withSanitizer()) + } + }.files + dependsOn(dependencies) + } +} + val hostRuntime by tasks.registering { description = "Build all main runtime modules for host" group = CompileToBitcodeExtension.BUILD_TASK_GROUP @@ -367,7 +394,12 @@ targetList.forEach { targetName -> destinationDir = project.buildDir.resolve("${targetName}Stdlib") from(project.buildDir.resolve("stdlib/${hostName}/stdlib")) - from(project.buildDir.resolve("bitcode/main/$targetName")) { + val runtimeFiles = runtimeBitcode.incoming.artifactView { + attributes { + attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, project.platformManager.targetByName(targetName).withSanitizer()) + } + }.files + from(runtimeFiles) { include("runtime.bc", "compiler_interface.bc") into("default/targets/$targetName/native") }