diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt index 6686ab4ed51..e0b992504c9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/KotlinTargetConfigurator.kt @@ -61,45 +61,6 @@ abstract class KotlinOnlyTargetConfigurator(createTestCompilation) -internal interface KotlinTargetWithTestsConfigurator, T : KotlinTargetWithTests<*, R>> - : KotlinTargetConfigurator { - - override fun configureTarget(target: T) { - super.configureTarget(target) - configureTest(target) - } - - val testRunClass: Class - - 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, NamedDomainObjectContainer>) - .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) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt index 2fb175afc9c..de4c8ac06a0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/registerKotlinPluginExtensions.kt @@ -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 { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/CreateDefaultTestRunSideEffect.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/CreateDefaultTestRunSideEffect.kt new file mode 100644 index 00000000000..ee1e6c2c843 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/CreateDefaultTestRunSideEffect.kt @@ -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> { target -> + target.addExtension(target::testRuns.name, target.testRuns) + target.testRuns.create(KotlinTargetWithTests.DEFAULT_TEST_RUN_NAME) +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinTestRunFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinTestRunFactory.kt new file mode 100644 index 00000000000..424cd0a13dc --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/KotlinTestRunFactory.kt @@ -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> : NamedDomainObjectFactory \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTestRunFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTestRunFactory.kt new file mode 100644 index 00000000000..7ad3e60b28e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/KotlinJsTestRunFactory.kt @@ -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 { + 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 + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt index 33717998f0f..e700ca7e444 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTarget.kt @@ -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 - internal set + + override val testRuns: NamedDomainObjectContainer by lazy { + project.container(KotlinJsReportAggregatingTestRun::class.java, KotlinJsTestRunFactory(this)) + } open var isMpp: Boolean? = null internal set diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt index c3a6d687d47..06cd6b4940f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/js/ir/KotlinJsIrTargetConfigurator.kt @@ -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(true), - KotlinTargetWithTestsConfigurator { + KotlinOnlyTargetConfigurator(true) { override val runtimeIncludesCompilationOutputs: Boolean = false - override val testRunClass: Class 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) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt index 92e67eb3ad3..952fef453f9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTarget.kt @@ -51,7 +51,9 @@ abstract class KotlinJvmTarget @Inject constructor( ) : KotlinOnlyTarget(project, KotlinPlatformType.jvm), KotlinTargetWithTests { - override lateinit var testRuns: NamedDomainObjectContainer + override val testRuns: NamedDomainObjectContainer by lazy { + project.container(KotlinJvmTestRun::class.java, KotlinJvmTestRunFactory(this)) + } internal val mainRun: Future = project.future { registerMainRunTask() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt index 6e584761d19..77362413ecf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTargetConfigurator.kt @@ -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(true), - KotlinTargetWithTestsConfigurator { - - override fun configurePlatformSpecificModel(target: KotlinJvmTarget) { - super.configurePlatformSpecificModel(target) - super.configurePlatformSpecificModel(target) - } - - override val testRunClass: Class - get() = KotlinJvmTestRun::class.java - - override fun createTestRun( - name: String, - target: KotlinJvmTarget, - ): KotlinJvmTestRun = KotlinJvmTestRun(name, target).apply { - val testTaskOrProvider = target.project.registerTask(testTaskName) { testTask -> - testTask.targetName = target.disambiguationClassifier - } - target.project.locateTask(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(true) { } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTestRunFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTestRunFactory.kt new file mode 100644 index 00000000000..54ca5fc5544 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmTestRunFactory.kt @@ -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 { + override fun create(name: String): KotlinJvmTestRun { + return KotlinJvmTestRun(name, target).apply { + val testTaskOrProvider = target.project.registerTask(testTaskName) { testTask -> + testTask.targetName = target.disambiguationClassifier + } + target.project.locateTask(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) + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotilnNativeConfigureBinariesSideEffect.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotilnNativeConfigureBinariesSideEffect.kt new file mode 100644 index 00000000000..181222ff8aa --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotilnNativeConfigureBinariesSideEffect.kt @@ -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 { 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(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(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( + 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(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(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) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt index f2c8168180a..691117583b0 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTarget.kt @@ -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( project: Project, konanTarget: KonanTarget, -) : KotlinNativeTarget(project, konanTarget), KotlinTargetWithTests { - - override lateinit var testRuns: NamedDomainObjectContainer - internal set -} +) : KotlinNativeTarget(project, konanTarget), KotlinTargetWithTests abstract class KotlinNativeTargetWithHostTests @Inject constructor(project: Project, konanTarget: KonanTarget) : - KotlinNativeTargetWithTests(project, konanTarget) + KotlinNativeTargetWithTests(project, konanTarget) { + override val testRuns: NamedDomainObjectContainer by lazy { + project.container(KotlinNativeHostTestRun::class.java, KotlinNativeHostTestRunFactory(this)) + } +} abstract class KotlinNativeTargetWithSimulatorTests @Inject constructor(project: Project, konanTarget: KonanTarget) : - KotlinNativeTargetWithTests(project, konanTarget) + KotlinNativeTargetWithTests(project, konanTarget) { + override val testRuns: NamedDomainObjectContainer by lazy { + project.container(KotlinNativeSimulatorTestRun::class.java, KotlinNativeSimulatorTestRunFactory(this)) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index deb22f0aab0..9677eaa8ba9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -43,55 +43,6 @@ open class KotlinNativeTargetConfigurator : 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( - 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(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(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 : AbstractKotl // region Configuration. override fun configurePlatformSpecificModel(target: T) { - configureBinaries(target) configureFrameworkExport(target) configureCInterops(target) @@ -185,51 +135,7 @@ open class KotlinNativeTargetConfigurator : 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(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(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 : AbstractKotl } } -abstract class KotlinNativeTargetWithTestsConfigurator< - TargetType : KotlinNativeTargetWithTests, - TestRunType : KotlinNativeBinaryTestRun, - TaskType : KotlinNativeTest, - >( -) : KotlinNativeTargetConfigurator(), - KotlinTargetWithTestsConfigurator { - - abstract val testTaskClass: Class - - 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) { - 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 - get() = KotlinNativeHostTest::class.java - - override val testRunClass: Class - 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 - get() = KotlinNativeSimulatorTest::class.java - - override val testRunClass: Class - 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) } -} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt index 2d1421e95b5..27129d52cd2 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetPreset.kt @@ -95,7 +95,7 @@ open class KotlinNativeTargetWithHostTestsPreset(name: String, project: Project, AbstractKotlinNativeTargetPreset(name, project, konanTarget) { override fun createTargetConfigurator(): AbstractKotlinTargetConfigurator = - 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(name, project, konanTarget) { override fun createTargetConfigurator(): AbstractKotlinTargetConfigurator = - KotlinNativeTargetWithSimulatorTestsConfigurator() + KotlinNativeTargetConfigurator() override fun instantiateTarget(name: String): KotlinNativeTargetWithSimulatorTests = project.objects.newInstance(KotlinNativeTargetWithSimulatorTests::class.java, project, konanTarget) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTestRunFactories.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTestRunFactories.kt new file mode 100644 index 00000000000..d6626709d80 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTestRunFactories.kt @@ -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 { + 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 { + override fun create(name: String): KotlinNativeSimulatorTestRun { + val thisTarget = target + return DefaultSimulatorTestRun(name, target).apply { + val project = target.project + executionTask = thisTarget.registerNativeTestTask(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 KotlinNativeTarget.registerNativeTestTask( + name: String, crossinline configure: (T) -> Unit = {}, +): TaskProvider { + 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() +} \ No newline at end of file