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