[gradle][plugin][konan] deployment of kotlin-native artifacts via maven machinery

This commit is contained in:
Vasily Levchenko
2018-02-15 21:11:48 +03:00
committed by Vasily Levchenko
parent ddcbe68a5b
commit 5185a17c24
6 changed files with 122 additions and 12 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.gradle.plugin package org.jetbrains.kotlin.gradle.plugin
import groovy.lang.Closure
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.internal.project.ProjectInternal
@@ -68,6 +69,8 @@ abstract class KonanCompileConfig<T: KonanCompileTask>(name: String,
override fun entryPoint(entryPoint: String) = forEach { it.entryPoint(entryPoint) } override fun entryPoint(entryPoint: String) = forEach { it.entryPoint(entryPoint) }
override fun measureTime(flag: Boolean) = forEach { it.measureTime(flag) } override fun measureTime(flag: Boolean) = forEach { it.measureTime(flag) }
override fun dependencies(closure: Closure<Unit>) = forEach { it.dependencies(closure) }
} }
open class KonanProgram(name: String, open class KonanProgram(name: String,
@@ -84,5 +84,6 @@ open class KonanInteropLibrary(name: String,
override fun link(vararg files: Any) = forEach { it.link(*files) } override fun link(vararg files: Any) = forEach { it.link(*files) }
override fun link(files: FileCollection) = forEach { it.link(files) } override fun link(files: FileCollection) = forEach { it.link(files) }
override fun dependencies(closure: Closure<Unit>) = forEach { it.dependencies(closure) }
} }
@@ -17,9 +17,23 @@
package org.jetbrains.kotlin.gradle.plugin package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.* import org.gradle.api.*
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.attributes.Usage
import org.gradle.api.component.ComponentWithVariants
import org.gradle.api.component.SoftwareComponent
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.internal.FeaturePreviews
import org.gradle.api.internal.component.SoftwareComponentInternal
import org.gradle.api.internal.component.UsageContext
import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.plugins.AppliedPlugin
import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.BasePlugin
import org.gradle.api.publish.PublishingExtension
import org.gradle.api.publish.internal.PublicationInternal
import org.gradle.api.publish.maven.MavenPublication
import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal
import org.gradle.language.cpp.internal.NativeVariant
import org.gradle.language.nativeplatform.internal.Names
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.plugin.KonanPlugin.Companion.COMPILE_ALL_TASK_NAME import org.jetbrains.kotlin.gradle.plugin.KonanPlugin.Companion.COMPILE_ALL_TASK_NAME
import org.jetbrains.kotlin.gradle.plugin.tasks.* import org.jetbrains.kotlin.gradle.plugin.tasks.*
@@ -242,6 +256,18 @@ open class KonanExtension {
var jvmArgs = mutableListOf<String>() var jvmArgs = mutableListOf<String>()
} }
open class KonanSoftwareComponent(val project: ProjectInternal?): SoftwareComponentInternal, ComponentWithVariants {
private val usages = mutableSetOf<UsageContext>()
override fun getUsages(): MutableSet<out UsageContext> = usages
private val variants = mutableSetOf<SoftwareComponent>()
override fun getName() = "main"
override fun getVariants(): Set<out SoftwareComponent> = variants
fun addVariant(component: SoftwareComponent) = variants.add(component)
}
class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderRegistry) class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderRegistry)
: Plugin<ProjectInternal> { : Plugin<ProjectInternal> {
@@ -259,6 +285,7 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
internal const val KONAN_DOWNLOAD_TASK_NAME = "checkKonanCompiler" internal const val KONAN_DOWNLOAD_TASK_NAME = "checkKonanCompiler"
internal const val KONAN_GENERATE_CMAKE_TASK_NAME = "generateCMake" internal const val KONAN_GENERATE_CMAKE_TASK_NAME = "generateCMake"
internal const val COMPILE_ALL_TASK_NAME = "compileKonan" internal const val COMPILE_ALL_TASK_NAME = "compileKonan"
internal const val KONAN_MAIN_VARIANT = "konan_main_variant"
internal const val KONAN_EXTENSION_NAME = "konan" internal const val KONAN_EXTENSION_NAME = "konan"
@@ -272,15 +299,20 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
project.delete(it.artifact) project.delete(it.artifact)
} }
override fun apply(project: ProjectInternal?) { override fun apply(project: ProjectInternal?) {
if (project == null) { return } if (project == null) {
return
}
registry.register(KonanToolingModelBuilder) registry.register(KonanToolingModelBuilder)
project.plugins.apply("base") project.plugins.apply("base")
// Create necessary tasks and extensions. // Create necessary tasks and extensions.
project.tasks.create(KONAN_DOWNLOAD_TASK_NAME, KonanCompilerDownloadTask::class.java) project.tasks.create(KONAN_DOWNLOAD_TASK_NAME, KonanCompilerDownloadTask::class.java)
project.tasks.create(KONAN_GENERATE_CMAKE_TASK_NAME, KonanGenerateCMakeTask::class.java) project.tasks.create(KONAN_GENERATE_CMAKE_TASK_NAME, KonanGenerateCMakeTask::class.java)
project.extensions.create(KONAN_EXTENSION_NAME, KonanExtension::class.java) project.extensions.create(KONAN_EXTENSION_NAME, KonanExtension::class.java)
project.extensions.create(KonanArtifactContainer::class.java, ARTIFACTS_CONTAINER_NAME, KonanArtifactContainer::class.java, project) val mainVariant = project.extensions.create(ComponentWithVariants::class.java, KONAN_MAIN_VARIANT, KonanSoftwareComponent::class.java, project)
val container = project.extensions.create(KonanArtifactContainer::class.java, ARTIFACTS_CONTAINER_NAME, KonanArtifactContainer::class.java, project)
// Set additional project properties like konan.home, konan.build.targets etc. // Set additional project properties like konan.home, konan.build.targets etc.
if (!project.hasProperty(ProjectProperty.KONAN_HOME)) { if (!project.hasProperty(ProjectProperty.KONAN_HOME)) {
@@ -306,7 +338,7 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
doLast { doLast {
for (task in project.tasks for (task in project.tasks
.withType(KonanCompileProgramTask::class.java) .withType(KonanCompileProgramTask::class.java)
.matching { !it.isCrossCompile}) { .matching { !it.isCrossCompile }) {
project.exec { project.exec {
with(it) { with(it) {
commandLine(task.artifact.canonicalPath) commandLine(task.artifact.canonicalPath)
@@ -318,8 +350,38 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
} }
} }
} }
//project.gradle.experimentalFeatures.enable()
project.gradle.services.get(FeaturePreviews::class.java).enableFeature(FeaturePreviews.Feature.GRADLE_METADATA)
// Enable multiplatform support // Enable multiplatform support
project.pluginManager.apply(KotlinNativePlatformPlugin::class.java) project.pluginManager.apply(KotlinNativePlatformPlugin::class.java)
project.afterEvaluate {
val konanSoftwareComponent = mainVariant as KonanSoftwareComponent
project.pluginManager.withPlugin("maven-publish") {
container.all {
val buildingConfig = it
val artifactId = buildingConfig.name
project.extensions.configure(PublishingExtension::class.java) {
val publishing = it
it.publications.create(artifactId, MavenPublication::class.java) {
it.artifactId = artifactId
it.groupId = project.group.toString()
it.from(konanSoftwareComponent)
(it as MavenPublicationInternal).publishWithOriginalFileName()
}
for (v in konanSoftwareComponent.variants) {
// TODO: with gradle 4.7 don't forget to change to SoftwareComponentsWithCoordinates
val name = "${v.name}/$artifactId"
publishing.publications.create(name, MavenPublication::class.java) {
it.artifactId = "${artifactId}-${v.name}"
it.groupId = project.group.toString()
it.version = project.version.toString()
it.from(v)
(it as MavenPublicationInternal).publishWithOriginalFileName()
}
}
}
}
}
}
} }
} }
@@ -31,6 +31,7 @@ interface KonanArtifactWithLibrariesSpec: KonanArtifactSpec {
fun libraries(configure: KonanLibrariesSpec.() -> Unit) fun libraries(configure: KonanLibrariesSpec.() -> Unit)
fun noDefaultLibs(flag: Boolean) fun noDefaultLibs(flag: Boolean)
fun dependencies(closure: Closure<Unit>)
} }
interface KonanBuildingSpec: KonanArtifactWithLibrariesSpec { interface KonanBuildingSpec: KonanArtifactWithLibrariesSpec {
@@ -20,18 +20,21 @@ import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.DefaultTask import org.gradle.api.DefaultTask
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.tasks.Input import org.gradle.api.artifacts.Configuration
import org.gradle.api.tasks.Internal import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.tasks.Nested import org.gradle.api.attributes.Attribute
import org.gradle.api.tasks.OutputFile import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.*
import org.gradle.language.cpp.CppBinary
import org.gradle.language.cpp.internal.NativeVariant
import org.gradle.language.nativeplatform.internal.Names
import org.gradle.nativeplatform.Linkage
import org.gradle.util.ConfigureUtil import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.KonanArtifactSpec import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KonanArtifactWithLibrariesSpec
import org.jetbrains.kotlin.gradle.plugin.KonanLibrariesSpec
import org.jetbrains.kotlin.gradle.plugin.konanTargets
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File import java.io.File
import java.util.*
internal val Project.host internal val Project.host
get() = HostManager.host.visibleName get() = HostManager.host.visibleName
@@ -63,6 +66,8 @@ abstract class KonanArtifactTask: KonanTargetableTask(), KonanArtifactSpec {
@Internal lateinit var destinationDir: File @Internal lateinit var destinationDir: File
@Internal lateinit var artifactName: String @Internal lateinit var artifactName: String
@Internal lateinit var platformConfiguration: Configuration
@Internal lateinit var configuration: Configuration
protected val artifactFullName: String protected val artifactFullName: String
@Internal get() = "$artifactPrefix$artifactName$artifactSuffix" @Internal get() = "$artifactPrefix$artifactName$artifactSuffix"
@@ -80,8 +85,39 @@ abstract class KonanArtifactTask: KonanTargetableTask(), KonanArtifactSpec {
super.init(target) super.init(target)
this.destinationDir = destinationDir this.destinationDir = destinationDir
this.artifactName = artifactName this.artifactName = artifactName
configuration = project.configurations.maybeCreate("artifact$artifactName")
platformConfiguration = project.configurations.create("artifact${artifactName}_${target.name}")
platformConfiguration.extendsFrom(configuration)
platformConfiguration.attributes{
it.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.NATIVE_LINK))
it.attribute(CppBinary.LINKAGE_ATTRIBUTE, Linkage.STATIC)
it.attribute(CppBinary.OPTIMIZED_ATTRIBUTE, false)
it.attribute(CppBinary.DEBUGGABLE_ATTRIBUTE, false)
it.attribute(Attribute.of("org.gradle.native.kotlin.platform", String::class.java), target.name)
}
project.pluginManager.withPlugin("maven-publish") {
platformConfiguration.artifacts.add(object: PublishArtifact {
override fun getName() = "${artifact.name}/${target.name}"
override fun getExtension() = if (artifactSuffix.startsWith('.')) artifactSuffix.substring(1) else artifactSuffix
override fun getType() = artifactSuffix
override fun getClassifier():String? = target.name
override fun getFile() = artifact
override fun getDate() = Date(artifact.lastModified())
override fun getBuildDependencies(): TaskDependency = this@KonanArtifactTask.taskDependencies
})
val objectFactory = project.objects
val linkUsage = objectFactory.named(Usage::class.java, Usage.NATIVE_LINK)
val runtimeUsage = objectFactory.named(Usage::class.java, Usage.NATIVE_RUNTIME)
val konanSoftwareComponent = project.extensions.getByName(KonanPlugin.KONAN_MAIN_VARIANT) as KonanSoftwareComponent
konanSoftwareComponent.addVariant(NativeVariant(Names.of(target.name), linkUsage, null, linkUsage, platformConfiguration))
}
} }
fun dependencies(closure: Closure<Unit>) {
if (konanTarget in project.konanTargets)
project.dependencies(closure)
}
// DSL. // DSL.
override fun artifactName(name: String) { override fun artifactName(name: String) {
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.gradle.plugin.tasks package org.jetbrains.kotlin.gradle.plugin.tasks
import org.gradle.api.artifacts.FileCollectionDependency
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.* import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
@@ -98,6 +99,12 @@ abstract class KonanCompileTask: KonanBuildingTask(), KonanCompileSpec {
addArgs("-repo", libraries.repos.map { it.canonicalPath }) addArgs("-repo", libraries.repos.map { it.canonicalPath })
if (platformConfiguration.files.isNotEmpty()) {
platformConfiguration.files.filter { it.name.endsWith(".klib") }.forEach {
addFileArgs("-library", project.files(it.absolutePath))
}
}
addFileArgs("-library", libraries.files) addFileArgs("-library", libraries.files)
addArgs("-library", libraries.namedKlibs) addArgs("-library", libraries.namedKlibs)
addArgs("-library", libraries.artifacts.map { it.artifact.canonicalPath }) addArgs("-library", libraries.artifacts.map { it.artifact.canonicalPath })