[Gradle] Replace KotlinTargetWithTestsConfigurator with KotlinTestRunFactory

KT-61634
This commit is contained in:
Sebastian Sellmair
2023-10-27 15:49:37 +02:00
committed by Space Team
parent 40820e42a6
commit 3fb415d966
15 changed files with 327 additions and 330 deletions
@@ -61,45 +61,6 @@ abstract class KotlinOnlyTargetConfigurator<KotlinCompilationType : KotlinCompil
createTestCompilation: Boolean,
) : AbstractKotlinTargetConfigurator<KotlinTargetType>(createTestCompilation)
internal interface KotlinTargetWithTestsConfigurator<R : KotlinTargetTestRun<*>, T : KotlinTargetWithTests<*, R>>
: KotlinTargetConfigurator<T> {
override fun configureTarget(target: T) {
super.configureTarget(target)
configureTest(target)
}
val testRunClass: Class<R>
fun createTestRun(name: String, target: T): R
fun configureTest(target: T) {
initializeTestRuns(target)
target.testRuns.create(KotlinTargetWithTests.DEFAULT_TEST_RUN_NAME)
}
private fun initializeTestRuns(target: T) {
val project = target.project
val testRunsPropertyName = KotlinTargetWithTests<*, *>::testRuns.name
val mutableProperty =
target::class.memberProperties
.find { it.name == testRunsPropertyName } as? KMutableProperty1<*, *>
?: error(
"The ${this::class.qualifiedName} implementation of ${KotlinTargetWithTests::class.qualifiedName} must " +
"override the $testRunsPropertyName property with a var."
)
val testRunsContainer = project.container(testRunClass) { testRunName -> createTestRun(testRunName, target) }
@Suppress("UNCHECKED_CAST")
(mutableProperty as KMutableProperty1<KotlinTargetWithTests<*, R>, NamedDomainObjectContainer<R>>)
.set(target, testRunsContainer)
(target as ExtensionAware).extensions.add(target::testRuns.name, testRunsContainer)
}
}
internal fun Project.usageByName(usageName: String): Usage =
objects.named(Usage::class.java, usageName)
@@ -66,6 +66,7 @@ import org.jetbrains.kotlin.gradle.targets.NativeForwardImplementationToApiEleme
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
import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeConfigureBinariesSideEffect
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizedCInteropApiElementsConfigurationsSetupAction
import org.jetbrains.kotlin.gradle.targets.native.tasks.artifact.KotlinArtifactsExtensionSetupAction
import org.jetbrains.kotlin.gradle.tooling.RegisterBuildKotlinToolingMetadataTask
@@ -112,6 +113,8 @@ internal fun Project.registerKotlinPluginExtensions() {
register(project, NativeForwardImplementationToApiElementsSideEffect)
register(project, CreateArtifactsSideEffect)
register(project, ConfigureBuildSideEffect)
register(project, KotlinNativeConfigureBinariesSideEffect)
register(project, CreateDefaultTestRunSideEffect)
}
KotlinCompilationSideEffect.extensionPoint.apply {
@@ -0,0 +1,14 @@
/*
* 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.KotlinTargetWithTests
import org.jetbrains.kotlin.gradle.plugin.addExtension
internal val CreateDefaultTestRunSideEffect = KotlinTargetSideEffect<KotlinTargetWithTests<*, *>> { target ->
target.addExtension(target::testRuns.name, target.testRuns)
target.testRuns.create(KotlinTargetWithTests.DEFAULT_TEST_RUN_NAME)
}
@@ -0,0 +1,11 @@
/*
* 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.NamedDomainObjectFactory
import org.jetbrains.kotlin.gradle.plugin.KotlinTestRun
internal interface KotlinTestRunFactory<T : KotlinTestRun<*>> : NamedDomainObjectFactory<T>
@@ -0,0 +1,31 @@
/*
* 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.js
import org.jetbrains.kotlin.gradle.targets.KotlinTestRunFactory
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTarget
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
internal class KotlinJsTestRunFactory(private val target: KotlinJsIrTarget) : KotlinTestRunFactory<KotlinJsReportAggregatingTestRun> {
override fun create(name: String): KotlinJsReportAggregatingTestRun {
val testRun = target.project.objects.newInstance(KotlinJsReportAggregatingTestRun::class.java, name, target)
val testTask = target.project.kotlinTestRegistry.getOrCreateAggregatedTestTask(
name = testRun.testTaskName,
description = "Run JS tests for all platforms"
)
// workaround to avoid the infinite recursion in item factories of the target and the subtargets:
target.testRuns.matching { it.name == name }.whenObjectAdded {
it.configureAllExecutions {
// do not do anything with the aggregated test run, but ensure that they are created
}
}
testRun.executionTask = testTask
return testRun
}
}
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.targets.js.JsAggregatingExecutionSource
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsReportAggregatingTestRun
import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTestRunFactory
import org.jetbrains.kotlin.gradle.targets.js.KotlinWasmTargetType
import org.jetbrains.kotlin.gradle.targets.js.binaryen.BinaryenExec
import org.jetbrains.kotlin.gradle.targets.js.dsl.*
@@ -54,8 +55,10 @@ constructor(
KotlinWasmSubTargetContainerDsl {
private val propertiesProvider = PropertiesProvider(project)
override lateinit var testRuns: NamedDomainObjectContainer<KotlinJsReportAggregatingTestRun>
internal set
override val testRuns: NamedDomainObjectContainer<KotlinJsReportAggregatingTestRun> by lazy {
project.container(KotlinJsReportAggregatingTestRun::class.java, KotlinJsTestRunFactory(this))
}
open var isMpp: Boolean? = null
internal set
@@ -10,50 +10,16 @@ import org.jetbrains.kotlin.gradle.dsl.JsSourceMapEmbedMode
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompilerOptions
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.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
open class KotlinJsIrTargetConfigurator :
KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true),
KotlinTargetWithTestsConfigurator<KotlinJsReportAggregatingTestRun, KotlinJsIrTarget> {
KotlinOnlyTargetConfigurator<KotlinJsIrCompilation, KotlinJsIrTarget>(true) {
override val runtimeIncludesCompilationOutputs: Boolean = false
override val testRunClass: Class<KotlinJsReportAggregatingTestRun> get() = KotlinJsReportAggregatingTestRun::class.java
override fun createTestRun(
name: String,
target: KotlinJsIrTarget
): KotlinJsReportAggregatingTestRun {
val result = target.project.objects.newInstance(
KotlinJsReportAggregatingTestRun::class.java,
name,
target
)
val testTask = target.project.kotlinTestRegistry.getOrCreateAggregatedTestTask(
name = result.testTaskName,
description = "Run JS tests for all platforms"
)
// workaround to avoid the infinite recursion in item factories of the target and the subtargets:
target.testRuns.matching { it.name == name }.whenObjectAdded {
it.configureAllExecutions {
// do not do anything with the aggregated test run, but ensure that they are created
}
}
result.executionTask = testTask
return result
}
internal companion object {
internal fun KotlinJsCompilerOptions.configureJsDefaultOptions(
platformType: KotlinPlatformType
platformType: KotlinPlatformType,
) {
moduleKind.set(JsModuleKind.MODULE_UMD)
sourceMap.set(true)
@@ -51,7 +51,9 @@ abstract class KotlinJvmTarget @Inject constructor(
) : KotlinOnlyTarget<KotlinJvmCompilation>(project, KotlinPlatformType.jvm),
KotlinTargetWithTests<JvmClasspathTestRunSource, KotlinJvmTestRun> {
override lateinit var testRuns: NamedDomainObjectContainer<KotlinJvmTestRun>
override val testRuns: NamedDomainObjectContainer<KotlinJvmTestRun> by lazy {
project.container(KotlinJvmTestRun::class.java, KotlinJvmTestRunFactory(this))
}
internal val mainRun: Future<KotlinJvmRunDslImpl?> = project.future { registerMainRunTask() }
@@ -5,55 +5,9 @@
package org.jetbrains.kotlin.gradle.targets.jvm
import org.gradle.api.Task
import org.gradle.api.plugins.JavaBasePlugin
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinOnlyTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
import org.jetbrains.kotlin.gradle.utils.whenEvaluated
open class KotlinJvmTargetConfigurator :
KotlinOnlyTargetConfigurator<KotlinJvmCompilation, KotlinJvmTarget>(true),
KotlinTargetWithTestsConfigurator<KotlinJvmTestRun, KotlinJvmTarget> {
override fun configurePlatformSpecificModel(target: KotlinJvmTarget) {
super<KotlinOnlyTargetConfigurator>.configurePlatformSpecificModel(target)
super<KotlinTargetWithTestsConfigurator>.configurePlatformSpecificModel(target)
}
override val testRunClass: Class<KotlinJvmTestRun>
get() = KotlinJvmTestRun::class.java
override fun createTestRun(
name: String,
target: KotlinJvmTarget,
): KotlinJvmTestRun = KotlinJvmTestRun(name, target).apply {
val testTaskOrProvider = target.project.registerTask<KotlinJvmTest>(testTaskName) { testTask ->
testTask.targetName = target.disambiguationClassifier
}
target.project.locateTask<Task>(JavaBasePlugin.CHECK_TASK_NAME)?.dependsOn(testTaskOrProvider)
executionTask = testTaskOrProvider
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
setExecutionSourceFrom(testCompilation)
target.project.whenEvaluated {
// use afterEvaluate to override the JavaPlugin defaults for Test tasks
testTaskOrProvider.configure { testTask ->
testTask.description = "Runs the tests of the $name test run."
testTask.group = JavaBasePlugin.VERIFICATION_GROUP
}
}
target.project.kotlinTestRegistry.registerTestTask(testTaskOrProvider)
}
KotlinOnlyTargetConfigurator<KotlinJvmCompilation, KotlinJvmTarget>(true) {
}
@@ -0,0 +1,46 @@
/*
* 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.jvm
import org.gradle.api.Task
import org.gradle.api.plugins.JavaBasePlugin
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.launchInStage
import org.jetbrains.kotlin.gradle.targets.KotlinTestRunFactory
import org.jetbrains.kotlin.gradle.targets.jvm.tasks.KotlinJvmTest
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
internal class KotlinJvmTestRunFactory(private val target: KotlinJvmTarget) : KotlinTestRunFactory<KotlinJvmTestRun> {
override fun create(name: String): KotlinJvmTestRun {
return KotlinJvmTestRun(name, target).apply {
val testTaskOrProvider = target.project.registerTask<KotlinJvmTest>(testTaskName) { testTask ->
testTask.targetName = target.disambiguationClassifier
}
target.project.locateTask<Task>(JavaBasePlugin.CHECK_TASK_NAME)?.dependsOn(testTaskOrProvider)
executionTask = testTaskOrProvider
val testCompilation = target.compilations.getByName(KotlinCompilation.TEST_COMPILATION_NAME)
setExecutionSourceFrom(testCompilation)
target.project.launchInStage(KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript) {
// use afterEvaluate to override the JavaPlugin defaults for Test tasks
testTaskOrProvider.configure { testTask ->
testTask.description = "Runs the tests of the $name test run."
testTask.group = JavaBasePlugin.VERIFICATION_GROUP
}
}
target.project.kotlinTestRegistry.registerTestTask(testTaskOrProvider)
}
}
}
@@ -0,0 +1,121 @@
/*
* 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.native
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.plugins.BasePlugin
import org.gradle.api.tasks.Exec
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.plugin.KotlinNativeTargetConfigurator
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.launchInStage
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.XcodeVersionTask
import org.jetbrains.kotlin.gradle.plugin.mpp.apple.version
import org.jetbrains.kotlin.gradle.targets.KotlinTargetSideEffect
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeLink
import org.jetbrains.kotlin.gradle.tasks.dependsOn
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
internal val KotlinNativeConfigureBinariesSideEffect = KotlinTargetSideEffect<KotlinNativeTarget> { target ->
val project = target.project
// Create link and run tasks.
target.binaries.all {
project.createLinkTask(it)
}
target.binaries.withType(Executable::class.java).all {
project.createRunTask(it)
}
target.binaries.prefixGroups.all { prefixGroup ->
val linkGroupTask = project.locateOrRegisterTask<Task>(prefixGroup.linkTaskName) {
it.group = BasePlugin.BUILD_GROUP
it.description = "Links all binaries for target '${target.name}'."
}
prefixGroup.binaries.all {
linkGroupTask.dependsOn(it.linkTaskName)
}
}
// Create an aggregate link task for each compilation.
target.compilations.all {
project.registerTask<DefaultTask>(it.binariesTaskName) { task ->
task.group = BasePlugin.BUILD_GROUP
task.description = "Links all binaries for compilation '${it.name}' of target '${it.target.name}'."
}
}
project.launchInStage(KotlinPluginLifecycle.Stage.AfterEvaluateBuildscript) {
target.binaries.forEach { binary ->
project.tasks.named(binary.compilation.binariesTaskName).configure { binariesTask ->
binariesTask.dependsOn(binary.linkTaskName)
}
}
}
/**
* We create test binaries for all platforms but test runs only for:
* - host platforms: macosX64, linuxX64, mingwX64;
* - simulated platforms: iosX64, tvosX64, watchosX64.
* See more in [KotlinNativeTargetWithTestsConfigurator] and its subclasses.
*/
target.binaries.test(listOf(NativeBuildType.DEBUG)) { }
}
private fun Project.createLinkTask(binary: NativeBinary) {
// workaround for too late compilation compilerOptions creation
// which leads to not able run project.afterEvaluate because of wrong context
// this afterEvaluate comes from NativeCompilerOptions
val compilationCompilerOptions = binary.compilation.compilerOptions
val konanPropertiesBuildService = KonanPropertiesBuildService.registerIfAbsent(project)
val xcodeVersionTask = XcodeVersionTask.locateOrRegister(project)
val linkTask = registerTask<KotlinNativeLink>(
binary.linkTaskName, listOf(binary)
) {
val target = binary.target
it.group = BasePlugin.BUILD_GROUP
it.description = "Links ${binary.outputKind.description} '${binary.name}' for a target '${target.name}'."
it.enabled = binary.konanTarget.enabledOnCurrentHost
it.konanPropertiesService.set(konanPropertiesBuildService)
it.usesService(konanPropertiesBuildService)
it.toolOptions.freeCompilerArgs.value(compilationCompilerOptions.options.freeCompilerArgs)
it.toolOptions.freeCompilerArgs.addAll(providers.provider { PropertiesProvider(project).nativeLinkArgs })
it.runViaBuildToolsApi.value(false).disallowChanges() // K/N is not yet supported
it.xcodeVersion.set(xcodeVersionTask.version)
}
if (binary !is TestExecutable) {
tasks.named(binary.compilation.target.artifactsTaskName).dependsOn(linkTask)
locateOrRegisterTask<Task>(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(linkTask)
}
if (binary is Framework) {
createFrameworkArtifact(binary, linkTask)
}
}
private fun Project.createRunTask(binary: Executable) {
val taskName = binary.runTaskName ?: return
registerTask<Exec>(taskName) { exec ->
exec.group = KotlinNativeTargetConfigurator.RUN_GROUP
exec.description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}"
exec.enabled = binary.konanTarget.isCurrentHost
exec.executable = binary.outputFile.absolutePath
exec.workingDir = project.projectDir
exec.onlyIf { binary.outputFile.exists() }
exec.dependsOn(binary.linkTaskName)
}
}
@@ -9,10 +9,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Action
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.Attribute
import org.gradle.api.plugins.BasePlugin
import org.gradle.jvm.tasks.Jar
import org.jetbrains.kotlin.gradle.ExperimentalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.plugin.*
@@ -23,8 +20,8 @@ import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeBinaryTestRun
import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeHostTestRun
import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeSimulatorTestRun
import org.jetbrains.kotlin.gradle.targets.native.NativeBinaryTestRunSource
import org.jetbrains.kotlin.gradle.targets.native.internal.includeCommonizedCInteropMetadata
import org.jetbrains.kotlin.gradle.tasks.locateOrRegisterTask
import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeHostTestRunFactory
import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeSimulatorTestRunFactory
import org.jetbrains.kotlin.gradle.utils.dashSeparatedName
import org.jetbrains.kotlin.gradle.utils.klibModuleName
import org.jetbrains.kotlin.gradle.utils.newInstance
@@ -202,14 +199,18 @@ internal suspend fun getHostSpecificMainSharedSourceSets(project: Project): Set<
abstract class KotlinNativeTargetWithTests<T : KotlinNativeBinaryTestRun>(
project: Project,
konanTarget: KonanTarget,
) : KotlinNativeTarget(project, konanTarget), KotlinTargetWithTests<NativeBinaryTestRunSource, T> {
override lateinit var testRuns: NamedDomainObjectContainer<T>
internal set
}
) : KotlinNativeTarget(project, konanTarget), KotlinTargetWithTests<NativeBinaryTestRunSource, T>
abstract class KotlinNativeTargetWithHostTests @Inject constructor(project: Project, konanTarget: KonanTarget) :
KotlinNativeTargetWithTests<KotlinNativeHostTestRun>(project, konanTarget)
KotlinNativeTargetWithTests<KotlinNativeHostTestRun>(project, konanTarget) {
override val testRuns: NamedDomainObjectContainer<KotlinNativeHostTestRun> by lazy {
project.container(KotlinNativeHostTestRun::class.java, KotlinNativeHostTestRunFactory(this))
}
}
abstract class KotlinNativeTargetWithSimulatorTests @Inject constructor(project: Project, konanTarget: KonanTarget) :
KotlinNativeTargetWithTests<KotlinNativeSimulatorTestRun>(project, konanTarget)
KotlinNativeTargetWithTests<KotlinNativeSimulatorTestRun>(project, konanTarget) {
override val testRuns: NamedDomainObjectContainer<KotlinNativeSimulatorTestRun> by lazy {
project.container(KotlinNativeSimulatorTestRun::class.java, KotlinNativeSimulatorTestRunFactory(this))
}
}
@@ -43,55 +43,6 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
createTestCompilation = true
) {
// region Task creation.
private fun Project.createLinkTask(binary: NativeBinary) {
// workaround for too late compilation compilerOptions creation
// which leads to not able run project.afterEvaluate because of wrong context
// this afterEvaluate comes from NativeCompilerOptions
val compilationCompilerOptions = binary.compilation.compilerOptions
val konanPropertiesBuildService = KonanPropertiesBuildService.registerIfAbsent(project)
val xcodeVersionTask = XcodeVersionTask.locateOrRegister(project)
val linkTask = registerTask<KotlinNativeLink>(
binary.linkTaskName, listOf(binary)
) {
val target = binary.target
it.group = BasePlugin.BUILD_GROUP
it.description = "Links ${binary.outputKind.description} '${binary.name}' for a target '${target.name}'."
it.enabled = binary.konanTarget.enabledOnCurrentHost
it.konanPropertiesService.set(konanPropertiesBuildService)
it.usesService(konanPropertiesBuildService)
it.toolOptions.freeCompilerArgs.value(compilationCompilerOptions.options.freeCompilerArgs)
it.toolOptions.freeCompilerArgs.addAll(providers.provider { PropertiesProvider(project).nativeLinkArgs })
it.runViaBuildToolsApi.value(false).disallowChanges() // K/N is not yet supported
it.xcodeVersion.set(xcodeVersionTask.version)
}
if (binary !is TestExecutable) {
tasks.named(binary.compilation.target.artifactsTaskName).dependsOn(linkTask)
locateOrRegisterTask<Task>(LifecycleBasePlugin.ASSEMBLE_TASK_NAME).dependsOn(linkTask)
}
if (binary is Framework) {
createFrameworkArtifact(binary, linkTask)
}
}
private fun Project.createRunTask(binary: Executable) {
val taskName = binary.runTaskName ?: return
registerTask<Exec>(taskName) { exec ->
exec.group = RUN_GROUP
exec.description = "Executes Kotlin/Native executable ${binary.name} for target ${binary.target.name}"
exec.enabled = binary.konanTarget.isCurrentHost
exec.executable = binary.outputFile.absolutePath
exec.workingDir = project.projectDir
exec.onlyIf { binary.outputFile.exists() }
exec.dependsOn(binary.linkTaskName)
}
}
// FIXME support creating interop tasks for PM20
private fun Project.createCInteropTasks(
@@ -162,7 +113,6 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
// region Configuration.
override fun configurePlatformSpecificModel(target: T) {
configureBinaries(target)
configureFrameworkExport(target)
configureCInterops(target)
@@ -185,51 +135,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
}
}
protected fun configureBinaries(target: KotlinNativeTarget) {
val project = target.project
// Create link and run tasks.
target.binaries.all {
project.createLinkTask(it)
}
target.binaries.withType(Executable::class.java).all {
project.createRunTask(it)
}
target.binaries.prefixGroups.all { prefixGroup ->
val linkGroupTask = project.locateOrRegisterTask<Task>(prefixGroup.linkTaskName) {
it.group = BasePlugin.BUILD_GROUP
it.description = "Links all binaries for target '${target.name}'."
}
prefixGroup.binaries.all {
linkGroupTask.dependsOn(it.linkTaskName)
}
}
// Create an aggregate link task for each compilation.
target.compilations.all {
project.registerTask<DefaultTask>(it.binariesTaskName) { task ->
task.group = BasePlugin.BUILD_GROUP
task.description = "Links all binaries for compilation '${it.name}' of target '${it.target.name}'."
}
}
project.whenEvaluated {
target.binaries.forEach { binary ->
project.tasks.named(binary.compilation.binariesTaskName).configure { binariesTask ->
binariesTask.dependsOn(binary.linkTaskName)
}
}
}
/**
* We create test binaries for all platforms but test runs only for:
* - host platforms: macosX64, linuxX64, mingwX64;
* - simulated platforms: iosX64, tvosX64, watchosX64.
* See more in [KotlinNativeTargetWithTestsConfigurator] and its subclasses.
*/
target.binaries.test(listOf(NativeBuildType.DEBUG)) { }
}
fun configureFrameworkExport(target: KotlinNativeTarget) {
val project = target.project
@@ -320,99 +226,3 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
}
}
abstract class KotlinNativeTargetWithTestsConfigurator<
TargetType : KotlinNativeTargetWithTests<TestRunType>,
TestRunType : KotlinNativeBinaryTestRun,
TaskType : KotlinNativeTest,
>(
) : KotlinNativeTargetConfigurator<TargetType>(),
KotlinTargetWithTestsConfigurator<TestRunType, TargetType> {
abstract val testTaskClass: Class<TaskType>
abstract fun isTestTaskEnabled(target: TargetType): Boolean
protected open fun configureTestTask(target: TargetType, testTask: TaskType) {
testTask.group = LifecycleBasePlugin.VERIFICATION_GROUP
testTask.description = "Executes Kotlin/Native unit tests for target ${target.name}."
testTask.targetName = target.name
testTask.enabled = isTestTaskEnabled(target)
testTask.workingDir = target.project.projectDir.absolutePath
testTask.configureConventions()
}
protected open fun configureTestRun(target: TargetType, testRun: AbstractKotlinNativeTestRun<TaskType>) {
with(testRun) {
val project = target.project
val testTaskOrProvider = project.registerTask(testTaskName, testTaskClass) { testTask ->
configureTestTask(target, testTask)
}
executionTask = testTaskOrProvider
setExecutionSourceFrom(target.binaries.getTest(NativeBuildType.DEBUG))
project.kotlinTestRegistry.registerTestTask(testTaskOrProvider)
}
}
}
class KotlinNativeTargetWithHostTestsConfigurator() :
KotlinNativeTargetWithTestsConfigurator<
KotlinNativeTargetWithHostTests,
KotlinNativeHostTestRun,
KotlinNativeHostTest>() {
override val testTaskClass: Class<KotlinNativeHostTest>
get() = KotlinNativeHostTest::class.java
override val testRunClass: Class<KotlinNativeHostTestRun>
get() = KotlinNativeHostTestRun::class.java
override fun isTestTaskEnabled(target: KotlinNativeTargetWithHostTests): Boolean =
target.konanTarget.isCurrentHost
override fun createTestRun(
name: String,
target: KotlinNativeTargetWithHostTests,
): KotlinNativeHostTestRun =
DefaultHostTestRun(name, target).apply { configureTestRun(target, this) }
}
class KotlinNativeTargetWithSimulatorTestsConfigurator :
KotlinNativeTargetWithTestsConfigurator<
KotlinNativeTargetWithSimulatorTests,
KotlinNativeSimulatorTestRun,
KotlinNativeSimulatorTest>() {
override val testTaskClass: Class<KotlinNativeSimulatorTest>
get() = KotlinNativeSimulatorTest::class.java
override val testRunClass: Class<KotlinNativeSimulatorTestRun>
get() = KotlinNativeSimulatorTestRun::class.java
override fun isTestTaskEnabled(target: KotlinNativeTargetWithSimulatorTests): Boolean =
HostManager.hostIsMac && HostManager.host.architecture == target.konanTarget.architecture
override fun configureTestTask(target: KotlinNativeTargetWithSimulatorTests, testTask: KotlinNativeSimulatorTest) {
super.configureTestTask(target, testTask)
if (isTestTaskEnabled(target)) {
val deviceIdProvider = testTask.project.provider {
XcodeUtils.getDefaultTestDeviceId(target.konanTarget)
?: error("Xcode does not support simulator tests for ${target.konanTarget.name}. Check that requested SDK is installed.")
}
testTask.device.convention(deviceIdProvider).finalizeValueOnRead()
}
testTask.standalone.convention(true).finalizeValueOnRead()
}
override fun createTestRun(
name: String,
target: KotlinNativeTargetWithSimulatorTests,
): KotlinNativeSimulatorTestRun =
DefaultSimulatorTestRun(name, target).apply { configureTestRun(target, this) }
}
@@ -95,7 +95,7 @@ open class KotlinNativeTargetWithHostTestsPreset(name: String, project: Project,
AbstractKotlinNativeTargetPreset<KotlinNativeTargetWithHostTests>(name, project, konanTarget) {
override fun createTargetConfigurator(): AbstractKotlinTargetConfigurator<KotlinNativeTargetWithHostTests> =
KotlinNativeTargetWithHostTestsConfigurator()
KotlinNativeTargetConfigurator()
override fun instantiateTarget(name: String): KotlinNativeTargetWithHostTests =
project.objects.newInstance(KotlinNativeTargetWithHostTests::class.java, project, konanTarget)
@@ -106,7 +106,7 @@ open class KotlinNativeTargetWithSimulatorTestsPreset(name: String, project: Pro
AbstractKotlinNativeTargetPreset<KotlinNativeTargetWithSimulatorTests>(name, project, konanTarget) {
override fun createTargetConfigurator(): AbstractKotlinTargetConfigurator<KotlinNativeTargetWithSimulatorTests> =
KotlinNativeTargetWithSimulatorTestsConfigurator()
KotlinNativeTargetConfigurator()
override fun instantiateTarget(name: String): KotlinNativeTargetWithSimulatorTests =
project.objects.newInstance(KotlinNativeTargetWithSimulatorTests::class.java, project, konanTarget)
@@ -0,0 +1,74 @@
/*
* 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.native
import org.gradle.api.tasks.TaskProvider
import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.gradle.plugin.mpp.NativeBuildType
import org.jetbrains.kotlin.gradle.plugin.mpp.isCurrentHost
import org.jetbrains.kotlin.gradle.targets.KotlinTestRunFactory
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeSimulatorTest
import org.jetbrains.kotlin.gradle.targets.native.tasks.KotlinNativeTest
import org.jetbrains.kotlin.gradle.tasks.registerTask
import org.jetbrains.kotlin.gradle.testing.internal.configureConventions
import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry
import org.jetbrains.kotlin.gradle.testing.testTaskName
import org.jetbrains.kotlin.gradle.utils.XcodeUtils
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
internal class KotlinNativeHostTestRunFactory(private val target: KotlinNativeTarget) : KotlinTestRunFactory<KotlinNativeHostTestRun> {
override fun create(name: String): KotlinNativeHostTestRun {
return DefaultHostTestRun(name, target).apply {
val project = target.project
executionTask = this@KotlinNativeHostTestRunFactory.target.registerNativeTestTask(testTaskName)
setExecutionSourceFrom(this@KotlinNativeHostTestRunFactory.target.binaries.getTest(NativeBuildType.DEBUG))
project.kotlinTestRegistry.registerTestTask(executionTask)
}
}
}
internal class KotlinNativeSimulatorTestRunFactory(private val target: KotlinNativeTarget) :
KotlinTestRunFactory<KotlinNativeSimulatorTestRun> {
override fun create(name: String): KotlinNativeSimulatorTestRun {
val thisTarget = target
return DefaultSimulatorTestRun(name, target).apply {
val project = target.project
executionTask = thisTarget.registerNativeTestTask<KotlinNativeSimulatorTest>(testTaskName) { testTask ->
testTask.isEnabled = HostManager.hostIsMac && HostManager.host.architecture == thisTarget.konanTarget.architecture
testTask.configureDeviceId(thisTarget.konanTarget)
testTask.standalone.convention(true).finalizeValueOnRead()
}
setExecutionSourceFrom(thisTarget.binaries.getTest(NativeBuildType.DEBUG))
project.kotlinTestRegistry.registerTestTask(executionTask)
}
}
}
private inline fun <reified T : KotlinNativeTest> KotlinNativeTarget.registerNativeTestTask(
name: String, crossinline configure: (T) -> Unit = {},
): TaskProvider<T> {
return project.registerTask(name, T::class.java) { testTask ->
testTask.group = LifecycleBasePlugin.VERIFICATION_GROUP
testTask.description = "Executes Kotlin/Native unit tests for target ${targetName}."
testTask.targetName = this@registerNativeTestTask.targetName
testTask.enabled = konanTarget.isCurrentHost
testTask.workingDir = project.projectDir.absolutePath
testTask.configureConventions()
configure(testTask)
}
}
private fun KotlinNativeSimulatorTest.configureDeviceId(konanTarget: KonanTarget) {
if (!isEnabled) return
val deviceIdProvider = project.provider {
XcodeUtils.getDefaultTestDeviceId(konanTarget) ?: error(
"Xcode does not support simulator tests for ${konanTarget.name}. Check that requested SDK is installed."
)
}
device.convention(deviceIdProvider).finalizeValueOnRead()
}