[Gradle] Replace 'configureArchivesAndComponent' with KotlinTargetArtifact

KT-61634
This commit is contained in:
Sebastian Sellmair
2023-10-19 16:19:53 +02:00
committed by Space Team
parent eb4daa4482
commit ded5cf2caa
19 changed files with 552 additions and 418 deletions
@@ -11,6 +11,12 @@ repositories {
}
kotlin {
sourceSets.all {
languageSettings {
optIn("kotlinx.cinterop.ExperimentalForeignApi")
}
}
val platformTarget = when {
HostManager.hostIsMac -> macosX64("platform")
HostManager.hostIsMingw -> mingwX64("platform")
@@ -0,0 +1,34 @@
/*
* Copyright 2010-2023 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.artifacts
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.targets.js.ir.KLIB_TYPE
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.wasmDecamelizedDefaultNameOrNull
import org.jetbrains.kotlin.gradle.utils.decamelize
import org.jetbrains.kotlin.gradle.utils.libsDirectory
internal val KotlinJsKlibArtifact = KotlinTargetArtifact { target, apiElements, runtimeElements ->
if (target !is KotlinJsIrTarget) return@KotlinTargetArtifact
val jsKlibTask = target.createArtifactsTask {
it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
it.archiveExtension.set(KLIB_TYPE)
it.destinationDirectory.set(target.project.libsDirectory)
if (target.platformType == KotlinPlatformType.wasm) {
if (target.wasmDecamelizedDefaultNameOrNull() != null) {
target.disambiguationClassifier?.let { classifier ->
it.archiveAppendix.set(classifier.decamelize())
}
}
}
}
target.createPublishArtifact(jsKlibTask, KLIB_TYPE, apiElements, runtimeElements)
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2023 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.artifacts
import org.gradle.api.artifacts.type.ArtifactTypeDefinition.JAR_TYPE
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.targets.jvm.KotlinJvmTarget
internal val KotlinJvmJarArtifact = KotlinTargetArtifact { target, apiElements, runtimeElements ->
if (target !is KotlinJvmTarget) return@KotlinTargetArtifact
val mainCompilation = target.compilations.getByName(MAIN_COMPILATION_NAME)
val jvmJarTask = target.createArtifactsTask { jar ->
jar.from(mainCompilation.output.allOutputs)
}
target.createPublishArtifact(jvmJarTask, JAR_TYPE, apiElements, runtimeElements)
}
@@ -0,0 +1,54 @@
/*
* Copyright 2010-2023 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.artifacts
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.bundling.Jar
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.categoryByName
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.sourceSetDependencyConfigurationByScope
import org.jetbrains.kotlin.gradle.plugin.usesPlatformOf
import org.jetbrains.kotlin.gradle.targets.metadata.COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.tasks.registerTask
internal val KotlinLegacyCompatibilityMetadataArtifact = KotlinTargetArtifact { target, _, _ ->
if (target !is KotlinMetadataTarget) return@KotlinTargetArtifact
if (!target.project.isKotlinGranularMetadataEnabled) return@KotlinTargetArtifact
if (!target.project.isCompatibilityMetadataVariantEnabled) return@KotlinTargetArtifact
val legacyJar = target.project.registerTask<Jar>(target.legacyArtifactsTaskName)
legacyJar.configure {
// Capture it here to use in onlyIf spec. Direct usage causes serialization of target attempt when configuration cache is enabled
it.description = "Assembles an archive containing the Kotlin metadata of the commonMain source set."
it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
}
/* Create actual Gradle artifact */
target.project.configurations.create(COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME).apply {
isCanBeConsumed = true
isCanBeResolved = false
usesPlatformOf(target)
attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
attributes.attribute(Category.CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
val commonMainApiConfiguration = target.project.configurations.sourceSetDependencyConfigurationByScope(
target.project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME),
KotlinDependencyScope.API_SCOPE
)
extendsFrom(commonMainApiConfiguration)
target.project.artifacts.add(name, legacyJar)
}
}
@@ -0,0 +1,22 @@
/*
* Copyright 2010-2023 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.artifacts
import org.gradle.api.artifacts.type.ArtifactTypeDefinition.JAR_TYPE
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
internal val KotlinLegacyMetadataArtifact = KotlinTargetArtifact artifact@{ target, apiElements, _ ->
if (target !is KotlinMetadataTarget) return@artifact
if (target.project.isKotlinGranularMetadataEnabled) return@artifact
val metadataJar = target.createArtifactsTask { jar ->
jar.from(target.compilations.getByName(MAIN_COMPILATION_NAME).output.allOutputs)
}
target.createPublishArtifact(metadataJar, JAR_TYPE, apiElements)
}
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2023 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.artifacts
import org.gradle.api.artifacts.type.ArtifactTypeDefinition.JAR_TYPE
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage
import org.jetbrains.kotlin.gradle.plugin.categoryByName
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.targets.metadata.createGenerateProjectStructureMetadataTask
import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
import org.jetbrains.kotlin.gradle.targets.metadata.isCompatibilityMetadataVariantEnabled
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.targets.native.internal.includeCommonizedCInteropMetadata
internal val KotlinMetadataArtifact = KotlinTargetArtifact { target, apiElements, _ ->
if (target !is KotlinMetadataTarget || !target.project.isKotlinGranularMetadataEnabled) return@KotlinTargetArtifact
apiElements.attributes.attribute(Usage.USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
apiElements.attributes.attribute(Category.CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
val metadataJarTask = target.createArtifactsTask { jar ->
jar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
if (target.project.isCompatibilityMetadataVariantEnabled) {
jar.archiveClassifier.set("all")
}
}
/* Include 'KotlinProjectStructureMetadata' file */
val generateMetadata = target.project.createGenerateProjectStructureMetadataTask()
metadataJarTask.configure { jar ->
jar.from(generateMetadata.map { it.resultFile }) { spec ->
spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME }
}
}
/* Include output of metadata compilations into metadata jar (including commonizer output if available */
val hostSpecificSourceSets = getHostSpecificSourceSets(target.project)
target.compilations.all { compilation ->
/* Filter legacy compilation */
if (compilation is KotlinCommonCompilation && !compilation.isKlibCompilation) return@all
/* Filter 'host specific' source sets (aka source sets that require a certain host to compile metadata) */
if (compilation.defaultSourceSet in hostSpecificSourceSets) return@all
val metadataContent = target.project.filesWithUnpackedArchives(compilation.output.allOutputs, setOf("klib"))
metadataJarTask.configure { it.from(metadataContent) { spec -> spec.into(compilation.defaultSourceSet.name) } }
if (compilation is KotlinSharedNativeCompilation) {
target.project.includeCommonizedCInteropMetadata(metadataJarTask, compilation)
}
}
target.createPublishArtifact(metadataJarTask, JAR_TYPE, apiElements)
}
@@ -0,0 +1,78 @@
/*
* Copyright 2010-2023 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.artifacts
import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.Usage
import org.gradle.api.plugins.BasePlugin
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl
import org.jetbrains.kotlin.gradle.plugin.launch
import org.jetbrains.kotlin.gradle.plugin.launchInStage
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.mpp.getHostSpecificSourceSets
import org.jetbrains.kotlin.gradle.plugin.usageByName
import org.jetbrains.kotlin.gradle.targets.metadata.filesWithUnpackedArchives
import org.jetbrains.kotlin.gradle.targets.metadata.findMetadataCompilation
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.targets.native.internal.includeCommonizedCInteropMetadata
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.utils.copyAttributes
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
internal val KotlinNativeHostSpecificMetadataArtifact = KotlinTargetArtifact { target, apiElements, _ ->
if (target !is KotlinNativeTarget) return@KotlinTargetArtifact
if (!target.project.isKotlinGranularMetadataEnabled) return@KotlinTargetArtifact
val project = target.project
target.project.configurations.create(target.hostSpecificMetadataElementsConfigurationName) { configuration ->
configuration.isCanBeConsumed = true
configuration.isCanBeResolved = false
configuration.extendsFrom(*apiElements.extendsFrom.toTypedArray())
target.project.launchInStage(AfterFinaliseDsl) {
copyAttributes(from = apiElements.attributes, to = configuration.attributes)
configuration.attributes.attribute(Usage.USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
}
}
val hostSpecificSourceSets = getHostSpecificSourceSets(target.project)
if (hostSpecificSourceSets.isEmpty()) return@KotlinTargetArtifact
val hostSpecificMetadataJar = project.locateOrRegisterTask<Jar>(target.hostSpecificMetadataElementsConfigurationName) { metadataJar ->
metadataJar.archiveAppendix.set(project.provider { target.disambiguationClassifier.orEmpty().toLowerCaseAsciiOnly() })
metadataJar.archiveClassifier.set("metadata")
metadataJar.group = BasePlugin.BUILD_GROUP
metadataJar.description = "Assembles Kotlin metadata of target '${target.name}'."
val publishable = target.publishable
metadataJar.onlyIf { publishable }
project.launch {
val metadataCompilations = hostSpecificSourceSets.mapNotNull {
project.findMetadataCompilation(it)
}
metadataCompilations.forEach { compilation ->
metadataJar.from(project.filesWithUnpackedArchives(compilation.output.allOutputs, setOf("klib"))) { spec ->
spec.into(compilation.name)
}
metadataJar.dependsOn(compilation.output.classesDirs)
if (compilation is KotlinSharedNativeCompilation) {
project.includeCommonizedCInteropMetadata(metadataJar, compilation)
}
}
}
}
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar)
project.artifacts.add(target.hostSpecificMetadataElementsConfigurationName, hostSpecificMetadataJar) { artifact ->
artifact.classifier = "metadata"
}
}
@@ -0,0 +1,81 @@
/*
* Copyright 2010-2023 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.artifacts
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.TaskProvider
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator.NativeArtifactFormat
import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.registerTask
import java.io.File
internal val KotlinNativeKlibArtifact = KotlinTargetArtifact { target, apiElements, _ ->
if (target !is KotlinNativeTarget) return@KotlinTargetArtifact
/* Just registering a dummy placeholder that other tasks can use as umbrella */
val artifactsTask = target.project.registerTask<DefaultTask>(target.artifactsTaskName) {
it.group = BasePlugin.BUILD_GROUP
it.description = "Assembles outputs for target '${target.name}'."
}
apiElements.outgoing.attributes.attribute(target.project.artifactTypeAttribute, NativeArtifactFormat.KLIB)
target.compilations.getByName(MAIN_COMPILATION_NAME).let { mainCompilation ->
artifactsTask.dependsOn(mainCompilation.compileTaskProvider)
createRegularKlibArtifact(mainCompilation)
}
}
internal fun createRegularKlibArtifact(compilation: AbstractKotlinNativeCompilation) = createKlibArtifact(
compilation = compilation,
artifactFile = compilation.compileTaskProvider.map { it.outputFile.get() },
classifier = null,
producingTask = compilation.compileTaskProvider
)
internal fun createKlibArtifact(
compilation: AbstractKotlinNativeCompilation,
artifactFile: Provider<File>,
classifier: String?,
producingTask: TaskProvider<*>,
) {
if (!compilation.konanTarget.enabledOnCurrentHost) {
return
}
val apiElementsName = compilation.target.apiElementsConfigurationName
with(compilation.project.configurations.getByName(apiElementsName)) {
val klibArtifact = compilation.project.artifacts.add(name, artifactFile) { artifact ->
artifact.name = compilation.compilationName
artifact.extension = "klib"
artifact.type = "klib"
artifact.classifier = classifier
artifact.builtBy(producingTask)
}
compilation.project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
artifacts.add(klibArtifact)
attributes.attribute(compilation.project.artifactTypeAttribute, NativeArtifactFormat.KLIB)
}
}
internal fun Project.klibOutputDirectory(
compilation: KotlinCompilationInfo,
): DirectoryProperty {
val targetSubDirectory = compilation.targetDisambiguationClassifier?.let { "$it/" }.orEmpty()
return project.objects.directoryProperty().value(
layout.buildDirectory.dir("classes/kotlin/$targetSubDirectory${compilation.compilationName}")
)
}
@@ -0,0 +1,59 @@
/*
* Copyright 2010-2023 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.artifacts
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency.ARCHIVES_CONFIGURATION
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.jetbrains.kotlin.gradle.plugin.KotlinGradlePluginExtensionPoint
import org.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
internal fun interface KotlinTargetArtifact {
suspend fun createArtifact(target: KotlinTarget, apiElements: Configuration, runtimeElements: Configuration?)
companion object {
val extensionPoint = KotlinGradlePluginExtensionPoint<KotlinTargetArtifact>()
}
}
internal fun KotlinTarget.createArtifactsTask(configure: (Jar) -> Unit = {}): TaskProvider<Jar> {
return project.registerTask<Jar>(artifactsTaskName) { jar ->
jar.description = "Assembles an archive containing the main classes."
jar.group = BasePlugin.BUILD_GROUP
jar.isPreserveFileTimestamps = false
jar.isReproducibleFileOrder = true
disambiguationClassifier?.let { classifier ->
jar.archiveAppendix.set(classifier.toLowerCaseAsciiOnly())
}
configure(jar)
}
}
internal fun KotlinTarget.createPublishArtifact(
artifactTask: TaskProvider<*>,
artifactType: String,
vararg elementsConfiguration: Configuration?,
): PublishArtifact {
val artifact = project.artifacts.add(ARCHIVES_CONFIGURATION, artifactTask) { artifact ->
artifact.builtBy(artifactTask)
artifact.type = artifactType
}
elementsConfiguration.filterNotNull().forEach { configuration ->
configuration.outgoing.artifacts.add(artifact)
configuration.outgoing.attributes.attribute(project.artifactTypeAttribute, artifactType)
}
return artifact
}
@@ -9,20 +9,15 @@ import org.gradle.api.Named
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.artifacts.PublishArtifact
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
import org.gradle.api.attributes.*
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip
import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.KotlinCompilationSideEffect
import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.runKotlinCompilationSideEffects
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsCompilerAttribute
import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetAttribute
@@ -39,14 +34,12 @@ interface KotlinTargetConfigurator<KotlinTargetType : KotlinTarget> {
fun configureTarget(
target: KotlinTargetType,
) {
target.runKotlinTargetSideEffects()
target.runKotlinCompilationSideEffects()
configureArchivesAndComponent(target)
target.runKotlinTargetSideEffects()
configureBuild(target)
configurePlatformSpecificModel(target)
}
fun configureArchivesAndComponent(target: KotlinTargetType)
fun configureBuild(target: KotlinTargetType)
fun configurePlatformSpecificModel(target: KotlinTargetType) = Unit
}
@@ -95,68 +88,7 @@ internal val KotlinTarget.testTaskName: String
abstract class KotlinOnlyTargetConfigurator<KotlinCompilationType : KotlinCompilation<*>, KotlinTargetType : KotlinOnlyTarget<KotlinCompilationType>>(
createTestCompilation: Boolean,
) : AbstractKotlinTargetConfigurator<KotlinTargetType>(createTestCompilation) {
open val archiveType: String = ArtifactTypeDefinition.JAR_TYPE
open val archiveTaskType: Class<out Zip>
get() = Jar::class.java
/** The implementations are expected to create a [Zip] task under the name [KotlinTarget.artifactsTaskName] of the [target]. */
protected open fun createArchiveTasks(target: KotlinTargetType): TaskProvider<out Zip> {
return target.project.registerTask(
target.artifactsTaskName,
archiveTaskType
) {
it.description = "Assembles an archive containing the main classes."
it.group = BasePlugin.BUILD_GROUP
it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
it.isPreserveFileTimestamps = false
it.isReproducibleFileOrder = true
target.disambiguationClassifier?.let { classifier ->
it.archiveAppendix.set(classifier.toLowerCaseAsciiOnly())
}
}
}
override fun configureArchivesAndComponent(target: KotlinTargetType) {
val project = target.project
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
val task = createArchiveTasks(target)
// Workaround: adding the artifact during configuration seems to interfere with the Java plugin, which results into missing
// task dependency 'assemble -> jar' if the Java plugin is applied after this steps
project.afterEvaluate {
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, task) { jarArtifact ->
jarArtifact.builtBy(task)
jarArtifact.type = archiveType
val apiElementsConfiguration = project.configurations.getByName(target.apiElementsConfigurationName)
// If the target adds its own artifact to this configuration until this happens, don't add another one:
addJarIfNoArtifactsPresent(project, apiElementsConfiguration, jarArtifact)
if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
val runtimeElementsConfiguration = project.configurations.getByName(target.runtimeElementsConfigurationName)
runtimeConfiguration?.let { addJarIfNoArtifactsPresent(project, runtimeConfiguration, jarArtifact) }
addJarIfNoArtifactsPresent(project, runtimeElementsConfiguration, jarArtifact)
}
}
}
}
private fun addJarIfNoArtifactsPresent(project: Project, configuration: Configuration, jarArtifact: PublishArtifact) {
if (configuration.artifacts.isEmpty()) {
val publications = configuration.outgoing
// Configure an implicit variant
publications.artifacts.add(jarArtifact)
publications.attributes.attribute(project.artifactTypeAttribute, archiveType)
}
}
}
) : AbstractKotlinTargetConfigurator<KotlinTargetType>(createTestCompilation)
internal interface KotlinTargetWithTestsConfigurator<R : KotlinTargetTestRun<*>, T : KotlinTargetWithTests<*, R>>
: KotlinTargetConfigurator<T> {
@@ -11,18 +11,15 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
import org.jetbrains.kotlin.gradle.plugin.KotlinJsIrSourceSetProcessor
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinCommonCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinSharedNativeCompilation
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrCompilation
import org.jetbrains.kotlin.gradle.targets.metadata.NativeSharedCompilationProcessor
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
internal val KotlinCompilationProcessorSideEffect = KotlinCompilationSideEffect { compilation ->
val processor = when (compilation) {
is KotlinCommonCompilation -> KotlinCommonSourceSetProcessor(KotlinCompilationInfo(compilation), KotlinTasksProvider())
is KotlinSharedNativeCompilation -> NativeSharedCompilationProcessor(compilation)
is KotlinJvmCompilation -> Kotlin2JvmSourceSetProcessor(KotlinTasksProvider(), KotlinCompilationInfo(compilation))
is KotlinJsIrCompilation -> KotlinJsIrSourceSetProcessor(KotlinTasksProvider(), KotlinCompilationInfo(compilation))
else -> null
}
processor?.run()
}
}
@@ -0,0 +1,79 @@
/*
* Copyright 2010-2023 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.plugin.mpp.compilationImpl
import org.gradle.api.plugins.BasePlugin
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.SubpluginEnvironment
import org.jetbrains.kotlin.gradle.plugin.launchInStage
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.enabledOnCurrentHost
import org.jetbrains.kotlin.gradle.artifacts.klibOutputDirectory
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.registerTask
/**
* Will register (and configure) the corresponding [KotlinNativeCompile] task for a given
* [AbstractKotlinNativeCompilation] (which includes shared native metadata and 'platform compilations')
*/
internal val KotlinCreateNativeCompileTasksSideEffect = KotlinCompilationSideEffect<AbstractKotlinNativeCompilation> { compilation ->
val project = compilation.project
val extension = project.topLevelExtension
val compilationInfo = KotlinCompilationInfo(compilation)
val kotlinNativeCompile = project.registerTask<KotlinNativeCompile>(
compilation.compileKotlinTaskName,
listOf(compilationInfo, compilation.compilerOptions.options)
) { task ->
task.group = BasePlugin.BUILD_GROUP
task.description = "Compiles a klibrary from the '${compilationInfo.compilationName}' " +
"compilation in target '${compilationInfo.targetDisambiguationClassifier}'."
task.enabled = compilation.konanTarget.enabledOnCurrentHost
task.destinationDirectory.set(project.klibOutputDirectory(compilationInfo).dir("klib"))
if (project.kotlinPropertiesProvider.useK2 == true) {
task.compilerOptions.useK2.set(true)
}
task.runViaBuildToolsApi.value(false).disallowChanges() // K/N is not yet supported
task.explicitApiMode.value(
project.providers.provider {
// Plugin explicitly does not configures 'explicitApi' mode for test sources
// compilation, as test sources are not published
if (compilationInfo.isMain) {
extension.explicitApi
} else {
ExplicitApiMode.Disabled
}
}
).finalizeValueOnRead()
}
compilationInfo.classesDirs.from(kotlinNativeCompile.map { it.outputFile })
project.tasks.named(compilation.compileAllTaskName).dependsOn(kotlinNativeCompile)
project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(kotlinNativeCompile)
compilation.addCompilerPlugins()
}
private fun AbstractKotlinNativeCompilation.addCompilerPlugins() {
val project = target.project
project.launchInStage(KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript) {
SubpluginEnvironment
.loadSubplugins(project)
.addSubpluginOptions(project, this@addCompilerPlugins)
compileTaskProvider.configure {
it.compilerPluginClasspath = this@addCompilerPlugins.configurations.pluginConfiguration
}
}
}
@@ -6,6 +6,12 @@
package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.artifacts.*
import org.jetbrains.kotlin.gradle.artifacts.KotlinJsKlibArtifact
import org.jetbrains.kotlin.gradle.artifacts.KotlinJvmJarArtifact
import org.jetbrains.kotlin.gradle.artifacts.KotlinNativeHostSpecificMetadataArtifact
import org.jetbrains.kotlin.gradle.artifacts.KotlinNativeKlibArtifact
import org.jetbrains.kotlin.gradle.artifacts.KotlinTargetArtifact
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.AndroidMainSourceSetConventionsChecker
import org.jetbrains.kotlin.gradle.dsl.IosSourceSetConventionChecker
@@ -49,10 +55,11 @@ import org.jetbrains.kotlin.gradle.plugin.sources.KotlinMultiplatformSourceSetSe
import org.jetbrains.kotlin.gradle.plugin.sources.LanguageSettingsSetupAction
import org.jetbrains.kotlin.gradle.plugin.statistics.MultiplatformBuildStatsReportSetupAction
import org.jetbrains.kotlin.gradle.scripting.internal.ScriptingGradleSubpluginSetupAction
import org.jetbrains.kotlin.gradle.targets.CreateArtifactsSideEffect
import org.jetbrains.kotlin.gradle.targets.CreateDefaultCompilationsSideEffect
import org.jetbrains.kotlin.gradle.targets.CreateTargetConfigurationsSideEffect
import org.jetbrains.kotlin.gradle.targets.NativeForwardImplementationToApiElementsSideEffect
import org.jetbrains.kotlin.gradle.targets.KotlinTargetSideEffect
import org.jetbrains.kotlin.gradle.targets.NativeForwardImplementationToApiElementsSideEffect
import org.jetbrains.kotlin.gradle.targets.js.npm.AddNpmDependencyExtensionProjectSetupAction
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetSetupAction
import org.jetbrains.kotlin.gradle.targets.native.CreateFatFrameworksSetupAction
@@ -100,15 +107,27 @@ internal fun Project.registerKotlinPluginExtensions() {
register(project, CreateDefaultCompilationsSideEffect)
register(project, CreateTargetConfigurationsSideEffect)
register(project, NativeForwardImplementationToApiElementsSideEffect)
register(project, CreateArtifactsSideEffect)
}
KotlinCompilationSideEffect.extensionPoint.apply {
register(project, KotlinCreateSourcesJarTaskSideEffect)
register(project, KotlinCreateResourcesTaskSideEffect)
register(project, KotlinCreateLifecycleTasksSideEffect)
register(project, KotlinCreateNativeCompileTasksSideEffect)
register(project, KotlinCompilationProcessorSideEffect)
}
KotlinTargetArtifact.extensionPoint.apply {
register(project, KotlinMetadataArtifact)
register(project, KotlinLegacyCompatibilityMetadataArtifact)
register(project, KotlinLegacyMetadataArtifact)
register(project, KotlinJvmJarArtifact)
register(project, KotlinJsKlibArtifact)
register(project, KotlinNativeKlibArtifact)
register(project, KotlinNativeHostSpecificMetadataArtifact)
}
KotlinGradleProjectChecker.extensionPoint.apply {
register(project, CommonMainOrTestWithDependsOnChecker)
register(project, DeprecatedKotlinNativeTargetsChecker)
@@ -0,0 +1,24 @@
/*
* Copyright 2010-2023 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
import org.jetbrains.kotlin.gradle.artifacts.KotlinTargetArtifact
import org.jetbrains.kotlin.gradle.plugin.launch
/**
* Creates target level artifacts (and exposes them in the 'apiElements' and 'runtimeElements' configurations)
* The corresponding task for jvm would be called 'jvmJar'
*/
internal val CreateArtifactsSideEffect = KotlinTargetSideEffect { target ->
val apiElements = target.project.configurations.getByName(target.apiElementsConfigurationName)
val runtimeElements = target.project.configurations.findByName(target.runtimeElementsConfigurationName)
KotlinTargetArtifact.extensionPoint[target.project].forEach { artifact ->
target.project.launch {
artifact.createArtifact(target, apiElements, runtimeElements)
}
}
}
@@ -5,9 +5,6 @@
package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip
import org.jetbrains.kotlin.gradle.dsl.JsModuleKind
import org.jetbrains.kotlin.gradle.dsl.JsSourceMapEmbedMode
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompilerOptions
@@ -17,8 +14,6 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTestsConfigurator
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
import org.jetbrains.kotlin.gradle.utils.decamelize
import org.jetbrains.kotlin.gradle.utils.libsDirectory
open class KotlinJsIrTargetConfigurator :
KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true),
@@ -28,12 +23,6 @@ open class KotlinJsIrTargetConfigurator :
override val testRunClass: Class<KotlinJsReportAggregatingTestRun> get() = KotlinJsReportAggregatingTestRun::class.java
override val archiveType: String
get() = KLIB_TYPE
override val archiveTaskType: Class<out Zip>
get() = Jar::class.java
override fun createTestRun(
name: String,
target: KotlinJsIrTarget
@@ -61,24 +50,6 @@ open class KotlinJsIrTargetConfigurator :
return result
}
override fun createArchiveTasks(target: KotlinJsIrTarget): TaskProvider<out Zip> {
val libsDirectory = target.project.libsDirectory
return super.createArchiveTasks(target).apply {
configure {
it.archiveExtension.set(KLIB_TYPE)
it.destinationDirectory.set(libsDirectory)
if (target.platformType == KotlinPlatformType.wasm) {
if (target.wasmDecamelizedDefaultNameOrNull() != null) {
target.disambiguationClassifier?.let { classifier ->
it.archiveAppendix.set(classifier.decamelize())
}
}
}
}
}
}
internal companion object {
internal fun KotlinJsCompilerOptions.configureJsDefaultOptions(
@@ -94,9 +94,10 @@ class KotlinCompilationNpmResolver(
if (compilation.isMain()) {
project.tasks
.withType(Zip::class.java)
.named(npmProject.target.artifactsTaskName)
.configure {
it.dependsOn(packageJsonTask)
.configureEach {
if (it.name == npmProject.target.artifactsTaskName) {
it.dependsOn(packageJsonTask)
}
}
val publicPackageJsonConfiguration = createPublicPackageJsonConfiguration()
@@ -12,12 +12,9 @@ import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Category.CATEGORY_ATTRIBUTE
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.file.FileCollection
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.tasks.TaskProvider
import org.gradle.api.tasks.bundling.Jar
import org.gradle.api.tasks.bundling.Zip
import org.jetbrains.kotlin.commonizer.SharedCommonizerTarget
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.metadataTarget
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
@@ -28,14 +25,10 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
import org.jetbrains.kotlin.gradle.targets.native.internal.createCInteropMetadataDependencyClasspath
import org.jetbrains.kotlin.gradle.targets.native.internal.includeCommonizedCInteropMetadata
import org.jetbrains.kotlin.gradle.targets.native.internal.sharedCommonizerTarget
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.utils.whenEvaluated
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.tooling.core.extrasLazyProperty
import org.jetbrains.kotlin.util.capitalizeDecapitalize.toLowerCaseAsciiOnly
internal const val COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME = "commonMainMetadataElements"
@@ -90,72 +83,15 @@ class KotlinMetadataTargetConfigurator :
compileKotlinTaskProvider.configure { it.onlyIf { isCompatibilityMetadataVariantEnabled } }
}
val allMetadataJar = target.project.tasks.named<Jar>(ALL_METADATA_JAR_NAME)
createMetadataCompilationsForCommonSourceSets(target, allMetadataJar)
configureProjectStructureMetadataGeneration(target.project, allMetadataJar)
createMetadataCompilationsForCommonSourceSets(target)
configureMetadataDependenciesConfigurationsForCommonSourceSets(target)
target.project.configurations.getByName(target.apiElementsConfigurationName).run {
attributes.attribute(USAGE_ATTRIBUTE, target.project.usageByName(KotlinUsages.KOTLIN_METADATA))
attributes.attribute(CATEGORY_ATTRIBUTE, target.project.categoryByName(Category.LIBRARY))
/** Note: to add this artifact here is enough to avoid duplicate artifacts in this configuration: the default artifact
* won't be added (later) if there's already an artifact in the configuration, see
* [KotlinOnlyTargetConfigurator.configureArchivesAndComponent] */
target.project.artifacts.add(target.apiElementsConfigurationName, allMetadataJar)
}
if (target.project.isCompatibilityMetadataVariantEnabled) {
createCommonMainElementsConfiguration(target)
}
} else {
/* We had nothing to do: Still mark this job as complete */
target.metadataCompilationsCreated.complete()
}
}
override fun createArchiveTasks(target: KotlinMetadataTarget): TaskProvider<out Zip> {
if (!target.project.isKotlinGranularMetadataEnabled)
return super.createArchiveTasks(target)
val result = target.project.registerTask<Jar>(target.artifactsTaskName) {
it.group = BasePlugin.BUILD_GROUP
it.isReproducibleFileOrder = true
it.isPreserveFileTimestamps = false
/** The content is added to this JAR in [KotlinMetadataTargetConfigurator.configureTarget]. */
}
result.configure { allMetadataJar ->
allMetadataJar.description = "Assembles a jar archive containing the metadata for all Kotlin source sets."
allMetadataJar.group = BasePlugin.BUILD_GROUP
if (target.project.isCompatibilityMetadataVariantEnabled) {
allMetadataJar.archiveClassifier.set("all")
}
target.disambiguationClassifier?.let { classifier ->
allMetadataJar.archiveAppendix.set(classifier.toLowerCaseAsciiOnly())
}
}
if (target.project.isCompatibilityMetadataVariantEnabled) {
val legacyJar = target.project.registerTask<Jar>(target.legacyArtifactsTaskName)
legacyJar.configure {
// Capture it here to use in onlyIf spec. Direct usage causes serialization of target attempt when configuration cache is enabled
val isCompatibilityMetadataVariantEnabled = target.project.isCompatibilityMetadataVariantEnabled
it.description = "Assembles an archive containing the Kotlin metadata of the commonMain source set."
if (!isCompatibilityMetadataVariantEnabled) {
it.archiveClassifier.set("commonMain")
}
it.onlyIf { isCompatibilityMetadataVariantEnabled }
it.from(target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME).output.allOutputs)
}
}
return result
}
private fun configureMetadataDependenciesConfigurationsForCommonSourceSets(target: KotlinMetadataTarget) {
target.project.whenEvaluated {
kotlinExtension.sourceSets.all { sourceSet ->
@@ -169,7 +105,6 @@ class KotlinMetadataTargetConfigurator :
private fun createMetadataCompilationsForCommonSourceSets(
target: KotlinMetadataTarget,
allMetadataJar: TaskProvider<out Jar>,
) = target.project.launchInStage(KotlinPluginLifecycle.Stage.AfterFinaliseDsl) {
withRestrictedStages(KotlinPluginLifecycle.Stage.upTo(KotlinPluginLifecycle.Stage.FinaliseCompilations)) {
// Do this after all targets are configured by the user build script
@@ -179,7 +114,7 @@ class KotlinMetadataTargetConfigurator :
val sourceSetsWithMetadataCompilations: Map<KotlinSourceSet, KotlinCompilation<*>> = publishedCommonSourceSets
.associateWith { sourceSet ->
createMetadataCompilation(target, sourceSet, allMetadataJar, sourceSet in hostSpecificSourceSets)
createMetadataCompilation(target, sourceSet, sourceSet in hostSpecificSourceSets)
}
.onEach { (sourceSet, compilation) ->
if (!isMetadataCompilationSupported(sourceSet)) {
@@ -224,16 +159,6 @@ class KotlinMetadataTargetConfigurator :
return true
}
private fun configureProjectStructureMetadataGeneration(project: Project, allMetadataJar: TaskProvider<out Jar>) {
val generateMetadata = project.createGenerateProjectStructureMetadataTask()
allMetadataJar.configure {
it.from(generateMetadata.map { it.resultFile }) { spec ->
spec.into("META-INF").rename { MULTIPLATFORM_PROJECT_METADATA_JSON_FILE_NAME }
}
}
}
private fun exportDependenciesForPublishing(
compilation: KotlinCompilation<*>,
) {
@@ -274,7 +199,6 @@ class KotlinMetadataTargetConfigurator :
private suspend fun createMetadataCompilation(
target: KotlinMetadataTarget,
sourceSet: KotlinSourceSet,
allMetadataJar: TaskProvider<out Jar>,
isHostSpecific: Boolean,
): KotlinCompilation<*> {
val project = target.project
@@ -300,13 +224,7 @@ class KotlinMetadataTargetConfigurator :
configureMetadataDependenciesForCompilation(this@apply)
if (!isHostSpecific) {
val metadataContent = project.filesWithUnpackedArchives(this@apply.output.allOutputs, setOf("klib"))
allMetadataJar.configure { it.from(metadataContent) { spec -> spec.into(this@apply.defaultSourceSet.name) } }
if (this is KotlinSharedNativeCompilation) {
project.includeCommonizedCInteropMetadata(allMetadataJar, this)
}
} else {
if (isHostSpecific) {
if (platformCompilations.filterIsInstance<KotlinNativeCompilation>().none { it.konanTarget.enabledOnCurrentHost }) {
// Then we don't have any platform module to put this compiled source set to, so disable the compilation task:
compileKotlinTaskProvider.configure { it.enabled = false }
@@ -344,36 +262,9 @@ class KotlinMetadataTargetConfigurator :
private val ResolvedArtifactResult.isMpp: Boolean get() = variant.attributes.containsMultiplatformAttributes
private fun createCommonMainElementsConfiguration(target: KotlinMetadataTarget) {
val project = target.project
project.configurations.create(COMMON_MAIN_ELEMENTS_CONFIGURATION_NAME).apply {
isCanBeConsumed = true
isCanBeResolved = false
usesPlatformOf(target)
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
attributes.attribute(CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
val commonMainApiConfiguration = project.configurations.sourceSetDependencyConfigurationByScope(
project.kotlinExtension.sourceSets.getByName(KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME),
KotlinDependencyScope.API_SCOPE
)
extendsFrom(commonMainApiConfiguration)
project.artifacts.add(name, project.tasks.getByName(target.legacyArtifactsTaskName))
}
}
}
internal class NativeSharedCompilationProcessor(
private val compilation: KotlinSharedNativeCompilation,
) : KotlinCompilationProcessor<KotlinNativeCompile>(KotlinCompilationInfo(compilation)) {
override val kotlinTask: TaskProvider<out KotlinNativeCompile> =
KotlinNativeTargetConfigurator.createKlibCompilationTask(compilationInfo, compilation.konanTarget)
override fun run() = Unit
}
internal fun Project.createGenerateProjectStructureMetadataTask(): TaskProvider<GenerateProjectStructureMetadata> =
project.registerTask(lowerCamelCaseName("generateProjectStructureMetadata")) { task ->
@@ -36,7 +36,7 @@ import javax.inject.Inject
abstract class KotlinNativeTarget @Inject constructor(
project: Project,
val konanTarget: KonanTarget
val konanTarget: KonanTarget,
) : KotlinTargetWithBinaries<KotlinNativeCompilation, KotlinNativeBinaryContainer>(
project,
KotlinPlatformType.native
@@ -64,44 +64,11 @@ abstract class KotlinNativeTarget @Inject constructor(
.intersect(mainCompilation.allKotlinSourceSets)
if (hostSpecificSourceSets.isNotEmpty()) {
val hostSpecificMetadataJar = project.locateOrRegisterTask<Jar>(hostSpecificMetadataJarTaskName) { metadataJar ->
metadataJar.archiveAppendix.set(project.provider { disambiguationClassifier.orEmpty().toLowerCaseAsciiOnly() })
metadataJar.archiveClassifier.set("metadata")
metadataJar.group = BasePlugin.BUILD_GROUP
metadataJar.description = "Assembles Kotlin metadata of target '${name}'."
val publishable = this@KotlinNativeTarget.publishable
metadataJar.onlyIf { publishable }
launch {
val metadataCompilations = hostSpecificSourceSets.mapNotNull {
project.findMetadataCompilation(it)
}
metadataCompilations.forEach { compilation ->
metadataJar.from(project.filesWithUnpackedArchives(compilation.output.allOutputs, setOf("klib"))) { spec ->
spec.into(compilation.name)
}
metadataJar.dependsOn(compilation.output.classesDirs)
if (compilation is KotlinSharedNativeCompilation) {
project.includeCommonizedCInteropMetadata(metadataJar, compilation)
}
}
}
}
project.artifacts.add(Dependency.ARCHIVES_CONFIGURATION, hostSpecificMetadataJar)
val metadataConfiguration = project.configurations.getByName(hostSpecificMetadataElementsConfigurationName)
project.artifacts.add(metadataConfiguration.name, hostSpecificMetadataJar) { artifact ->
artifact.classifier = "metadata"
}
mutableUsageContexts.add(
DefaultKotlinUsageContext(
mainCompilation,
KotlinUsageContext.MavenScope.COMPILE,
metadataConfiguration.name,
hostSpecificMetadataElementsConfigurationName,
includeIntoProjectStructureMetadata = false
)
)
@@ -196,7 +163,7 @@ internal fun isHostSpecificKonanTargetsSet(konanTargets: Iterable<KonanTarget>):
private suspend fun <T> getHostSpecificElements(
fragments: Iterable<T>,
isNativeShared: suspend (T) -> Boolean,
getKonanTargets: suspend (T) -> Set<KonanTarget>
getKonanTargets: suspend (T) -> Set<KonanTarget>,
): Set<T> = fragments.filterTo(mutableSetOf()) { isNativeShared(it) && isHostSpecificKonanTargetsSet(getKonanTargets(it)) }
internal suspend fun getHostSpecificSourceSets(project: Project): Set<KotlinSourceSet> {
@@ -234,7 +201,7 @@ internal suspend fun getHostSpecificMainSharedSourceSets(project: Project): Set<
abstract class KotlinNativeTargetWithTests<T : KotlinNativeBinaryTestRun>(
project: Project,
konanTarget: KonanTarget
konanTarget: KonanTarget,
) : KotlinNativeTarget(project, konanTarget), KotlinTargetWithTests<NativeBinaryTestRunSource, T> {
override lateinit var testRuns: NamedDomainObjectContainer<T>
@@ -12,27 +12,19 @@ import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.internal.plugins.DefaultArtifactPublicationSet
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Exec
import org.gradle.api.tasks.TaskProvider
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.ReadyForExecution
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.KOTLIN_NATIVE_IGNORE_INCORRECT_DEPENDENCIES
import org.jetbrains.kotlin.gradle.plugin.internal.artifactTypeAttribute
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XcodeVersionTask
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.registerEmbedAndSignAppleFrameworkTask
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.version
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.artifacts.createKlibArtifact
import org.jetbrains.kotlin.gradle.artifacts.klibOutputDirectory
import org.jetbrains.kotlin.gradle.targets.native.*
import org.jetbrains.kotlin.gradle.targets.native.internal.*
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeHostTest
@@ -44,11 +36,8 @@ import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
import org.jetbrains.kotlin.gradle.utils.whenEvaluated
import org.jetbrains.kotlin.gradle.utils.XcodeUtils
import org.jetbrains.kotlin.gradle.utils.copyAttributes
import org.jetbrains.kotlin.gradle.utils.newInstance
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotlinTargetConfigurator<T>(
createTestCompilation = true
@@ -150,8 +139,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
// Add the interop library in publication.
createKlibArtifact(
compilationInfo = compilationInfo,
konanTarget = konanTarget,
compilation,
artifactFile = interopTask.map { it.outputFile },
classifier = "cinterop-${interop.name}",
producingTask = interopTask,
@@ -187,30 +175,6 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
}
}
override fun configureArchivesAndComponent(target: T): Unit = with(target.project) {
registerTask<DefaultTask>(target.artifactsTaskName) {
it.group = BasePlugin.BUILD_GROUP
it.description = "Assembles outputs for target '${target.name}'."
}
target.compilations.all { createKlibCompilationTask(KotlinCompilationInfo(it), it.konanTarget) }
val apiElements = configurations.getByName(target.apiElementsConfigurationName)
apiElements.outgoing.attributes.attribute(artifactTypeAttribute, NativeArtifactFormat.KLIB)
if (project.isKotlinGranularMetadataEnabled) {
project.configurations.create(target.hostSpecificMetadataElementsConfigurationName) { configuration ->
configuration.isCanBeConsumed = true
configuration.isCanBeResolved = false
configuration.extendsFrom(*apiElements.extendsFrom.toTypedArray())
copyAttributes(from = apiElements.attributes, to = configuration.attributes)
configuration.attributes.attribute(USAGE_ATTRIBUTE, objects.named(Usage::class.java, KotlinUsages.KOTLIN_METADATA))
}
}
}
protected fun configureCInterops(target: KotlinNativeTarget): Unit = with(target.project) {
locateOrCreateCInteropApiElementsConfiguration(target)
target.compilations.all { compilation ->
@@ -352,130 +316,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
const val INTEROP_GROUP = "interop"
const val RUN_GROUP = "run"
internal fun createKlibCompilationTask(
compilationInfo: KotlinCompilationInfo,
konanTarget: KonanTarget,
): TaskProvider<KotlinNativeCompile> {
val project = compilationInfo.project
val ext = project.topLevelExtension
val compileTaskProvider = project.registerTask<KotlinNativeCompile>(
compilationInfo.compileKotlinTaskName,
listOf(
compilationInfo,
compilationInfo.compilerOptions.options as KotlinNativeCompilerOptions
)
) {
it.group = BasePlugin.BUILD_GROUP
it.description = "Compiles a klibrary from the '${compilationInfo.compilationName}' " +
"compilation in target '${compilationInfo.targetDisambiguationClassifier}'."
it.enabled = konanTarget.enabledOnCurrentHost
it.destinationDirectory.set(project.klibOutputDirectory(compilationInfo).dir("klib"))
val propertiesProvider = PropertiesProvider(project)
if (propertiesProvider.useK2 == true) {
it.compilerOptions.useK2.set(true)
}
it.runViaBuildToolsApi.value(false).disallowChanges() // K/N is not yet supported
it.explicitApiMode
.value(
project.providers.provider {
// Plugin explicitly does not configures 'explicitApi' mode for test sources
// compilation, as test sources are not published
if (compilationInfo.isMain) {
ext.explicitApi
} else {
ExplicitApiMode.Disabled
}
}
)
.finalizeValueOnRead()
}
compilationInfo.classesDirs.from(compileTaskProvider.map { it.outputFile })
project.project.tasks.named(compilationInfo.compileAllTaskName).dependsOn(compileTaskProvider)
if (compilationInfo.isMain) {
if (compilationInfo is KotlinCompilationInfo.TCS && compilationInfo.compilation is KotlinNativeCompilation) {
project.project.tasks.named(compilationInfo.compilation.target.artifactsTaskName).dependsOn(compileTaskProvider)
}
project.project.tasks.named(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(compileTaskProvider)
}
val shouldAddCompileOutputsToElements = compilationInfo.isMain
if (shouldAddCompileOutputsToElements) {
createRegularKlibArtifact(compilationInfo, konanTarget, compileTaskProvider)
}
if (compilationInfo is KotlinCompilationInfo.TCS && compilationInfo.compilation is AbstractKotlinNativeCompilation) {
// FIXME: support compiler plugins for PM20
addCompilerPlugins(compilationInfo.compilation)
}
return compileTaskProvider
}
private fun Project.klibOutputDirectory(
compilation: KotlinCompilationInfo,
): DirectoryProperty {
val targetSubDirectory = compilation.targetDisambiguationClassifier?.let { "$it/" }.orEmpty()
return project.objects.directoryProperty().value(
layout.buildDirectory.dir("classes/kotlin/$targetSubDirectory${compilation.compilationName}")
)
}
private fun addCompilerPlugins(compilation: AbstractKotlinNativeCompilation) {
val project = compilation.target.project
project.whenEvaluated {
SubpluginEnvironment
.loadSubplugins(project)
.addSubpluginOptions(project, compilation)
compilation.compileKotlinTaskProvider.configure {
it.compilerPluginClasspath = compilation.configurations.pluginConfiguration
}
}
}
internal fun createRegularKlibArtifact(
compilation: KotlinCompilationInfo,
konanTarget: KonanTarget,
compileTask: TaskProvider<out KotlinNativeCompile>,
) = createKlibArtifact(compilation, konanTarget, compileTask.map { it.outputFile.get() }, null, compileTask)
private fun createKlibArtifact(
compilationInfo: KotlinCompilationInfo,
konanTarget: KonanTarget,
artifactFile: Provider<File>,
classifier: String?,
producingTask: TaskProvider<*>,
) {
val project = compilationInfo.project
if (!konanTarget.enabledOnCurrentHost) {
return
}
val apiElementsName = when (compilationInfo) {
is KotlinCompilationInfo.TCS -> compilationInfo.compilation.target.apiElementsConfigurationName
}
with(project.configurations.getByName(apiElementsName)) {
val klibArtifact = project.project.artifacts.add(name, artifactFile) { artifact ->
artifact.name = compilationInfo.compilationName
artifact.extension = "klib"
artifact.type = "klib"
artifact.classifier = classifier
artifact.builtBy(producingTask)
}
project.project.extensions.getByType(DefaultArtifactPublicationSet::class.java).addCandidate(klibArtifact)
artifacts.add(klibArtifact)
attributes.attribute(project.artifactTypeAttribute, NativeArtifactFormat.KLIB)
}
}
}
}