Add new DSL for configuring K/N library artifact.
This commit is contained in:
committed by
TeamCityServer
parent
17fe4f67e5
commit
cfdd5673ee
+123
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.gradle.targets.native.tasks.artifact
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.presetName
|
||||
|
||||
abstract class KotlinArtifact {
|
||||
internal val modules = mutableSetOf<Any>()
|
||||
fun setModules(vararg project: Any) {
|
||||
modules.clear()
|
||||
modules.addAll(project)
|
||||
}
|
||||
|
||||
fun addModule(project: Any) {
|
||||
modules.add(project)
|
||||
}
|
||||
|
||||
internal abstract fun validate(project: Project, name: String): Boolean
|
||||
internal abstract fun registerAssembleTask(project: Project, name: String)
|
||||
}
|
||||
|
||||
abstract class KotlinNativeArtifact : KotlinArtifact() {
|
||||
var modes: Set<NativeBuildType> = NativeBuildType.DEFAULT_BUILD_TYPES
|
||||
var isStatic: Boolean = false
|
||||
var linkerOptions: List<String> = emptyList()
|
||||
|
||||
internal var kotlinOptionsFn: KotlinCommonToolOptions.() -> Unit = {}
|
||||
fun kotlinOptions(fn: KotlinCommonToolOptions.() -> Unit) {
|
||||
kotlinOptionsFn = fn
|
||||
}
|
||||
|
||||
internal val binaryOptions: MutableMap<String, String> = mutableMapOf()
|
||||
fun binaryOption(name: String, value: String) {
|
||||
binaryOptions[name] = value
|
||||
}
|
||||
|
||||
override fun validate(project: Project, name: String): Boolean {
|
||||
val logger = project.logger
|
||||
if (modules.isEmpty()) {
|
||||
logger.error("Native library '${name}' wasn't configured because it requires at least one module for linking")
|
||||
return false
|
||||
}
|
||||
|
||||
if (modes.isEmpty()) {
|
||||
logger.error("Native library '${name}' wasn't configured because it requires at least one build type in modes")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun Project.registerLibsDependencies(target: KonanTarget, artifactName: String, deps: Set<Any>): String {
|
||||
val librariesConfigurationName = lowerCamelCaseName(target.presetName, artifactName, "linkLibrary")
|
||||
configurations.maybeCreate(librariesConfigurationName).apply {
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
isTransitive = true
|
||||
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.native)
|
||||
attributes.attribute(KotlinNativeTarget.konanTargetAttribute, target.name)
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, KotlinUsages.KOTLIN_API))
|
||||
}
|
||||
deps.forEach { dependencies.add(librariesConfigurationName, it) }
|
||||
return librariesConfigurationName
|
||||
}
|
||||
|
||||
fun Project.registerExportDependencies(target: KonanTarget, artifactName: String, deps: Set<Any>): String {
|
||||
val exportConfigurationName = lowerCamelCaseName(target.presetName, artifactName, "linkExport")
|
||||
configurations.maybeCreate(exportConfigurationName).apply {
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
isTransitive = false
|
||||
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.native)
|
||||
attributes.attribute(KotlinNativeTarget.konanTargetAttribute, target.name)
|
||||
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, KotlinUsages.KOTLIN_API))
|
||||
}
|
||||
deps.forEach { dependencies.add(exportConfigurationName, it) }
|
||||
return exportConfigurationName
|
||||
}
|
||||
}
|
||||
|
||||
open class ArtifactType<T : KotlinArtifact>(internal val create: () -> T)
|
||||
object Library : ArtifactType<KotlinNativeLibrary>({ KotlinNativeLibrary() })
|
||||
object Framework : ArtifactType<KotlinNativeFramework>({ KotlinNativeFramework() })
|
||||
object FatFramework : ArtifactType<KotlinNativeFatFramework>({ KotlinNativeFatFramework() })
|
||||
object XCFramework : ArtifactType<KotlinNativeXCFramework>({ KotlinNativeXCFramework() })
|
||||
|
||||
@RequiresOptIn(
|
||||
message = "This API is experimental. It may be changed in the future.",
|
||||
level = RequiresOptIn.Level.WARNING
|
||||
)
|
||||
@Retention(AnnotationRetention.BINARY)
|
||||
@Target(AnnotationTarget.FUNCTION)
|
||||
annotation class ExperimentalArtifactDsl
|
||||
|
||||
private val SAFE_NAME_PATTERN = """\W""".toRegex()
|
||||
|
||||
@ExperimentalArtifactDsl
|
||||
fun <T : KotlinArtifact> Project.kotlinArtifact(type: ArtifactType<T>, configure: T.() -> Unit) =
|
||||
kotlinArtifact(name.replace(SAFE_NAME_PATTERN, "_"), type, configure)
|
||||
|
||||
@ExperimentalArtifactDsl
|
||||
fun <T : KotlinArtifact> Project.kotlinArtifact(name: String, type: ArtifactType<T>, configure: T.() -> Unit) {
|
||||
val artifact = type.create()
|
||||
artifact.addModule(this)
|
||||
configure(artifact)
|
||||
if (artifact.validate(this, name)) {
|
||||
artifact.registerAssembleTask(this, name)
|
||||
}
|
||||
}
|
||||
+74
@@ -0,0 +1,74 @@
|
||||
/*
|
||||
* Copyright 2010-2021 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.gradle.targets.native.tasks.artifact
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeOutputKind
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
|
||||
import org.jetbrains.kotlin.gradle.tasks.dependsOn
|
||||
import org.jetbrains.kotlin.gradle.tasks.registerTask
|
||||
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.presetName
|
||||
import org.jetbrains.kotlin.konan.util.visibleName
|
||||
|
||||
class KotlinNativeLibrary : KotlinNativeArtifact() {
|
||||
lateinit var target: KonanTarget
|
||||
|
||||
private val kind: NativeOutputKind
|
||||
get() = if (isStatic) NativeOutputKind.STATIC else NativeOutputKind.DYNAMIC
|
||||
|
||||
override fun validate(project: Project, name: String): Boolean {
|
||||
val logger = project.logger
|
||||
if (!super.validate(project, name)) return false
|
||||
if (!this::target.isInitialized) {
|
||||
logger.error("Native library '${name}' wasn't configured because it requires target")
|
||||
return false
|
||||
}
|
||||
if (!kind.availableFor(target)) {
|
||||
logger.error("Native library '${name}' wasn't configured because ${kind.description} is not available for ${target.visibleName}")
|
||||
return false
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
override fun registerAssembleTask(project: Project, name: String) {
|
||||
|
||||
val resultTask = project.registerTask<Task>(
|
||||
lowerCamelCaseName("assemble", name, kind.taskNameClassifier, "Library")
|
||||
) { task ->
|
||||
task.group = BasePlugin.BUILD_GROUP
|
||||
task.description = "Assemble all types of registered '$name' ${kind.description}."
|
||||
task.enabled = target.enabledOnCurrentHost
|
||||
}
|
||||
project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(resultTask)
|
||||
|
||||
val librariesConfigurationName = project.registerLibsDependencies(target, name, modules)
|
||||
val exportConfigurationName = project.registerExportDependencies(target, name, modules)
|
||||
modes.forEach { buildType ->
|
||||
val targetTask = project.registerTask<KotlinNativeLinkArtifactTask>(
|
||||
lowerCamelCaseName("assemble", name, buildType.visibleName, kind.taskNameClassifier, "Library", target.presetName),
|
||||
listOf(target, kind.compilerOutputKind)
|
||||
) { task ->
|
||||
task.description = "Assemble ${kind.description} '$name' for a target '${target.name}'."
|
||||
task.enabled = target.enabledOnCurrentHost
|
||||
task.baseName = name
|
||||
task.optimized = buildType.optimized
|
||||
task.debuggable = buildType.debuggable
|
||||
task.linkerOptions = linkerOptions
|
||||
task.binaryOptions = binaryOptions
|
||||
task.librariesConfiguration = librariesConfigurationName
|
||||
task.exportLibrariesConfiguration = exportConfigurationName
|
||||
task.kotlinOptions(kotlinOptionsFn)
|
||||
}
|
||||
resultTask.dependsOn(targetTask)
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user