diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index 3b919534c32..32e8c0bd619 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -2041,4 +2041,31 @@ class NewMultiplatformIT : BaseGradleIT() { assertNotContains(DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX) } } + + @Test + fun testAssociateCompilations() = with(Project("new-mpp-associate-compilations")) { + setupWorkingDir() + gradleBuildScript().modify(::transformBuildScriptWithPluginsDsl) + + val tasks = listOf("jvm", "js", nativeHostTargetName).map { ":compileIntegrationTestKotlin${it.capitalize()}" } + + build(*tasks.toTypedArray()) { + assertSuccessful() + assertTasksExecuted(*tasks.toTypedArray()) + + // JVM: + checkBytecodeContains( + projectDir.resolve("build/classes/kotlin/jvm/integrationTest/com/example/HelloIntegrationTest.class"), + "Hello.internalFun\$new_mpp_associate_compilations", + "HelloTest.internalTestFun\$new_mpp_associate_compilations" + ) + assertFileExists("build/classes/kotlin/jvm/integrationTest/META-INF/new-mpp-associate-compilations.kotlin_module") + + // JS: + assertFileExists("build/classes/kotlin/js/integrationTest/new-mpp-associate-compilations_integrationTest.js") + + // Native: + assertFileExists("build/classes/kotlin/$nativeHostTargetName/integrationTest/integrationTest.klib") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/build.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/build.gradle.kts index 689c91def8c..2e1f6bd8607 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/build.gradle.kts +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/build.gradle.kts @@ -34,9 +34,7 @@ kotlin.target.compilations { val benchmark by creating { defaultSourceSet.dependencies { - implementation(main.compileDependencyFiles + main.output.allOutputs) - runtimeOnly(main.runtimeDependencyFiles) - + associateWith(main) implementation(kotlin("reflect")) } } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/benchmark/kotlin/ABenchmark.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/benchmark/kotlin/ABenchmark.kt index 2ab90dbb1e8..140bb929349 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/benchmark/kotlin/ABenchmark.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/benchmark/kotlin/ABenchmark.kt @@ -3,6 +3,7 @@ package com.example fun main() { val a = A() val f = a::f + internalFun() f() println("${a::f.name} ran at the speed of light") } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/main/kotlin/A.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/main/kotlin/A.kt index b2ee3d1f08a..4edd326c339 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/main/kotlin/A.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-model-in-old-plugin/src/main/kotlin/A.kt @@ -2,4 +2,6 @@ package com.example class A { fun f(): String = "hello".also(::println) -} \ No newline at end of file +} + +fun internalFun() = 1 \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/build.gradle new file mode 100644 index 00000000000..e7a75c43b7d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/build.gradle @@ -0,0 +1,56 @@ +plugins { + id("org.jetbrains.kotlin.multiplatform").version("") +} + +repositories { + mavenLocal() + jcenter() +} + +kotlin { + sourceSets { + getByName("commonMain") { + dependencies { + implementation(kotlin("stdlib-common")) + } + } + + getByName("commonTest") { + dependencies { + implementation(kotlin("test-common")) + implementation(kotlin("test-annotations-common")) + } + } + + create("commonIntegrationTest") + } + + jvm { + compilations["main"].defaultSourceSet.dependencies { + implementation(kotlin("stdlib")) + } + compilations["test"].defaultSourceSet.dependencies { + implementation(kotlin("test-junit")) + } + } + + js { + compilations["main"].defaultSourceSet.dependencies { + implementation(kotlin("stdlib-js")) + } + compilations["test"].defaultSourceSet.dependencies { + implementation(kotlin("test-js")) + } + } + + mingwX64("mingw64") {} + linuxX64("linux64") {} + macosX64("macos64") {} + + targets.matching { it.name != "metadata" }.all { + compilations.create("integrationTest") { + associateWith(compilations["test"]) + defaultSourceSet.dependsOn(sourceSets["commonIntegrationTest"]) + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/settings.gradle.kts b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/settings.gradle.kts new file mode 100644 index 00000000000..efe86901347 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/settings.gradle.kts @@ -0,0 +1,8 @@ +pluginManagement { + repositories { + mavenLocal() + gradlePluginPortal() + } +} + +rootProject.name = "new-mpp-associate-compilations" \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonIntegrationTest/kotlin/HelloIntegrationTest.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonIntegrationTest/kotlin/HelloIntegrationTest.kt new file mode 100644 index 00000000000..27b6b3d9ffe --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonIntegrationTest/kotlin/HelloIntegrationTest.kt @@ -0,0 +1,24 @@ +package com.example + +import kotlin.test.Test + +class HelloIntegrationTest { + @Test + fun test(): Unit = Hello().run { + hello() + internalFun() + + HelloTest().run { + test() + internalTestFun() + } + } + + @Test + fun secondTest() = Unit + + @Test + fun thirdTest() = Unit +} + +fun topLevelMemberToMakeTheCompilerGenerateTheModuleFile() = 1 \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonMain/kotlin/Hello.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonMain/kotlin/Hello.kt new file mode 100644 index 00000000000..18cca42e9e0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonMain/kotlin/Hello.kt @@ -0,0 +1,6 @@ +package com.example + +class Hello { + fun hello() = 0 + internal fun internalFun() = 1 +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonTest/kotlin/HelloTest.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonTest/kotlin/HelloTest.kt new file mode 100644 index 00000000000..d85504a2aa0 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/new-mpp-associate-compilations/src/commonTest/kotlin/HelloTest.kt @@ -0,0 +1,19 @@ +package com.example + +import kotlin.test.Test + +class HelloTest { + @Test + fun test(): Unit = Hello().run { + hello() + internalFun() + } + + @Test + fun secondTest() = Unit + + @Test + fun thirdTest() = Unit + + internal fun internalTestFun() = 1 +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt index 0727c644899..c3d9fc54fbd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/Kapt3KotlinGradleSubplugin.kt @@ -403,7 +403,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin { kotlinCompilation?.run { output.apply { addClassesDir { project.files(classesOutputDir).builtBy(kaptTask) } - kotlinCompile.attachClassesDir { classesOutputDir } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt index 471d11cf07a..2b96d58b884 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/model/builder/KotlinModelBuilder.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.gradle.plugin.KOTLIN_JS_DSL_NAME import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.getConvention import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget +import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithTransitiveClosure import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile /** @@ -128,7 +129,9 @@ class KotlinModelBuilder(private val kotlinPluginVersion: String, private val an private fun AbstractKotlinCompile<*>.findFriendSourceSets(): Collection { val friendSourceSets = ArrayList() - friendTask?.sourceSetName?.let { friendSourceSets.add(it) } + taskData.compilation.associateWithTransitiveClosure.forEach { associateCompilation -> + friendSourceSets.add(associateCompilation.name) + } return friendSourceSets } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/TaskToFriendTaskMapper.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/TaskToFriendTaskMapper.kt deleted file mode 100644 index c105b4bcfdc..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/TaskToFriendTaskMapper.kt +++ /dev/null @@ -1,49 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.gradle.plugin - -import org.gradle.api.Task -import org.jetbrains.annotations.TestOnly - -internal abstract class TaskToFriendTaskMapper { - operator fun get(task: Task): String? = - getFriendByName(task.name) - - @TestOnly - operator fun get(name: String): String? = - getFriendByName(name) - - protected abstract fun getFriendByName(name: String): String? -} - -sealed internal class RegexTaskToFriendTaskMapper( - private val prefix: String, - suffix: String, - private val targetName: String, - private val postfixReplacement: String -) : TaskToFriendTaskMapper() { - class Default(targetName: String) : RegexTaskToFriendTaskMapper("compile", "TestKotlin", targetName, "Kotlin") - class Android(targetName: String) : RegexTaskToFriendTaskMapper("compile", "(Unit|Android)TestKotlin", targetName, "Kotlin") - - private val regex = "$prefix(.*)$suffix${targetName.capitalize()}".toRegex() - - override fun getFriendByName(name: String): String? { - val match = regex.matchEntire(name) ?: return null - val variant = match.groups[1]?.value ?: "" - return prefix + variant + postfixReplacement + targetName.capitalize() - } -} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt index 0975d9331a9..48b3275b053 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt @@ -192,6 +192,13 @@ abstract class AbstractKotlinCompilation( override fun toString(): String = "compilation '$compilationName' ($target)" + /** If a compilation is aware of its associate compilations' outputs being added to the classpath in a transformed or packaged way, + * it should point to those friend artifact files via this property. + * This is a workaround for Android variants that are compiled against + * JARs of each other, which is not exposed in the API in any other way than in the consumer's classpath. */ + internal open val friendArtifacts: FileCollection + get() = target.project.files() + override val moduleName: String get() = KotlinCompilationsModuleGroups.getModuleLeaderCompilation(this).takeIf { it != this }?.ownModuleName ?: ownModuleName diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt index 458e1f8c0f7..e36c8ccfcef 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/android/Android25ProjectHandler.kt @@ -75,12 +75,12 @@ class Android25ProjectHandler( } // Find the classpath entries that comes from the tested variant and register it as the friend path, lazily - kotlinTask.friendPaths = lazy { + compilation.testedVariantArtifacts.set(project.files(project.provider { variantData.getCompileClasspathArtifacts(preJavaClasspathKey) .filter { it.id.componentIdentifier is TestedComponentIdentifier } - .map { it.file.absolutePath } - .toTypedArray() - } + .map { it.file } + })) + kotlinTask.javaOutputDir = javaTask.destinationDir compilation.output.classesDirs.run { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt index cefa62bedff..fa16bb328d3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/jvm/KotlinJvmAndroidCompilation.kt @@ -7,7 +7,11 @@ package org.jetbrains.kotlin.gradle.plugin.mpp import com.android.build.gradle.api.BaseVariant +import org.gradle.api.file.FileCollection +import org.gradle.api.provider.Property import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.getTestedVariantData class KotlinJvmAndroidCompilation( target: KotlinAndroidTarget, @@ -19,6 +23,17 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile + @Suppress("UnstableApiUsage") + internal val testedVariantArtifacts: Property = target.project.objects.property(FileCollection::class.java) + + override val friendArtifacts: FileCollection get() = target.project.files(super.friendArtifacts, testedVariantArtifacts) + + override fun addAssociateCompilationDependencies(other: KotlinCompilation<*>) { + if ((other as? KotlinJvmAndroidCompilation)?.androidVariant != getTestedVariantData(androidVariant)) { + super.addAssociateCompilationDependencies(other) + } // otherwise, do nothing: the Android Gradle plugin adds these dependencies for us, we don't need to add them to the classpath + } + override val relatedConfigurationNames: List get() = super.relatedConfigurationNames + listOf( "${androidVariant.name}ApiElements", diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt index 38b8fe052c9..c8ad18f5dcd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilation.kt @@ -45,11 +45,24 @@ class KotlinNativeCompilation( // TODO: Move into the compilation task when the linking task does klib linking instead of compilation. internal val commonSources: ConfigurableFileCollection = project.files() + @Deprecated("Use associateWith(...) to add a friend compilation and associateWith to get all of them.") var friendCompilationName: String? = null + set(value) { + SingleWarningPerBuild.show( + project, + "Property `friendCompilationName` of `KotlinNativeCompilation` has been deprecated and will be removed. " + + "Use `associateWith(...)` instead." + ) + field = value + } - internal val friendCompilation: KotlinNativeCompilation? - get() = friendCompilationName?.let { - target.compilations.getByName(it) + internal val friendCompilations: List + get() = mutableListOf().apply { + @Suppress("DEPRECATION") + friendCompilationName?.let { + add(target.compilations.getByName(it)) + } + addAll(associateWithTransitiveClosure.filterIsInstance()) } // Native-specific DSL. diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt index aee2ea7b6c6..3d53cfb875f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeCompilationFactory.kt @@ -20,13 +20,9 @@ class KotlinNativeCompilationFactory( get() = KotlinNativeCompilation::class.java override fun create(name: String): KotlinNativeCompilation = - KotlinNativeCompilation(target, name).apply { - if (name == KotlinCompilation.TEST_COMPILATION_NAME) { - friendCompilationName = KotlinCompilation.MAIN_COMPILATION_NAME - } - // TODO: Validate compilation free args using the [CompilationFreeArgsValidator] - // when the compilation and the link args are separated (see KT-33717). - // Note: such validation should be done in the whenEvaluate block because - // a user can change args during project configuration. - } + // TODO: Validate compilation free args using the [CompilationFreeArgsValidator] + // when the compilation and the link args are separated (see KT-33717). + // Note: such validation should be done in the whenEvaluate block because + // a user can change args during project configuration. + KotlinNativeCompilation(target, name) } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 5066a19f393..c4287c5b0cc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -22,7 +22,6 @@ import org.jetbrains.kotlin.compilerRunner.konanVersion import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCompile -import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.mpp.* @@ -278,7 +277,9 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile().apply { - val friends = compilation.friendCompilation?.output?.allOutputs?.files - if (friends != null && friends.isNotEmpty()) { - addArg("-friend-modules", friends.joinToString(File.pathSeparator) { it.absolutePath }) + val friendCompilations = compilation.friendCompilations + val friendFiles = if (friendCompilations.isNotEmpty()) + project.files( + project.provider { friendCompilations.map { it.output.allOutputs } + compilation.friendArtifacts } + ) + else null + + if (friendFiles != null && !friendFiles.isEmpty) { + addArg("-friend-modules", friendFiles.joinToString(File.pathSeparator) { it.absolutePath }) } addAll(project.files(compilation.allSources).map { it.absolutePath }) diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt index cace59718bc..411ae10531b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/KotlinCompileCommon.kt @@ -55,7 +55,6 @@ open class KotlinCompileCommon : AbstractKotlinCompile() : AbstractKo ?: coroutinesFromGradleProperties ?: Coroutines.DEFAULT - @get:Internal - internal var friendTaskName: String? = null - @get:Internal internal var javaOutputDir: File? get() = taskData.javaOutputDir @@ -233,35 +230,14 @@ abstract class AbstractKotlinCompile() : AbstractKo internal val moduleName: String get() = taskData.compilation.moduleName - @Suppress("UNCHECKED_CAST") - @get:Internal - internal val friendTask: AbstractKotlinCompile? - get() = friendTaskName?.let { project.tasks.findByName(it) } as? AbstractKotlinCompile - - /** Classes directories that are not produced by this task but should be consumed by - * other tasks that have this one as a [friendTask]. */ - private val attachedClassesDirs: MutableList> = mutableListOf() - - /** Registers the directory provided by the [provider] as attached, meaning that the directory should - * be consumed as a friend classes directory by other tasks that have this task as a [friendTask]. */ - internal fun attachClassesDir(provider: () -> File?) { - attachedClassesDirs += lazy(provider) - } - @get:Internal // takes part in the compiler arguments - var friendPaths: Lazy?> = lazy { - friendTask?.let { friendTask -> - val possibleFriendDirs = ArrayList().apply { - add(friendTask.javaOutputDir) - add(friendTask.destinationDir) - addAll(friendTask.attachedClassesDirs.map { it.value }) - } - - possibleFriendDirs.filterNotNullTo(HashSet()) - .map { it.absolutePath } - .toTypedArray() + val friendPaths: Array + get() = taskData.compilation.run { + associateWithTransitiveClosure + .flatMap { it.output.classesDirs } + .plus(friendArtifacts) + .map { it.canonicalPath }.toTypedArray() } - } private val kotlinLogger by lazy { GradleKotlinLogger(logger) } @@ -404,7 +380,7 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl args.moduleName = taskData.compilation.moduleName logger.kotlinDebug { "args.moduleName = ${args.moduleName}" } - args.friendPaths = friendPaths.value + args.friendPaths = friendPaths logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" } if (defaultsOnly) return @@ -571,12 +547,11 @@ open class Kotlin2JsCompile : AbstractKotlinCompile(), Ko @get:InputFiles @get:Optional @get:PathSensitive(PathSensitivity.RELATIVE) - internal val friendDependency - get() = friendTaskName - ?.let { project.getTasksByName(it, false).singleOrNull() as? Kotlin2JsCompile } - ?.outputFile?.parentFile - ?.let { if (libraryFilter(it)) it else null } - ?.absolutePath + internal val friendDependencies: List + get() { + val filter = libraryFilter + return friendPaths.filter { filter(File(it)) } + } private val libraryFilter: (File) -> Boolean get() = if ("-Xir" in kotlinOptions.freeCompilerArgs) { @@ -601,13 +576,13 @@ open class Kotlin2JsCompile : AbstractKotlinCompile(), Ko .filter(libraryFilter) .map { it.canonicalPath } - args.libraries = (dependencies + listOfNotNull(friendDependency)).distinct().let { + args.libraries = (dependencies + friendDependencies).distinct().let { if (it.isNotEmpty()) it.joinToString(File.pathSeparator) else null } - args.friendModules = friendDependency + args.friendModules = friendDependencies.joinToString(File.pathSeparator) if (args.sourceMapBaseDirs == null && !args.sourceMapPrefix.isNullOrEmpty()) { args.sourceMapBaseDirs = project.projectDir.absolutePath diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt index 6ad69e3e0f3..228ebe11643 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/TasksProvider.kt @@ -122,10 +122,6 @@ internal open class KotlinTasksProvider(val targetName: String) { propertiesProvider: PropertiesProvider, compilation: AbstractKotlinCompilation<*> ) { - kotlinTaskHolder.configure { - it.friendTaskName = taskToFriendTaskMapper[it] - } - project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) { propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get()) @@ -136,17 +132,11 @@ internal open class KotlinTasksProvider(val targetName: String) { } } - protected open val taskToFriendTaskMapper: TaskToFriendTaskMapper = - RegexTaskToFriendTaskMapper.Default(targetName) - private inline fun taskOrWorkersTask(properties: PropertiesProvider): Class = if (properties.parallelTasksInProject != true) Task::class.java else WorkersTask::class.java } internal class AndroidTasksProvider(targetName: String) : KotlinTasksProvider(targetName) { - override val taskToFriendTaskMapper: TaskToFriendTaskMapper = - RegexTaskToFriendTaskMapper.Android(targetName) - override fun configure( kotlinTaskHolder: TaskProvider>, project: Project, diff --git a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/RegexTaskToFriendTaskMapperTest.kt b/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/RegexTaskToFriendTaskMapperTest.kt deleted file mode 100644 index c7b3cb1471d..00000000000 --- a/libraries/tools/kotlin-gradle-plugin/src/test/kotlin/org/jetbrains/kotlin/gradle/plugin/RegexTaskToFriendTaskMapperTest.kt +++ /dev/null @@ -1,69 +0,0 @@ -/* - * Copyright 2010-2016 JetBrains s.r.o. - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -package org.jetbrains.kotlin.gradle.plugin - -import org.junit.Assert -import org.junit.Test - -class RegexTaskToFriendTaskMapperTest { - @Test - fun getFriendTaskNameDefault() { - val mapper = RegexTaskToFriendTaskMapper.Default("") - Assert.assertEquals("compileKotlin", mapper["compileTestKotlin"]) - Assert.assertEquals(null, mapper["compileKotlin"]) - } - - @Test - fun getFriendTaskNameCustomTargetName() { - val mapper = RegexTaskToFriendTaskMapper.Default("Foo") - Assert.assertEquals("compileKotlinFoo", mapper["compileTestKotlinFoo"]) - Assert.assertEquals(null, mapper["compileKotlinFoo"]) - Assert.assertEquals(null, mapper["compileTestKotlinBar"]) - } - - @Test - fun getFriendTaskNameAndroid() { - val mapper = RegexTaskToFriendTaskMapper.Android("") - // Unit test examples - Assert.assertEquals("compileDebugKotlin", mapper["compileDebugUnitTestKotlin"]) - Assert.assertEquals("compileReleaseKotlin", mapper["compileReleaseUnitTestKotlin"]) - Assert.assertEquals("compileProdDebugKotlin", mapper["compileProdDebugUnitTestKotlin"]) - // Android test examples - Assert.assertEquals("compileDebugKotlin", mapper["compileDebugAndroidTestKotlin"]) - Assert.assertEquals("compileReleaseKotlin", mapper["compileReleaseAndroidTestKotlin"]) - Assert.assertEquals("compileProdDebugKotlin", mapper["compileProdDebugAndroidTestKotlin"]) - - Assert.assertEquals(null, mapper["compileDebugKotlin"]) - } - - @Test - fun getFriendTaskNameAndroidCustomTargetName() { - val mapper = RegexTaskToFriendTaskMapper.Android("Foo") - // Unit test examples - Assert.assertEquals("compileDebugKotlinFoo", mapper["compileDebugUnitTestKotlinFoo"]) - Assert.assertEquals("compileReleaseKotlinFoo", mapper["compileReleaseUnitTestKotlinFoo"]) - Assert.assertEquals("compileProdDebugKotlinFoo", mapper["compileProdDebugUnitTestKotlinFoo"]) - // Android test examples - Assert.assertEquals("compileDebugKotlinFoo", mapper["compileDebugAndroidTestKotlinFoo"]) - Assert.assertEquals("compileReleaseKotlinFoo", mapper["compileReleaseAndroidTestKotlinFoo"]) - Assert.assertEquals("compileProdDebugKotlinFoo", mapper["compileProdDebugAndroidTestKotlinFoo"]) - - Assert.assertEquals(null, mapper["compileDebugKotlinFoo"]) - Assert.assertEquals(null, mapper["compileDebugUnitTestKotlinBar"]) - Assert.assertEquals(null, mapper["compileDebugAndroidTestKotlinBar"]) - } -} \ No newline at end of file