[Gradle] Implement CreateTargetConfigurationsSideEffect and NativeForwardImplementationToApiElementsSideEffect

KT-61634
This commit is contained in:
Sebastian Sellmair
2023-10-19 10:10:48 +02:00
committed by Space Team
parent 787420cc21
commit eb4daa4482
6 changed files with 140 additions and 118 deletions
@@ -41,16 +41,13 @@ interface KotlinTargetConfigurator<KotlinTargetType : KotlinTarget> {
) {
target.runKotlinTargetSideEffects()
target.runKotlinCompilationSideEffects()
defineConfigurationsForTarget(target)
configureArchivesAndComponent(target)
configureBuild(target)
configurePlatformSpecificModel(target)
}
fun defineConfigurationsForTarget(target: KotlinTargetType)
fun configureArchivesAndComponent(target: KotlinTargetType)
fun configureBuild(target: KotlinTargetType)
fun configurePlatformSpecificModel(target: KotlinTargetType) = Unit
}
@@ -60,96 +57,6 @@ abstract class AbstractKotlinTargetConfigurator<KotlinTargetType : KotlinTarget>
protected open val runtimeIncludesCompilationOutputs = true
override fun defineConfigurationsForTarget(target: KotlinTargetType) {
val project = target.project
val configurations = project.configurations
val mainCompilation = target.compilations.maybeCreate(KotlinCompilation.MAIN_COMPILATION_NAME)
val compileConfiguration = mainCompilation.internal.configurations.deprecatedCompileConfiguration
val implementationConfiguration = configurations.maybeCreate(mainCompilation.implementationConfigurationName)
val runtimeOnlyConfiguration = when (mainCompilation) {
is KotlinCompilationToRunnableFiles<*> -> configurations.maybeCreate(mainCompilation.runtimeOnlyConfigurationName)
else -> null
}
configurations.maybeCreate(target.apiElementsConfigurationName).apply {
description = "API elements for main."
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
extendsFrom(configurations.maybeCreate(mainCompilation.apiConfigurationName))
if (mainCompilation is KotlinCompilationToRunnableFiles) {
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
runtimeConfiguration?.let { extendsFrom(it) }
}
usesPlatformOf(target)
}
if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
configurations.maybeCreate(target.runtimeElementsConfigurationName).apply {
description = "Elements of runtime for main."
isVisible = false
isCanBeConsumed = true
isCanBeResolved = false
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target))
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
extendsFrom(implementationConfiguration)
if (runtimeOnlyConfiguration != null)
extendsFrom(runtimeOnlyConfiguration)
runtimeConfiguration?.let { extendsFrom(it) }
usesPlatformOf(target)
}
}
configurations.maybeCreate(target.sourcesElementsConfigurationName).apply {
description = "Source files of main compilation of ${target.name}."
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
configureSourcesPublicationAttributes(target)
project.launch { isCanBeConsumed = target.internal.isSourcesPublishableFuture.await() }
}
if (createTestCompilation) {
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
val compileTestsConfiguration = testCompilation.internal.configurations.deprecatedCompileConfiguration
val testImplementationConfiguration = configurations.maybeCreate(testCompilation.implementationConfigurationName)
val testRuntimeOnlyConfiguration = when (testCompilation) {
is KotlinCompilationToRunnableFiles<*> -> configurations.maybeCreate(testCompilation.runtimeOnlyConfigurationName)
else -> null
}
compileConfiguration?.let { compileTestsConfiguration?.extendsFrom(it) }
testImplementationConfiguration.extendsFrom(implementationConfiguration)
testRuntimeOnlyConfiguration?.extendsFrom(runtimeOnlyConfiguration)
if (mainCompilation is KotlinCompilationToRunnableFiles && testCompilation is KotlinCompilationToRunnableFiles) {
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
val testRuntimeConfiguration = testCompilation.internal.configurations.deprecatedRuntimeConfiguration
runtimeConfiguration?.let { testRuntimeConfiguration?.extendsFrom(it) }
}
}
}
@Deprecated("Remove when IR compiler to klib will not need transitive implementation dependencies")
protected fun implementationToApiElements(target: KotlinTargetType) {
val configurations = target.project.configurations
// The configuration and the main compilation are created by the base class.
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
configurations.getByName(target.apiElementsConfigurationName).apply {
// K/N and K/JS IR compiler doesn't divide libraries into implementation and api ones. So we need to add implementation
// dependencies into the outgoing configuration.
extendsFrom(configurations.getByName(mainCompilation.implementationConfigurationName))
}
}
override fun configureBuild(target: KotlinTargetType) {
val project = target.project
@@ -50,6 +50,8 @@ 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.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.js.npm.AddNpmDependencyExtensionProjectSetupAction
import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetSetupAction
@@ -96,6 +98,8 @@ internal fun Project.registerKotlinPluginExtensions() {
KotlinTargetSideEffect.extensionPoint.apply {
register(project, CreateDefaultCompilationsSideEffect)
register(project, CreateTargetConfigurationsSideEffect)
register(project, NativeForwardImplementationToApiElementsSideEffect)
}
KotlinCompilationSideEffect.extensionPoint.apply {
@@ -0,0 +1,107 @@
/*
* 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.gradle.api.attributes.Category
import org.gradle.api.attributes.Usage
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.categoryByName
import org.jetbrains.kotlin.gradle.plugin.launch
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.configureSourcesPublicationAttributes
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.plugin.mpp.isSourcesPublishableFuture
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
internal val CreateTargetConfigurationsSideEffect = KotlinTargetSideEffect { target ->
val project = target.project
val configurations = project.configurations
val mainCompilation = target.compilations.maybeCreate(KotlinCompilation.MAIN_COMPILATION_NAME)
val compileConfiguration = mainCompilation.internal.configurations.deprecatedCompileConfiguration
val implementationConfiguration = configurations.maybeCreate(mainCompilation.implementationConfigurationName)
val runtimeOnlyConfiguration = when (mainCompilation) {
is KotlinCompilationToRunnableFiles<*> -> configurations.maybeCreate(mainCompilation.runtimeOnlyConfigurationName)
else -> null
}
configurations.maybeCreate(target.apiElementsConfigurationName).apply {
description = "API elements for main."
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
extendsFrom(configurations.maybeCreate(mainCompilation.apiConfigurationName))
if (mainCompilation is KotlinCompilationToRunnableFiles) {
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
runtimeConfiguration?.let { extendsFrom(it) }
}
usesPlatformOf(target)
}
if (mainCompilation is KotlinCompilationToRunnableFiles<*>) {
configurations.maybeCreate(target.runtimeElementsConfigurationName).apply {
description = "Elements of runtime for main."
isVisible = false
isCanBeConsumed = true
isCanBeResolved = false
attributes.attribute(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerRuntimeUsage(target))
attributes.attribute(Category.CATEGORY_ATTRIBUTE, project.categoryByName(Category.LIBRARY))
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
extendsFrom(implementationConfiguration)
if (runtimeOnlyConfiguration != null)
extendsFrom(runtimeOnlyConfiguration)
runtimeConfiguration?.let { extendsFrom(it) }
usesPlatformOf(target)
}
}
configurations.maybeCreate(target.sourcesElementsConfigurationName).apply {
description = "Source files of main compilation of ${target.name}."
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
configureSourcesPublicationAttributes(target)
project.launch { isCanBeConsumed = target.internal.isSourcesPublishableFuture.await() }
}
if (target !is KotlinMetadataTarget) {
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
val compileTestsConfiguration = testCompilation.internal.configurations.deprecatedCompileConfiguration
val testImplementationConfiguration = configurations.maybeCreate(testCompilation.implementationConfigurationName)
val testRuntimeOnlyConfiguration = when (testCompilation) {
is KotlinCompilationToRunnableFiles<*> -> configurations.maybeCreate(testCompilation.runtimeOnlyConfigurationName)
else -> null
}
compileConfiguration?.let { compileTestsConfiguration?.extendsFrom(it) }
testImplementationConfiguration.extendsFrom(implementationConfiguration)
testRuntimeOnlyConfiguration?.extendsFrom(runtimeOnlyConfiguration)
if (mainCompilation is KotlinCompilationToRunnableFiles && testCompilation is KotlinCompilationToRunnableFiles) {
val runtimeConfiguration = mainCompilation.internal.configurations.deprecatedRuntimeConfiguration
val testRuntimeConfiguration = testCompilation.internal.configurations.deprecatedRuntimeConfiguration
runtimeConfiguration?.let { testRuntimeConfiguration?.extendsFrom(it) }
}
}
if (target is KotlinJsIrTarget && !target.isMpp!!) {
target.project.configurations.maybeCreate(
target.commonFakeApiElementsConfigurationName
).apply {
description = "Common Fake API elements for main."
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
attributes.attribute<Usage>(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
}
}
}
@@ -0,0 +1,26 @@
/*
* 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.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
/**
* Kotlin/Multiplatform requires all dependencies to be available at compile time.
* We therefore forward all dependencies with the 'implementation' scope to 'apiElements' to ensure
* them being available transitively.
*/
internal val NativeForwardImplementationToApiElementsSideEffect = KotlinTargetSideEffect<KotlinNativeTarget> { target ->
val configurations = target.project.configurations
// The configuration and the main compilation are created by the base class.
val mainCompilation = target.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
configurations.getByName(target.apiElementsConfigurationName).apply {
// K/N and K/JS IR compiler doesn't divide libraries into implementation and api ones. So we need to add implementation
// dependencies into the outgoing configuration.
extendsFrom(configurations.getByName(mainCompilation.implementationConfigurationName))
}
}
@@ -5,17 +5,16 @@
package org.jetbrains.kotlin.gradle.targets.js.ir
import org.gradle.api.attributes.Usage
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
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.gradle.plugin.KotlinOnlyTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import org.jetbrains.kotlin.gradle.plugin.KotlinTargetWithTestsConfigurator
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
import org.jetbrains.kotlin.gradle.utils.decamelize
@@ -80,22 +79,6 @@ open class KotlinJsIrTargetConfigurator :
}
}
override fun defineConfigurationsForTarget(target: KotlinJsIrTarget) {
super.defineConfigurationsForTarget(target)
if (target.isMpp!!) return
target.project.configurations.maybeCreate(
target.commonFakeApiElementsConfigurationName
).apply {
description = "Common Fake API elements for main."
isVisible = false
isCanBeResolved = false
isCanBeConsumed = true
attributes.attribute<Usage>(Usage.USAGE_ATTRIBUTE, KotlinUsages.producerApiUsage(target))
attributes.attribute(KotlinPlatformType.attribute, KotlinPlatformType.common)
}
}
internal companion object {
internal fun KotlinJsCompilerOptions.configureJsDefaultOptions(
@@ -303,11 +303,6 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
}
}
override fun defineConfigurationsForTarget(target: T) {
super.defineConfigurationsForTarget(target)
implementationToApiElements(target)
}
private fun warnAboutIncorrectDependencies(target: KotlinNativeTarget) = target.project.launchInStage(ReadyForExecution) {
val compileOnlyDependencies = target.compilations.mapNotNull {