[K/N] Use configurations for interproject compdb deps ^KT-53776

Merge-request: KT-MR-7158
Merged-by: Alexander Shabalin <Alexander.Shabalin@jetbrains.com>
This commit is contained in:
Alexander Shabalin
2022-12-09 09:42:08 +00:00
committed by Space Team
parent 76997edebe
commit 01cabefea7
9 changed files with 207 additions and 148 deletions
@@ -22,10 +22,9 @@ import org.gradle.workers.WorkParameters
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.ExecClang
import org.jetbrains.kotlin.execLlvmUtility
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.konan.target.SanitizerKind
import org.jetbrains.kotlin.utils.Maybe
import org.jetbrains.kotlin.konan.target.TargetWithSanitizer
import java.io.File
import javax.inject.Inject
@@ -83,21 +82,23 @@ private abstract class CompileToBitcodeJob : WorkAction<CompileToBitcodeJob.Para
*
* Compiles [inputFiles] into [outputFile] with [compiler] and `llvm-link`.
*
* @property target target for which to compile
* @see CompileToBitcodePlugin
*/
abstract class CompileToBitcode @Inject constructor(
@Input val target: KonanTarget,
private val _sanitizer: Maybe<SanitizerKind>,
private val _target: TargetWithSanitizer,
) : DefaultTask() {
/**
* Target for which to compile
*/
@get:Input
val target by _target::target
/**
* Compile with sanitizer enabled.
* Optional [sanitizer][SanitizerKind] for [target].
*/
@get:Input
@get:Optional
val sanitizer
get() = _sanitizer.orNull
val sanitizer by _target::sanitizer
/**
* Final output file.
@@ -17,20 +17,12 @@ 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.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.*
import org.jetbrains.kotlin.testing.native.GoogleTestExtension
import org.jetbrains.kotlin.utils.Maybe
import org.jetbrains.kotlin.utils.asMaybe
import org.jetbrains.kotlin.utils.capitalized
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}"
@@ -76,8 +68,8 @@ open class CompileToBitcodePlugin : Plugin<Project> {
open class CompileToBitcodeExtension @Inject constructor(val project: Project) : TargetDomainObjectContainer<CompileToBitcodeExtension.Target>(project) {
init {
this.factory = { target, sanitizer ->
project.objects.newInstance<Target>(this, target, sanitizer.asMaybe)
this.factory = { target ->
project.objects.newInstance<Target>(this, target)
}
}
@@ -118,11 +110,10 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
}
abstract class TestsGroup @Inject constructor(
val target: KonanTarget,
private val _sanitizer: Maybe<SanitizerKind>,
private val _target: TargetWithSanitizer,
) {
val sanitizer
get() = _sanitizer.orNull
val target by _target::target
val sanitizer by _target::sanitizer
abstract val testedModules: ListProperty<String>
abstract val testSupportModules: ListProperty<String>
abstract val testFrameworkModules: ListProperty<String>
@@ -131,10 +122,10 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
abstract class Target @Inject constructor(
private val owner: CompileToBitcodeExtension,
val target: KonanTarget,
_sanitizer: Maybe<SanitizerKind>,
private val _target: TargetWithSanitizer,
) {
val sanitizer = _sanitizer.orNull
val target by _target::target
val sanitizer by _target::sanitizer
private val project by owner::project
@@ -157,7 +148,7 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
}
private fun addToCompdb(compileTask: CompileToBitcode) {
compilationDatabase.target(target, sanitizer) {
compilationDatabase.target(_target) {
entry {
val args = listOf(execClang.resolveExecutable(compileTask.compiler.get())) + compileTask.compilerFlags.get() + execClang.clangArgsForCppRuntime(target.name)
directory.set(compileTask.compilerWorkingDirectory)
@@ -166,6 +157,13 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
// 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)
}
}
}
@@ -173,7 +171,7 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
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 {
val task = project.tasks.create(taskName, CompileToBitcode::class.java, _target).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") })
@@ -204,7 +202,7 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
testTaskName: String,
action: Action<in TestsGroup>,
) {
val testsGroup = project.objects.newInstance(TestsGroup::class.java, target, sanitizer.asMaybe).apply {
val testsGroup = project.objects.newInstance(TestsGroup::class.java, _target).apply {
testFrameworkModules.convention(listOf("googletest", "googlemock"))
testLauncherModule.convention("test_support")
action.execute(this)
@@ -219,7 +217,7 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
val testedModulesTestTasks = testedModulesMainTasks.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 {
?: 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") })
@@ -247,7 +245,7 @@ open class CompileToBitcodeExtension @Inject constructor(val project: Project) :
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, it.target, it.sanitizer.asMaybe).apply {
?: 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") })
@@ -8,21 +8,16 @@ package org.jetbrains.kotlin.cpp
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
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
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.SanitizerKind
import org.gradle.kotlin.dsl.*
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 org.jetbrains.kotlin.konan.target.TargetWithSanitizer
import org.jetbrains.kotlin.utils.capitalized
import javax.inject.Inject
/**
@@ -30,25 +25,37 @@ import javax.inject.Inject
*
* Allows generating compilation databases for different targets. For example:
* ```
* dependencies {
* compilationDatabase(project(":some:other:project"))
* }
*
* compilationDatabase {
* target(someTarget1) {
* entry { ... }
* }
* allTargets {
* mergeFrom(provider { project("subproject") })
* mergeFrom(compilationDatabase)
* }
* }
* ```
* Adds an entry for target `someTarget1`, and for each known target merges in databases generated
* by this plugin in `subproject`.
* Adds an entry for target `someTarget1`, and for each known target merges in databases from `:some:other:project`.
* The task that generates the database can be found via `compilationDatabase.target(someTarget1).task`.
*
* @see CompilationDatabasePlugin gradle plugin that creates this extension.
*/
abstract class CompilationDatabaseExtension @Inject constructor(private val project: Project) : TargetDomainObjectContainer<CompilationDatabaseExtension.Target>(project) {
init {
this.factory = { target, sanitizer ->
project.objects.newInstance<Target>(project, target, sanitizer.asMaybe)
this.factory = { target ->
project.objects.newInstance<Target>(this, target)
}
}
private val outgoingConfiguration = project.configurations.create("generateCompilationDatabase") {
description = "Generate Compilation Database"
isCanBeConsumed = true
isCanBeResolved = false
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, USAGE))
}
}
@@ -61,10 +68,10 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
* @property sanitizer optional sanitizer for [target].
*/
abstract class Entry @Inject constructor(
val target: KonanTarget,
_sanitizer: Maybe<SanitizerKind>,
private val _target: TargetWithSanitizer,
) {
val sanitizer = _sanitizer.orNull
val target by _target::target
val sanitizer by _target::sanitizer
/**
* **directory** from the [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html#format).
@@ -101,31 +108,19 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
* Configure compilation database generation for [target].
*
* [entry] to add new entries.
* [mergeFrom] to merge databases from other projects with [CompilationDatabasePlugin]s.
* [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<SanitizerKind>,
private val owner: CompilationDatabaseExtension,
private val _target: TargetWithSanitizer,
) {
val sanitizer = _sanitizer.orNull
val target by _target::target
val sanitizer by _target::sanitizer
protected abstract val mergeFrom: ListProperty<GenerateCompilationDatabase>
/**
* 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<Project>) {
mergeFrom.add(from.flatMap { project ->
project.extensions.getByType<CompilationDatabaseExtension>().target(target, sanitizer).task
})
}
private val project by owner::project
protected abstract val entries: ListProperty<GenerateCompilationDatabase.Entry>
@@ -136,7 +131,7 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
*/
fun entry(action: Action<in Entry>) {
entries.add(project.provider {
val instance = project.objects.newInstance<Entry>(target, sanitizer.asMaybe).apply {
val instance = project.objects.newInstance<Entry>(_target).apply {
action.execute(this)
}
project.objects.newInstance<GenerateCompilationDatabase.Entry>().apply {
@@ -148,21 +143,56 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
})
}
protected abstract val mergeFrom: ListProperty<Configuration>
/**
* Merge compilation database entries from given [configuration].
*
* @param configuration provider of additional compilation database entries
*/
fun mergeFrom(configuration: Configuration) {
mergeFrom.add(configuration)
}
/**
* Gradle task that generates compilation database for [target] with optional [sanitizer].
*/
val task = project.tasks.register<GenerateCompilationDatabase>("${target}${sanitizer.targetSuffix}CompilationDatabase") {
description = "Generate compilation database for $target${sanitizer.targetSuffix}"
val task = project.tasks.register<GenerateCompilationDatabase>("compilationDatabase${_target.name.capitalized}") {
description = "Generate compilation database for $_target"
group = TASK_GROUP
mergeFiles.from(mergeFrom)
mergeFiles.from(mergeFrom.map { configurations ->
configurations.map {
it.incoming.artifactView {
attributes {
attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, _target)
}
}.files
}
})
entries.set(this@Target.entries)
outputFile.set(project.layout.buildDirectory.file("${target}${sanitizer.targetSuffix}/compile_commands.json"))
outputFile.set(project.layout.buildDirectory.file("$_target/compile_commands.json"))
}
init {
owner.outgoingConfiguration.outgoing {
variants {
create("$_target") {
attributes {
attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, _target)
}
artifact(task)
}
}
}
}
}
companion object {
@JvmStatic
val TASK_GROUP = "development support"
@JvmStatic
val USAGE = "compilationDatabase"
}
}
@@ -170,11 +200,23 @@ abstract class CompilationDatabaseExtension @Inject constructor(private val proj
* Generating [JSON Compilation Database](https://clang.llvm.org/docs/JSONCompilationDatabase.html).
*
* Creates [CompilationDatabaseExtension] extension named `compilationDatabase`.
* Creates [Configuration][org.gradle.api.artifacts.Configuration] named `compilationDatabase`.
*
* @see CompilationDatabaseExtension extension that this plugin creates.
*/
open class CompilationDatabasePlugin : Plugin<Project> {
override fun apply(project: Project) {
project.extensions.create<CompilationDatabaseExtension>("compilationDatabase", project)
project.dependencies.attributesSchema {
attribute(TargetWithSanitizer.TARGET_ATTRIBUTE)
}
project.configurations.create("compilationDatabase") {
description = "Compilation Database"
isCanBeConsumed = false
isCanBeResolved = true
attributes {
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(CompilationDatabaseExtension.USAGE))
}
}
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.cpp
import com.google.gson.JsonSyntaxException
import com.google.gson.annotations.Expose
import org.gradle.api.DefaultTask
import org.gradle.api.file.ConfigurableFileCollection
@@ -126,7 +127,11 @@ abstract class GenerateCompilationDatabase : DefaultTask() {
val serialized = mutableListOf<SerializedEntry>()
mergeFiles.files.forEach { file ->
FileReader(file).use {
serialized.addAll(gson.fromJson(it, Array<SerializedEntry>::class.java))
try {
serialized.addAll(gson.fromJson(it, Array<SerializedEntry>::class.java))
} catch (e: JsonSyntaxException) {
throw IllegalStateException("Failed to parse $file as compilation database", e)
}
}
}
entries.get().forEach {
@@ -16,7 +16,7 @@ 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
* 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`.
@@ -31,15 +31,12 @@ import org.gradle.kotlin.dsl.getByType
* target(someTarget) {
* // This is a lambda inside of a T scope. Called for `someTarget` without any sanitizer.
* }
* target(someTarget, someSanitizer) {
* target(someTarget.withSanitizer(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.
@@ -57,36 +54,32 @@ open class TargetDomainObjectContainer<T : Any> constructor(
/**
* How to create [T]. Must be set before using the rest of API.
*/
lateinit var factory: (KonanTarget, SanitizerKind?) -> T
lateinit var factory: (TargetWithSanitizer) -> T
private val targets: MutableMap<Pair<KonanTarget, SanitizerKind?>, T> = mutableMapOf()
private val targets: MutableMap<TargetWithSanitizer, T> = mutableMapOf()
/**
* Create or update configuration [T] for [target] with optional [sanitizer] and apply [action] to it.
* Create or update configuration [T] for [target] and apply [action] to it.
*
* @param target target of the configuration
* @param sanitizer optional sanitizer for [target]
* @param action action to apply to the configuration
* @return resulting configuration
*/
fun target(target: KonanTarget, sanitizer: SanitizerKind? = null, action: Action<in T>): T {
val key = target to sanitizer
val element = targets.getOrPut(key) { factory(target, sanitizer) }
fun target(target: TargetWithSanitizer, action: Action<in T>): T {
val element = targets.getOrPut(target) { factory(target) }
action.execute(element)
return element
}
/**
* Get configuration [T] for [target] with optional [sanitizer].
* Get configuration [T] for [target].
*
* @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
* @throws UnknownDomainObjectException if configuration for [target] 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")
fun target(target: TargetWithSanitizer): T {
return targets[target] ?: throw UnknownDomainObjectException("Configuration for $target does not exists")
}
/**
@@ -95,13 +88,8 @@ open class TargetDomainObjectContainer<T : Any> constructor(
* @param action action to apply to the configuration
* @return list of configurations
*/
fun allTargets(action: Action<in T>): List<T> {
return platformManager.enabled.flatMap { target ->
val sanitizers = target.supportedSanitizers() + listOf(null)
sanitizers.map { sanitizer ->
this.target(target, sanitizer, action)
}
}
fun allTargets(action: Action<in T>): List<T> = platformManager.allTargetsWithSanitizers.map {
this.target(it, action)
}
/**
@@ -114,33 +102,21 @@ open class TargetDomainObjectContainer<T : Any> constructor(
}
/**
* Create or update configuration [T] for [host target][HostManager.host] with optional [sanitizer] and apply [action] to it.
* Create or update configuration [T] for [host target][HostManager.host] and apply [action] to it.
*
* @param sanitizer optional sanitizer for [host target][HostManager.host]
* @param action action to apply to the configuration
* @return resulting configuration
*/
fun hostTarget(sanitizer: SanitizerKind? = null, action: Action<in T>): T {
return target(HostManager.host, sanitizer, action)
fun hostTarget(action: Action<in T>): T {
return target(HostManager.host.withSanitizer(), 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.
* Get configuration [T] for [host target][HostManager.host].
*
* @return resulting configuration
* @throws UnknownDomainObjectException if configuration for [host target][HostManager.host] without sanitizer does not exist
* @throws UnknownDomainObjectException if configuration for [host target][HostManager.host] does not exist
*/
val hostTarget: T
get() = hostTarget()
get() = target(HostManager.host.withSanitizer())
}
@@ -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.konan.target
import org.gradle.api.Named
import org.gradle.api.attributes.Attribute
import java.io.Serializable
/**
* [Target][KonanTarget] with optional [sanitizer][SanitizerKind].
*
* Can be used as a gradle attribute: `attribute(TargetWithSanitizer.TARGET_ATTRIBUTE, target.withSanitizer())`
*/
class TargetWithSanitizer(
val target: KonanTarget,
val sanitizer: SanitizerKind?,
) : Named, Serializable {
override fun getName(): String = "$target${sanitizer.targetSuffix}"
override fun toString(): String = name
override fun hashCode(): Int {
return name.hashCode()
}
override fun equals(other: Any?): Boolean {
val otherTarget = other as? TargetWithSanitizer ?: return false
return name == otherTarget.name
}
companion object {
@JvmStatic
val TARGET_ATTRIBUTE = Attribute.of("org.jetbrains.kotlin.target", TargetWithSanitizer::class.java)
}
}
/**
* Construct [TargetWithSanitizer] from [target][KonanTarget] and optional [sanitizer][SanitizerKind].
*/
fun KonanTarget.withSanitizer(sanitizer: SanitizerKind? = null) = TargetWithSanitizer(this, sanitizer)
/**
* All known targets with their sanitizers.
*/
val PlatformManager.allTargetsWithSanitizers
get() = this.enabled.flatMap { target ->
listOf(target.withSanitizer()) + target.supportedSanitizers().map {
target.withSanitizer(it)
}
}
@@ -1,23 +0,0 @@
/*
* 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.utils
/**
* Wrapper over [T]?.
*
* Useful for some generalized functions that you want to pass [T]? into, but they forbid nullable types.
* For example, [ObjectFactory.newInstance][org.gradle.api.model.ObjectFactory.newInstance] cannot be used
* to construct a type that has [T]? as a constructor argument.
*
* @property orNull get underlying value.
*/
data class Maybe<T>(val orNull: T?)
/**
* Construct [Maybe]<[T]> from [T]?.
*/
inline val <T> T?.asMaybe
get() = Maybe(this)
@@ -0,0 +1,10 @@
/*
* 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.utils
@OptIn(ExperimentalStdlibApi::class)
val String.capitalized: String
get() = replaceFirstChar { it.uppercase() }
+6 -9
View File
@@ -142,6 +142,8 @@ configurations {
commonSources
}
apply plugin: CompilationDatabasePlugin
dependencies {
ftpAntTask 'org.apache.ant:ant-commons-net:1.9.9'
distPack project(':kotlin-native:Interop:Runtime')
@@ -157,9 +159,10 @@ dependencies {
commonSources project(path: ':kotlin-stdlib-common', configuration: 'sources')
commonSources project(path: ':kotlin-test:kotlin-test-common', configuration: 'sources')
commonSources project(path: ':kotlin-test:kotlin-test-annotations-common', configuration: 'sources')
compilationDatabase project(":kotlin-native:common")
compilationDatabase project(":kotlin-native:runtime")
}
apply plugin: CompilationDatabasePlugin
apply plugin: GitClangFormatPlugin
apply plugin: 'maven-publish'
apply plugin: BasePlugin
@@ -725,13 +728,7 @@ task pusher(type: KotlinBuildPusher){
compilationDatabase {
allTargets {
mergeFrom(provider { project("common") })
mergeFrom(provider { project("runtime") })
// TODO: Reconsider this
task.configure {
dependsOn(":kotlin-native:runtime:downloadGoogleTest")
}
mergeFrom(configurations.compilationDatabase)
}
}
@@ -886,4 +883,4 @@ publishing {
)
}
}
}
}