Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance. Project price only 1 $
You can buy this project and download/modify it how often you want.
/*
* Copyright 2010-2019 JetBrains s.r.o. 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.jvm
import org.gradle.api.InvalidUserCodeException
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DuplicatesStrategy
import org.gradle.api.plugins.JavaBasePlugin
import org.gradle.api.plugins.JavaPlugin
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.testing.Test
import org.gradle.jvm.tasks.Jar
import org.gradle.language.jvm.tasks.ProcessResources
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsDefault
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnostic
import org.jetbrains.kotlin.gradle.plugin.internal.JavaSourceSetsAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.SourceSetCompatibilityHelper
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinOnlyTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.internal
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmRunDsl
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmRunDslImpl
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.registerMainRunTask
import org.jetbrains.kotlin.gradle.tasks.DefaultKotlinJavaToolchain
import org.jetbrains.kotlin.gradle.tasks.withType
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.Future
import org.jetbrains.kotlin.gradle.utils.findAppliedAndroidPluginIdOrNull
import org.jetbrains.kotlin.gradle.utils.future
import java.util.concurrent.Callable
import javax.inject.Inject
abstract class KotlinJvmTarget @Inject constructor(
project: Project,
) : KotlinOnlyTarget(project, KotlinPlatformType.jvm),
HasConfigurableKotlinCompilerOptions,
KotlinTargetWithTests {
override val testRuns: NamedDomainObjectContainer by lazy {
project.container(KotlinJvmTestRun::class.java, KotlinJvmTestRunFactory(this))
}
internal val mainRun: Future = project.future { registerMainRunTask() }
/**
* ### ⚠️ KotlinJvmTarget 'mainRun' is experimental
* The [KotlinJvmTarget], by default, creates a 'run' task called {targetName}Run, which will allows simple
* execution of the targets 'main' code.
*
* e.g.
* ```kotlin
* // build.gradle.kts
* kotlin {
* jvm().mainRun {
* mainClass.set("FooKt")
* }
* }
*
* // src/jvmMain/Foo
* fun main() {
* println("Hello from foo")
* }
* ```
*
* will be executable using
* ```text
* ./gradlew jvmRun
* > "Hello from foo"
* ```
*
* ### Running a different 'mainClass' from CLI:
* The execution of the main code allows providing a different 'mainClass' via CLI. *
* It accepts System Properties and Gradle Properties. However, when Gradle Configuration Cache is used,
* System Properties are the preferred way.
*
* ```text
* ./gradlew jvmRun -DmainClass="BarKt"
* ^
* Will execute the 'src/jvmMain/kotlin/Bar' main method.
* ```
*/
@ExperimentalKotlinGradlePluginApi
fun mainRun(configure: KotlinJvmRunDsl.() -> Unit) = project.launch {
mainRun.await()?.configure()
}
var withJavaEnabled = false
private set
@Suppress("unused") // user DSL
fun withJava() {
if (withJavaEnabled)
return
project.multiplatformExtension.targets.find { it is KotlinJvmTarget && it.withJavaEnabled }
?.let { existingJavaTarget ->
throw InvalidUserCodeException(
"Only one of the JVM targets can be configured to work with Java. The target '${existingJavaTarget.name}' is " +
"already set up to work with Java; cannot setup another target '$targetName'"
)
}
/**
* Reports diagnostic in the case of
* ```kotlin
* kotlin {
* jvm().withJava()
* }
* ```
*
* is used together with the Android Gradle Plugin.
* This case is incompatible so far, as the 'withJava' implementation is still using 'global' namespaces
* (like main/test, etc), which will clash with the global names used by AGP (also occupying main, test, etc).
*/
val trace = Throwable()
project.launchInStage(AfterFinaliseDsl) check@{
val androidPluginId = project.findAppliedAndroidPluginIdOrNull() ?: return@check
project.reportDiagnostic(KotlinToolingDiagnostics.JvmWithJavaIsIncompatibleWithAndroid(androidPluginId, trace))
}
withJavaEnabled = true
project.plugins.apply(JavaBasePlugin::class.java)
val javaSourceSets = project.variantImplementationFactory()
.getInstance(project)
.sourceSets
AbstractKotlinPlugin.setUpJavaSourceSets(this, duplicateJavaSourceSetsAsKotlinSourceSets = false)
// Below, some effort is made to ensure that a user or 3rd-party plugin that inspects or interacts
// with the entities created by the Java plugin, not knowing of the existence of the Kotlin plugin,
// sees 'the right picture' of the inputs and outputs, for example:
// * the relevant dependencies for Java and Kotlin are in sync,
// * the Java outputs contain the outputs produced by Kotlin as well
javaSourceSets.all { javaSourceSet ->
val compilation = compilations.getByName(javaSourceSet.name)
val compileJavaTask = project.tasks.withType().named(javaSourceSet.compileJavaTaskName)
setupJavaSourceSetSourcesAndResources(javaSourceSet, compilation)
val javaClasses = project.files(compileJavaTask.map { it.destinationDirectory })
compilation.output.classesDirs.from(javaClasses)
(javaSourceSet.output.classesDirs as? ConfigurableFileCollection)?.from(
compilation.output.classesDirs.minus(javaClasses)
)
javaSourceSet.output.setResourcesDir(Callable { compilation.output.resourcesDirProvider })
setupDependenciesCrossInclusionForJava(compilation, javaSourceSet)
}
project.launchInStage(AfterFinaliseDsl) {
val sourceSetCompatibilityHelper = project
.variantImplementationFactory()
.getInstance()
javaSourceSets.all { javaSourceSet ->
copyUserDefinedAttributesToJavaConfigurations(javaSourceSet, sourceSetCompatibilityHelper)
}
}
project.plugins.withType(JavaPlugin::class.java) {
// Eliminate the Java output configurations from dependency resolution to avoid ambiguity between them and
// the equivalent configurations created for the target:
project.configurations.findByName(JavaPlugin.API_ELEMENTS_CONFIGURATION_NAME)?.isCanBeConsumed = false
project.configurations.findByName(JavaPlugin.RUNTIME_ELEMENTS_CONFIGURATION_NAME)?.isCanBeConsumed = false
disableJavaPluginTasks(javaSourceSets)
}
compilations.all { compilation ->
compilation.maybeCreateJavaSourceSet()
}
}
private fun disableJavaPluginTasks(javaSourceSet: SourceSetContainer) {
// A 'normal' build should not do redundant job like running the tests twice or building two JARs,
// so disable some tasks and just make them depend on the others:
val targetJar = project.tasks.withType(Jar::class.java).named(artifactsTaskName)
project.tasks.withType(Jar::class.java).named(javaSourceSet.getByName("main").jarTaskName) { javaJar ->
(javaJar.source as? ConfigurableFileCollection)?.setFrom(targetJar.map { it.source })
javaJar.archiveFileName.set(targetJar.flatMap { it.archiveFileName })
javaJar.dependsOn(targetJar)
javaJar.enabled = false
}
project.tasks.withType(Test::class.java).named(JavaPlugin.TEST_TASK_NAME) { javaTestTask ->
javaTestTask.dependsOn(project.tasks.named(testTaskName))
javaTestTask.enabled = false
}
}
private fun setupJavaSourceSetSourcesAndResources(
javaSourceSet: SourceSet,
compilation: KotlinJvmCompilation,
) {
javaSourceSet.java.setSrcDirs(listOf("src/${compilation.defaultSourceSet.name}/java"))
compilation.defaultSourceSet.kotlin.srcDirs(javaSourceSet.java.sourceDirectories)
// To avoid confusion in the sources layout, remove the default Java source directories
// (like src/main/java, src/test/java) and instead add sibling directories to those where the Kotlin
// sources are placed (i.e. src/jvmMain/java, src/jvmTest/java):
javaSourceSet.resources.setSrcDirs(compilation.defaultSourceSet.resources.sourceDirectories)
compilation.defaultSourceSet.resources.srcDirs(javaSourceSet.resources.sourceDirectories)
project.tasks.named(
compilation.processResourcesTaskName,
ProcessResources::class.java
).configure {
// Now 'compilation' has additional resources dir from java compilation which points to the initial
// resources location. Because of this, ProcessResources task will copy same files twice,
// so we are excluding duplicates.
it.duplicatesStrategy = DuplicatesStrategy.EXCLUDE
}
// Resources processing is done with the Kotlin resource processing task:
project.tasks.named(javaSourceSet.processResourcesTaskName).configure {
it.dependsOn(project.tasks.named(compilation.processResourcesTaskName))
it.enabled = false
}
}
private fun setupDependenciesCrossInclusionForJava(
compilation: KotlinJvmCompilation,
javaSourceSet: SourceSet,
) {
// Make sure Kotlin compilation dependencies appear in the Java source set classpaths:
listOfNotNull(
compilation.apiConfigurationName,
compilation.implementationConfigurationName,
compilation.compileOnlyConfigurationName,
compilation.internal.configurations.deprecatedCompileConfiguration?.name,
).forEach { configurationName ->
project.addExtendsFromRelation(javaSourceSet.compileClasspathConfigurationName, configurationName)
}
listOfNotNull(
compilation.apiConfigurationName,
compilation.implementationConfigurationName,
compilation.runtimeOnlyConfigurationName,
compilation.internal.configurations.deprecatedRuntimeConfiguration?.name,
).forEach { configurationName ->
project.addExtendsFromRelation(javaSourceSet.runtimeClasspathConfigurationName, configurationName)
}
// Add the Java source set dependencies to the Kotlin compilation compile & runtime configurations:
val sourceSetCompatibilityHelper = project
.variantImplementationFactory()
.getInstance()
val compileConfigurationName = if (areRuntimeOrCompileConfigurationsAvailable()) {
sourceSetCompatibilityHelper
.getCompileConfigurationName(javaSourceSet)
?.takeIf { project.configurations.findByName(it) != null }
} else null
listOfNotNull(
compileConfigurationName,
javaSourceSet.compileOnlyConfigurationName,
javaSourceSet.apiConfigurationName.takeIf { project.configurations.findByName(it) != null },
javaSourceSet.implementationConfigurationName
).forEach { configurationName ->
project.addExtendsFromRelation(compilation.compileDependencyConfigurationName, configurationName)
}
val runtimeConfigurationName = if (areRuntimeOrCompileConfigurationsAvailable()) {
sourceSetCompatibilityHelper
.getRuntimeConfigurationName(javaSourceSet)
?.takeIf { project.configurations.findByName(it) != null }
} else null
listOfNotNull(
runtimeConfigurationName,
javaSourceSet.runtimeOnlyConfigurationName,
javaSourceSet.apiConfigurationName.takeIf { project.configurations.findByName(it) != null },
javaSourceSet.implementationConfigurationName
).forEach { configurationName ->
project.addExtendsFromRelation(compilation.runtimeDependencyConfigurationName, configurationName)
}
}
private fun copyUserDefinedAttributesToJavaConfigurations(
javaSourceSet: SourceSet,
sourceSetCompatibilityHelper: SourceSetCompatibilityHelper
) {
val compileConfigurationName = if (areRuntimeOrCompileConfigurationsAvailable()) {
sourceSetCompatibilityHelper
.getCompileConfigurationName(javaSourceSet)
?.takeIf { project.configurations.findByName(it) != null }
} else null
val runtimeConfigurationName = if (areRuntimeOrCompileConfigurationsAvailable()) {
sourceSetCompatibilityHelper
.getRuntimeConfigurationName(javaSourceSet)
?.takeIf { project.configurations.findByName(it) != null }
} else null
listOfNotNull(
compileConfigurationName,
javaSourceSet.compileClasspathConfigurationName,
runtimeConfigurationName,
javaSourceSet.runtimeClasspathConfigurationName,
javaSourceSet.apiConfigurationName,
javaSourceSet.implementationConfigurationName,
javaSourceSet.compileOnlyConfigurationName,
javaSourceSet.runtimeOnlyConfigurationName,
).mapNotNull {
project.configurations.findByName(it)
}.forEach { configuration ->
copyAttributesTo(project, dest = configuration)
}
}
/**
* Check if "compile" and "runtime" configurations are still available in current Gradle version.
*/
private fun areRuntimeOrCompileConfigurationsAvailable(): Boolean =
GradleVersion.version(project.gradle.gradleVersion) <= GradleVersion.version("6.8.3")
@ExperimentalKotlinGradlePluginApi
override val compilerOptions: KotlinJvmCompilerOptions = project.objects
.newInstance()
.apply {
DefaultKotlinJavaToolchain.wireJvmTargetToToolchain(
this,
project
)
}
}