From 5185a17c249e00a1234daa9043d47b067497ff75 Mon Sep 17 00:00:00 2001 From: Vasily Levchenko Date: Thu, 15 Feb 2018 21:11:48 +0300 Subject: [PATCH] [gradle][plugin][konan] deployment of kotlin-native artifacts via maven machinery --- .../gradle/plugin/KonanCompileConfig.kt | 3 + .../gradle/plugin/KonanInteropLibrary.kt | 1 + .../kotlin/gradle/plugin/KonanPlugin.kt | 70 +++++++++++++++++-- .../kotlin/gradle/plugin/KonanSpecs.kt | 1 + .../gradle/plugin/tasks/KonanBaseTasks.kt | 52 +++++++++++--- .../gradle/plugin/tasks/KonanCompileTask.kt | 7 ++ 6 files changed, 122 insertions(+), 12 deletions(-) diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileConfig.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileConfig.kt index 7ed3f6f5183..ebfb8dc5db6 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileConfig.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanCompileConfig.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.gradle.plugin +import groovy.lang.Closure import org.gradle.api.Task import org.gradle.api.file.FileCollection import org.gradle.api.internal.project.ProjectInternal @@ -68,6 +69,8 @@ abstract class KonanCompileConfig(name: String, override fun entryPoint(entryPoint: String) = forEach { it.entryPoint(entryPoint) } override fun measureTime(flag: Boolean) = forEach { it.measureTime(flag) } + + override fun dependencies(closure: Closure) = forEach { it.dependencies(closure) } } open class KonanProgram(name: String, diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropLibrary.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropLibrary.kt index 506d335b6dc..bbe0e83bee3 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropLibrary.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanInteropLibrary.kt @@ -84,5 +84,6 @@ open class KonanInteropLibrary(name: String, override fun link(vararg files: Any) = forEach { it.link(*files) } override fun link(files: FileCollection) = forEach { it.link(files) } + override fun dependencies(closure: Closure) = forEach { it.dependencies(closure) } } \ No newline at end of file diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanPlugin.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanPlugin.kt index 5640dfb8695..33b9d7f1b5c 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanPlugin.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanPlugin.kt @@ -17,9 +17,23 @@ package org.jetbrains.kotlin.gradle.plugin 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.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.plugins.AppliedPlugin 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.jetbrains.kotlin.gradle.plugin.KonanPlugin.Companion.COMPILE_ALL_TASK_NAME import org.jetbrains.kotlin.gradle.plugin.tasks.* @@ -242,6 +256,18 @@ open class KonanExtension { var jvmArgs = mutableListOf() } +open class KonanSoftwareComponent(val project: ProjectInternal?): SoftwareComponentInternal, ComponentWithVariants { + private val usages = mutableSetOf() + override fun getUsages(): MutableSet = usages + + private val variants = mutableSetOf() + override fun getName() = "main" + + override fun getVariants(): Set = variants + + fun addVariant(component: SoftwareComponent) = variants.add(component) +} + class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderRegistry) : Plugin { @@ -259,6 +285,7 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR internal const val KONAN_DOWNLOAD_TASK_NAME = "checkKonanCompiler" internal const val KONAN_GENERATE_CMAKE_TASK_NAME = "generateCMake" internal const val COMPILE_ALL_TASK_NAME = "compileKonan" + internal const val KONAN_MAIN_VARIANT = "konan_main_variant" internal const val KONAN_EXTENSION_NAME = "konan" @@ -272,15 +299,20 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR project.delete(it.artifact) } + + override fun apply(project: ProjectInternal?) { - if (project == null) { return } + if (project == null) { + return + } registry.register(KonanToolingModelBuilder) project.plugins.apply("base") // Create necessary tasks and extensions. project.tasks.create(KONAN_DOWNLOAD_TASK_NAME, KonanCompilerDownloadTask::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(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. if (!project.hasProperty(ProjectProperty.KONAN_HOME)) { @@ -306,7 +338,7 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR doLast { for (task in project.tasks .withType(KonanCompileProgramTask::class.java) - .matching { !it.isCrossCompile}) { + .matching { !it.isCrossCompile }) { project.exec { with(it) { 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 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() + } + } + } + } + } + } } } diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanSpecs.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanSpecs.kt index 26859dadc08..f524f46a03e 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanSpecs.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/KonanSpecs.kt @@ -31,6 +31,7 @@ interface KonanArtifactWithLibrariesSpec: KonanArtifactSpec { fun libraries(configure: KonanLibrariesSpec.() -> Unit) fun noDefaultLibs(flag: Boolean) + fun dependencies(closure: Closure) } interface KonanBuildingSpec: KonanArtifactWithLibrariesSpec { diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanBaseTasks.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanBaseTasks.kt index be8efb09a85..12e4f294f83 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanBaseTasks.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanBaseTasks.kt @@ -20,18 +20,21 @@ import groovy.lang.Closure import org.gradle.api.Action import org.gradle.api.DefaultTask import org.gradle.api.Project -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.Internal -import org.gradle.api.tasks.Nested -import org.gradle.api.tasks.OutputFile +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.PublishArtifact +import org.gradle.api.attributes.Attribute +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.jetbrains.kotlin.gradle.plugin.KonanArtifactSpec -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.gradle.plugin.* import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget import java.io.File +import java.util.* internal val Project.host get() = HostManager.host.visibleName @@ -63,6 +66,8 @@ abstract class KonanArtifactTask: KonanTargetableTask(), KonanArtifactSpec { @Internal lateinit var destinationDir: File @Internal lateinit var artifactName: String + @Internal lateinit var platformConfiguration: Configuration + @Internal lateinit var configuration: Configuration protected val artifactFullName: String @Internal get() = "$artifactPrefix$artifactName$artifactSuffix" @@ -80,8 +85,39 @@ abstract class KonanArtifactTask: KonanTargetableTask(), KonanArtifactSpec { super.init(target) this.destinationDir = destinationDir 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) { + if (konanTarget in project.konanTargets) + project.dependencies(closure) + } // DSL. override fun artifactName(name: String) { diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanCompileTask.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanCompileTask.kt index 6c00880b5ad..de6ad37397b 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanCompileTask.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/tasks/KonanCompileTask.kt @@ -16,6 +16,7 @@ package org.jetbrains.kotlin.gradle.plugin.tasks +import org.gradle.api.artifacts.FileCollectionDependency import org.gradle.api.file.FileCollection import org.gradle.api.tasks.* import org.jetbrains.kotlin.gradle.plugin.* @@ -98,6 +99,12 @@ abstract class KonanCompileTask: KonanBuildingTask(), KonanCompileSpec { 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) addArgs("-library", libraries.namedKlibs) addArgs("-library", libraries.artifacts.map { it.artifact.canonicalPath })