Reimplement friend task/friend paths using associated compilations
Replace the old ad-hoc task matching mechanism used for connecting the compilation tasks that need to share internal visibility with an implementation based on the associate compilations and compilation outputs rather than `destinationDir`s of the tasks. The only place that still requires ad-hoc friend paths is the Android instrumented tests compiling against the JAR of the main variant, not its classes dirs. Support that with `friendArtifacts`. Issue #KT-17630 Fixed Issue #KT-20760 Fixed
This commit is contained in:
+27
@@ -2041,4 +2041,31 @@ class NewMultiplatformIT : BaseGradleIT() {
|
|||||||
assertNotContains(DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX)
|
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")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+1
-3
@@ -34,9 +34,7 @@ kotlin.target.compilations {
|
|||||||
|
|
||||||
val benchmark by creating {
|
val benchmark by creating {
|
||||||
defaultSourceSet.dependencies {
|
defaultSourceSet.dependencies {
|
||||||
implementation(main.compileDependencyFiles + main.output.allOutputs)
|
associateWith(main)
|
||||||
runtimeOnly(main.runtimeDependencyFiles)
|
|
||||||
|
|
||||||
implementation(kotlin("reflect"))
|
implementation(kotlin("reflect"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+1
@@ -3,6 +3,7 @@ package com.example
|
|||||||
fun main() {
|
fun main() {
|
||||||
val a = A()
|
val a = A()
|
||||||
val f = a::f
|
val f = a::f
|
||||||
|
internalFun()
|
||||||
f()
|
f()
|
||||||
println("${a::f.name} ran at the speed of light")
|
println("${a::f.name} ran at the speed of light")
|
||||||
}
|
}
|
||||||
+2
@@ -3,3 +3,5 @@ package com.example
|
|||||||
class A {
|
class A {
|
||||||
fun f(): String = "hello".also(::println)
|
fun f(): String = "hello".also(::println)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun internalFun() = 1
|
||||||
+56
@@ -0,0 +1,56 @@
|
|||||||
|
plugins {
|
||||||
|
id("org.jetbrains.kotlin.multiplatform").version("<pluginMarkerVersion>")
|
||||||
|
}
|
||||||
|
|
||||||
|
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"])
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+8
@@ -0,0 +1,8 @@
|
|||||||
|
pluginManagement {
|
||||||
|
repositories {
|
||||||
|
mavenLocal()
|
||||||
|
gradlePluginPortal()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rootProject.name = "new-mpp-associate-compilations"
|
||||||
+24
@@ -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
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
package com.example
|
||||||
|
|
||||||
|
class Hello {
|
||||||
|
fun hello() = 0
|
||||||
|
internal fun internalFun() = 1
|
||||||
|
}
|
||||||
+19
@@ -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
|
||||||
|
}
|
||||||
-1
@@ -403,7 +403,6 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
|
|||||||
kotlinCompilation?.run {
|
kotlinCompilation?.run {
|
||||||
output.apply {
|
output.apply {
|
||||||
addClassesDir { project.files(classesOutputDir).builtBy(kaptTask) }
|
addClassesDir { project.files(classesOutputDir).builtBy(kaptTask) }
|
||||||
kotlinCompile.attachClassesDir { classesOutputDir }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-1
@@ -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.KotlinSourceSet
|
||||||
import org.jetbrains.kotlin.gradle.plugin.getConvention
|
import org.jetbrains.kotlin.gradle.plugin.getConvention
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTarget
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithTransitiveClosure
|
||||||
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
|
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<String> {
|
private fun AbstractKotlinCompile<*>.findFriendSourceSets(): Collection<String> {
|
||||||
val friendSourceSets = ArrayList<String>()
|
val friendSourceSets = ArrayList<String>()
|
||||||
friendTask?.sourceSetName?.let { friendSourceSets.add(it) }
|
taskData.compilation.associateWithTransitiveClosure.forEach { associateCompilation ->
|
||||||
|
friendSourceSets.add(associateCompilation.name)
|
||||||
|
}
|
||||||
return friendSourceSets
|
return friendSourceSets
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-49
@@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
+7
@@ -192,6 +192,13 @@ abstract class AbstractKotlinCompilation<T : KotlinCommonOptions>(
|
|||||||
|
|
||||||
override fun toString(): String = "compilation '$compilationName' ($target)"
|
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
|
override val moduleName: String
|
||||||
get() = KotlinCompilationsModuleGroups.getModuleLeaderCompilation(this).takeIf { it != this }?.ownModuleName ?: ownModuleName
|
get() = KotlinCompilationsModuleGroups.getModuleLeaderCompilation(this).takeIf { it != this }?.ownModuleName ?: ownModuleName
|
||||||
|
|
||||||
|
|||||||
+4
-4
@@ -75,12 +75,12 @@ class Android25ProjectHandler(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find the classpath entries that comes from the tested variant and register it as the friend path, lazily
|
// 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)
|
variantData.getCompileClasspathArtifacts(preJavaClasspathKey)
|
||||||
.filter { it.id.componentIdentifier is TestedComponentIdentifier }
|
.filter { it.id.componentIdentifier is TestedComponentIdentifier }
|
||||||
.map { it.file.absolutePath }
|
.map { it.file }
|
||||||
.toTypedArray()
|
}))
|
||||||
}
|
|
||||||
kotlinTask.javaOutputDir = javaTask.destinationDir
|
kotlinTask.javaOutputDir = javaTask.destinationDir
|
||||||
|
|
||||||
compilation.output.classesDirs.run {
|
compilation.output.classesDirs.run {
|
||||||
|
|||||||
+15
@@ -7,7 +7,11 @@
|
|||||||
package org.jetbrains.kotlin.gradle.plugin.mpp
|
package org.jetbrains.kotlin.gradle.plugin.mpp
|
||||||
|
|
||||||
import com.android.build.gradle.api.BaseVariant
|
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.dsl.KotlinJvmOptions
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.getTestedVariantData
|
||||||
|
|
||||||
class KotlinJvmAndroidCompilation(
|
class KotlinJvmAndroidCompilation(
|
||||||
target: KotlinAndroidTarget,
|
target: KotlinAndroidTarget,
|
||||||
@@ -19,6 +23,17 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
|||||||
override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
override val compileKotlinTask: org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
get() = super.compileKotlinTask as org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
|
@Suppress("UnstableApiUsage")
|
||||||
|
internal val testedVariantArtifacts: Property<FileCollection> = 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<String>
|
override val relatedConfigurationNames: List<String>
|
||||||
get() = super.relatedConfigurationNames + listOf(
|
get() = super.relatedConfigurationNames + listOf(
|
||||||
"${androidVariant.name}ApiElements",
|
"${androidVariant.name}ApiElements",
|
||||||
|
|||||||
+16
-3
@@ -45,11 +45,24 @@ class KotlinNativeCompilation(
|
|||||||
// TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
|
// TODO: Move into the compilation task when the linking task does klib linking instead of compilation.
|
||||||
internal val commonSources: ConfigurableFileCollection = project.files()
|
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
|
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?
|
internal val friendCompilations: List<KotlinNativeCompilation>
|
||||||
get() = friendCompilationName?.let {
|
get() = mutableListOf<KotlinNativeCompilation>().apply {
|
||||||
target.compilations.getByName(it)
|
@Suppress("DEPRECATION")
|
||||||
|
friendCompilationName?.let {
|
||||||
|
add(target.compilations.getByName(it))
|
||||||
|
}
|
||||||
|
addAll(associateWithTransitiveClosure.filterIsInstance<KotlinNativeCompilation>())
|
||||||
}
|
}
|
||||||
|
|
||||||
// Native-specific DSL.
|
// Native-specific DSL.
|
||||||
|
|||||||
+5
-9
@@ -20,13 +20,9 @@ class KotlinNativeCompilationFactory(
|
|||||||
get() = KotlinNativeCompilation::class.java
|
get() = KotlinNativeCompilation::class.java
|
||||||
|
|
||||||
override fun create(name: String): KotlinNativeCompilation =
|
override fun create(name: String): KotlinNativeCompilation =
|
||||||
KotlinNativeCompilation(target, name).apply {
|
// TODO: Validate compilation free args using the [CompilationFreeArgsValidator]
|
||||||
if (name == KotlinCompilation.TEST_COMPILATION_NAME) {
|
// when the compilation and the link args are separated (see KT-33717).
|
||||||
friendCompilationName = KotlinCompilation.MAIN_COMPILATION_NAME
|
// 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]
|
KotlinNativeCompilation(target, name)
|
||||||
// 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.
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
+12
-5
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.compilerRunner.konanVersion
|
|||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions
|
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions
|
||||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
|
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.LanguageSettingsBuilder
|
||||||
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
import org.jetbrains.kotlin.gradle.plugin.mpp.*
|
||||||
@@ -278,7 +277,9 @@ open class KotlinNativeCompile : AbstractKotlinNativeCompile<KotlinCommonOptions
|
|||||||
get() = project.files(compilation.commonSources).asFileTree
|
get() = project.files(compilation.commonSources).asFileTree
|
||||||
|
|
||||||
private val friendModule: FileCollection?
|
private val friendModule: FileCollection?
|
||||||
get() = compilation.friendCompilation?.output?.allOutputs
|
get() = project.files(
|
||||||
|
project.provider { compilation.friendCompilations.map { it.output.allOutputs } + compilation.friendArtifacts }
|
||||||
|
)
|
||||||
// endregion.
|
// endregion.
|
||||||
|
|
||||||
// region Language settings imported from a SourceSet.
|
// region Language settings imported from a SourceSet.
|
||||||
@@ -543,9 +544,15 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile<KotlinCommonToolOption
|
|||||||
// Allow a user to force the old behaviour of a link task.
|
// Allow a user to force the old behaviour of a link task.
|
||||||
// TODO: Remove in 1.3.70.
|
// TODO: Remove in 1.3.70.
|
||||||
mutableListOf<String>().apply {
|
mutableListOf<String>().apply {
|
||||||
val friends = compilation.friendCompilation?.output?.allOutputs?.files
|
val friendCompilations = compilation.friendCompilations
|
||||||
if (friends != null && friends.isNotEmpty()) {
|
val friendFiles = if (friendCompilations.isNotEmpty())
|
||||||
addArg("-friend-modules", friends.joinToString(File.pathSeparator) { it.absolutePath })
|
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 })
|
addAll(project.files(compilation.allSources).map { it.absolutePath })
|
||||||
|
|||||||
-1
@@ -55,7 +55,6 @@ open class KotlinCompileCommon : AbstractKotlinCompile<K2MetadataCompilerArgumen
|
|||||||
if (defaultsOnly) return
|
if (defaultsOnly) return
|
||||||
|
|
||||||
val classpathList = classpath.files.toMutableList()
|
val classpathList = classpath.files.toMutableList()
|
||||||
friendTask?.let { classpathList.add(it.destinationDir) }
|
|
||||||
|
|
||||||
with(args) {
|
with(args) {
|
||||||
classpath = classpathList.joinToString(File.pathSeparator)
|
classpath = classpathList.joinToString(File.pathSeparator)
|
||||||
|
|||||||
+14
-39
@@ -213,9 +213,6 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
|||||||
?: coroutinesFromGradleProperties
|
?: coroutinesFromGradleProperties
|
||||||
?: Coroutines.DEFAULT
|
?: Coroutines.DEFAULT
|
||||||
|
|
||||||
@get:Internal
|
|
||||||
internal var friendTaskName: String? = null
|
|
||||||
|
|
||||||
@get:Internal
|
@get:Internal
|
||||||
internal var javaOutputDir: File?
|
internal var javaOutputDir: File?
|
||||||
get() = taskData.javaOutputDir
|
get() = taskData.javaOutputDir
|
||||||
@@ -233,35 +230,14 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
|
|||||||
internal val moduleName: String
|
internal val moduleName: String
|
||||||
get() = taskData.compilation.moduleName
|
get() = taskData.compilation.moduleName
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
|
||||||
@get:Internal
|
|
||||||
internal val friendTask: AbstractKotlinCompile<T>?
|
|
||||||
get() = friendTaskName?.let { project.tasks.findByName(it) } as? AbstractKotlinCompile<T>
|
|
||||||
|
|
||||||
/** 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<Lazy<File?>> = 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
|
@get:Internal // takes part in the compiler arguments
|
||||||
var friendPaths: Lazy<Array<String>?> = lazy {
|
val friendPaths: Array<String>
|
||||||
friendTask?.let { friendTask ->
|
get() = taskData.compilation.run {
|
||||||
val possibleFriendDirs = ArrayList<File?>().apply {
|
associateWithTransitiveClosure
|
||||||
add(friendTask.javaOutputDir)
|
.flatMap { it.output.classesDirs }
|
||||||
add(friendTask.destinationDir)
|
.plus(friendArtifacts)
|
||||||
addAll(friendTask.attachedClassesDirs.map { it.value })
|
.map { it.canonicalPath }.toTypedArray()
|
||||||
}
|
|
||||||
|
|
||||||
possibleFriendDirs.filterNotNullTo(HashSet())
|
|
||||||
.map { it.absolutePath }
|
|
||||||
.toTypedArray()
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
|
private val kotlinLogger by lazy { GradleKotlinLogger(logger) }
|
||||||
|
|
||||||
@@ -404,7 +380,7 @@ open class KotlinCompile : AbstractKotlinCompile<K2JVMCompilerArguments>(), Kotl
|
|||||||
args.moduleName = taskData.compilation.moduleName
|
args.moduleName = taskData.compilation.moduleName
|
||||||
logger.kotlinDebug { "args.moduleName = ${args.moduleName}" }
|
logger.kotlinDebug { "args.moduleName = ${args.moduleName}" }
|
||||||
|
|
||||||
args.friendPaths = friendPaths.value
|
args.friendPaths = friendPaths
|
||||||
logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" }
|
logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" }
|
||||||
|
|
||||||
if (defaultsOnly) return
|
if (defaultsOnly) return
|
||||||
@@ -571,12 +547,11 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
|
|||||||
@get:InputFiles
|
@get:InputFiles
|
||||||
@get:Optional
|
@get:Optional
|
||||||
@get:PathSensitive(PathSensitivity.RELATIVE)
|
@get:PathSensitive(PathSensitivity.RELATIVE)
|
||||||
internal val friendDependency
|
internal val friendDependencies: List<String>
|
||||||
get() = friendTaskName
|
get() {
|
||||||
?.let { project.getTasksByName(it, false).singleOrNull() as? Kotlin2JsCompile }
|
val filter = libraryFilter
|
||||||
?.outputFile?.parentFile
|
return friendPaths.filter { filter(File(it)) }
|
||||||
?.let { if (libraryFilter(it)) it else null }
|
}
|
||||||
?.absolutePath
|
|
||||||
|
|
||||||
private val libraryFilter: (File) -> Boolean
|
private val libraryFilter: (File) -> Boolean
|
||||||
get() = if ("-Xir" in kotlinOptions.freeCompilerArgs) {
|
get() = if ("-Xir" in kotlinOptions.freeCompilerArgs) {
|
||||||
@@ -601,13 +576,13 @@ open class Kotlin2JsCompile : AbstractKotlinCompile<K2JSCompilerArguments>(), Ko
|
|||||||
.filter(libraryFilter)
|
.filter(libraryFilter)
|
||||||
.map { it.canonicalPath }
|
.map { it.canonicalPath }
|
||||||
|
|
||||||
args.libraries = (dependencies + listOfNotNull(friendDependency)).distinct().let {
|
args.libraries = (dependencies + friendDependencies).distinct().let {
|
||||||
if (it.isNotEmpty())
|
if (it.isNotEmpty())
|
||||||
it.joinToString(File.pathSeparator) else
|
it.joinToString(File.pathSeparator) else
|
||||||
null
|
null
|
||||||
}
|
}
|
||||||
|
|
||||||
args.friendModules = friendDependency
|
args.friendModules = friendDependencies.joinToString(File.pathSeparator)
|
||||||
|
|
||||||
if (args.sourceMapBaseDirs == null && !args.sourceMapPrefix.isNullOrEmpty()) {
|
if (args.sourceMapBaseDirs == null && !args.sourceMapPrefix.isNullOrEmpty()) {
|
||||||
args.sourceMapBaseDirs = project.projectDir.absolutePath
|
args.sourceMapBaseDirs = project.projectDir.absolutePath
|
||||||
|
|||||||
-10
@@ -122,10 +122,6 @@ internal open class KotlinTasksProvider(val targetName: String) {
|
|||||||
propertiesProvider: PropertiesProvider,
|
propertiesProvider: PropertiesProvider,
|
||||||
compilation: AbstractKotlinCompilation<*>
|
compilation: AbstractKotlinCompilation<*>
|
||||||
) {
|
) {
|
||||||
kotlinTaskHolder.configure {
|
|
||||||
it.friendTaskName = taskToFriendTaskMapper[it]
|
|
||||||
}
|
|
||||||
|
|
||||||
project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) {
|
project.runOnceAfterEvaluated("apply properties and language settings to ${kotlinTaskHolder.name}", kotlinTaskHolder) {
|
||||||
propertiesProvider.mapKotlinTaskProperties(kotlinTaskHolder.get())
|
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 <reified Task, reified WorkersTask : Task> taskOrWorkersTask(properties: PropertiesProvider): Class<out Task> =
|
private inline fun <reified Task, reified WorkersTask : Task> taskOrWorkersTask(properties: PropertiesProvider): Class<out Task> =
|
||||||
if (properties.parallelTasksInProject != true) Task::class.java else WorkersTask::class.java
|
if (properties.parallelTasksInProject != true) Task::class.java else WorkersTask::class.java
|
||||||
}
|
}
|
||||||
|
|
||||||
internal class AndroidTasksProvider(targetName: String) : KotlinTasksProvider(targetName) {
|
internal class AndroidTasksProvider(targetName: String) : KotlinTasksProvider(targetName) {
|
||||||
override val taskToFriendTaskMapper: TaskToFriendTaskMapper =
|
|
||||||
RegexTaskToFriendTaskMapper.Android(targetName)
|
|
||||||
|
|
||||||
override fun configure(
|
override fun configure(
|
||||||
kotlinTaskHolder: TaskProvider<out AbstractKotlinCompile<*>>,
|
kotlinTaskHolder: TaskProvider<out AbstractKotlinCompile<*>>,
|
||||||
project: Project,
|
project: Project,
|
||||||
|
|||||||
-69
@@ -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"])
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Reference in New Issue
Block a user