[Gradle] Introduce defaultFragmentName for K2 MPP Structure
It is possible to add source files to task directly. Especially this is a very popular case for Android integration. Android variants can contain any number of extra-source files that should be compiled together with other android-specific sources. Android specific sources that come from Android source sets already compiled together as part of "main" fragment (KT-62508). With this change this logic is extended to any extra sources that are added directly to the compile task. ^KT-62508 Verification Pending
This commit is contained in:
committed by
Space Team
parent
020bb72d2b
commit
7a150cce47
+9
@@ -27,11 +27,13 @@ import org.gradle.work.Incremental
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsDefault
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsHelper
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.create
|
||||
import org.jetbrains.kotlin.gradle.report.BuildReportMode
|
||||
import org.jetbrains.kotlin.gradle.tasks.K2MultiplatformStructure
|
||||
import org.jetbrains.kotlin.gradle.tasks.KaptGenerateStubs
|
||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||
import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions
|
||||
@@ -59,6 +61,13 @@ abstract class KaptGenerateStubsTask @Inject constructor(
|
||||
@get:Internal
|
||||
abstract override val libraries: ConfigurableFileCollection
|
||||
|
||||
/**
|
||||
* [K2MultiplatformStructure] is not required for Kapt stubs
|
||||
*/
|
||||
@InternalKotlinGradlePluginApi
|
||||
@get:Internal
|
||||
override val multiplatformStructure: K2MultiplatformStructure get() = super.multiplatformStructure
|
||||
|
||||
/* Used as input as empty kapt classpath should not trigger stub generation, but a non-empty one should. */
|
||||
@Input
|
||||
fun getIfKaptClasspathIsPresent() = !kaptClasspath.isEmpty
|
||||
|
||||
+2
@@ -51,6 +51,8 @@ internal object KotlinCompilationK2MultiplatformConfigurator : KotlinCompilation
|
||||
K2MultiplatformStructure.Fragment(fragmentName, sourceFiles.reduce { acc, fileTree -> acc + fileTree })
|
||||
}
|
||||
})
|
||||
|
||||
compileTask.multiplatformStructure.defaultFragmentName.set(compilation.defaultSourceSet.fragmentName())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+9
@@ -14,6 +14,7 @@ import org.gradle.api.tasks.*
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
|
||||
import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompilerOptionsDefault
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.ContributeCompilerArgumentsContext
|
||||
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
|
||||
@@ -21,6 +22,7 @@ import org.jetbrains.kotlin.gradle.plugin.statistics.CompileKotlinJsIrLinkMetric
|
||||
import org.jetbrains.kotlin.gradle.plugin.statistics.UsesBuildFusService
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode
|
||||
import org.jetbrains.kotlin.gradle.targets.js.dsl.KotlinJsBinaryMode.DEVELOPMENT
|
||||
import org.jetbrains.kotlin.gradle.tasks.K2MultiplatformStructure
|
||||
import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile
|
||||
import org.jetbrains.kotlin.gradle.utils.configureExperimentalTryNext
|
||||
import javax.inject.Inject
|
||||
@@ -44,6 +46,13 @@ abstract class KotlinJsIrLink @Inject constructor(
|
||||
@get:Internal
|
||||
override val sources: FileCollection = super.sources
|
||||
|
||||
/**
|
||||
* [K2MultiplatformStructure] is not required for JS IR link
|
||||
*/
|
||||
@InternalKotlinGradlePluginApi
|
||||
@get:Internal
|
||||
override val multiplatformStructure: K2MultiplatformStructure get() = super.multiplatformStructure
|
||||
|
||||
override fun skipCondition(): Boolean {
|
||||
return !entryModule.get().asFile.exists()
|
||||
}
|
||||
|
||||
+1
-1
@@ -500,7 +500,7 @@ internal constructor(
|
||||
sources { args ->
|
||||
/* Shared native compilations in K2 still use -Xcommon-sources and klib dependencies */
|
||||
if (compilerOptions.usesK2.get() && sharedCompilationData == null) {
|
||||
args.fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs(sourceFileFilter)
|
||||
args.fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs(sources.files, sourceFileFilter)
|
||||
} else {
|
||||
args.commonSources = commonSourcesTree.files.takeIf { it.isNotEmpty() }?.toPathsArray()
|
||||
}
|
||||
|
||||
+37
-4
@@ -7,12 +7,14 @@ package org.jetbrains.kotlin.gradle.tasks
|
||||
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.provider.ListProperty
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.SetProperty
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.api.tasks.util.PatternFilterable
|
||||
import org.gradle.work.Incremental
|
||||
import org.gradle.work.NormalizeLineEndings
|
||||
import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
|
||||
import java.io.File
|
||||
|
||||
@InternalKotlinGradlePluginApi
|
||||
abstract class K2MultiplatformStructure {
|
||||
@@ -43,17 +45,48 @@ abstract class K2MultiplatformStructure {
|
||||
|
||||
@get:Nested
|
||||
abstract val fragments: ListProperty<Fragment>
|
||||
|
||||
/**
|
||||
* If new sources were added to the Compile Task,
|
||||
* and they weren't mapped to any of the fragments then [defaultFragmentName] will be used
|
||||
*
|
||||
* It is marked with @Optional as an extra protection measure for cases when some task extends
|
||||
* a compile task but doesn't need K2 Structure for example [KotlinJsIrLink]
|
||||
*
|
||||
* @see KotlinCompileTool.source
|
||||
*/
|
||||
@get:Input
|
||||
@get:Optional
|
||||
abstract val defaultFragmentName: Property<String>
|
||||
}
|
||||
|
||||
internal val K2MultiplatformStructure.fragmentsCompilerArgs: Array<String>
|
||||
get() = fragments.get().map { it.fragmentName }.toSet().toTypedArray()
|
||||
|
||||
internal fun K2MultiplatformStructure.fragmentSourcesCompilerArgs(sourceFileFilter: PatternFilterable? = null): Array<String> =
|
||||
fragments.get().flatMap { sourceSet ->
|
||||
private fun fragmentSourceCompilerArg(sourceFile: File, fragmentName: String) = "$fragmentName:${sourceFile.absolutePath}"
|
||||
|
||||
internal fun K2MultiplatformStructure.fragmentSourcesCompilerArgs(
|
||||
allSources: Collection<File>,
|
||||
sourceFileFilter: PatternFilterable? = null
|
||||
): Array<String> {
|
||||
val sourcesWithKnownFragment = mutableSetOf<File>()
|
||||
val fragmentSourcesCompilerArgs = fragments.get().flatMap { sourceSet ->
|
||||
sourceSet.sources
|
||||
.run { if (sourceFileFilter != null) asFileTree.matching(sourceFileFilter) else this }
|
||||
.files.map { sourceFile -> "${sourceSet.fragmentName}:${sourceFile.absolutePath}" }
|
||||
}.toTypedArray()
|
||||
.files.map { sourceFile ->
|
||||
sourcesWithKnownFragment.add(sourceFile)
|
||||
fragmentSourceCompilerArg(sourceFile, sourceSet.fragmentName)
|
||||
}
|
||||
}.toMutableList()
|
||||
|
||||
val sourcesWithUnknownFragment = allSources - sourcesWithKnownFragment
|
||||
val defaultFragmentName = defaultFragmentName.orNull
|
||||
if (defaultFragmentName != null) {
|
||||
sourcesWithUnknownFragment.mapTo(fragmentSourcesCompilerArgs) { fragmentSourceCompilerArg(it, defaultFragmentName) }
|
||||
}
|
||||
|
||||
return fragmentSourcesCompilerArgs.toTypedArray()
|
||||
}
|
||||
|
||||
internal val K2MultiplatformStructure.fragmentRefinesCompilerArgs: Array<String>
|
||||
get() = refinesEdges.get().map { edge ->
|
||||
|
||||
+1
-1
@@ -178,7 +178,7 @@ abstract class Kotlin2JsCompile @Inject constructor(
|
||||
|
||||
if (multiPlatformEnabled.get()) {
|
||||
if (compilerOptions.usesK2.get()) {
|
||||
args.fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs(sourceFileFilter)
|
||||
args.fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs(sources.files, sourceFileFilter)
|
||||
} else {
|
||||
args.commonSources = commonSourceSet.asFileTree.toPathsArray()
|
||||
}
|
||||
|
||||
+5
-5
@@ -263,18 +263,18 @@ abstract class KotlinCompile @Inject constructor(
|
||||
}
|
||||
|
||||
sources { args ->
|
||||
val sourcesFiles = sources.asFileTree.files.toList()
|
||||
val javaSourcesFiles = javaSources.files.toList()
|
||||
val scriptSourcesFiles = scriptSources.asFileTree.files.toList()
|
||||
|
||||
if (multiPlatformEnabled.get()) {
|
||||
if (compilerOptions.usesK2.get()) {
|
||||
args.fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs(sourceFileFilter)
|
||||
args.fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs(sourcesFiles, sourceFileFilter)
|
||||
} else {
|
||||
args.commonSources = commonSourceSet.asFileTree.toPathsArray()
|
||||
}
|
||||
}
|
||||
|
||||
val sourcesFiles = sources.asFileTree.files.toList()
|
||||
val javaSourcesFiles = javaSources.files.toList()
|
||||
val scriptSourcesFiles = scriptSources.asFileTree.files.toList()
|
||||
|
||||
if (logger.isInfoEnabled) {
|
||||
logger.info("Kotlin source files: ${sourcesFiles.joinToString()}")
|
||||
logger.info("Java source files: ${javaSourcesFiles.joinToString()}")
|
||||
|
||||
+53
-1
@@ -7,21 +7,25 @@
|
||||
|
||||
package org.jetbrains.kotlin.gradle.unitTests
|
||||
|
||||
import org.gradle.kotlin.dsl.get
|
||||
import org.gradle.kotlin.dsl.newInstance
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
|
||||
import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments
|
||||
import org.jetbrains.kotlin.compilerRunner.ArgumentUtils
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinVersion
|
||||
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
|
||||
import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAware
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilerArgumentsProducer.CreateCompilerArgumentsContext.Companion.lenient
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinJsCompilerType.IR
|
||||
import org.jetbrains.kotlin.gradle.plugin.mpp.disambiguateName
|
||||
import org.jetbrains.kotlin.gradle.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.tasks.K2MultiplatformStructure.Fragment
|
||||
import org.jetbrains.kotlin.gradle.tasks.K2MultiplatformStructure.RefinesEdge
|
||||
import org.jetbrains.kotlin.gradle.util.*
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertEquals
|
||||
import kotlin.test.assertNull
|
||||
@@ -46,6 +50,7 @@ class K2MultiplatformStructureTest {
|
||||
Fragment("c", project.files())
|
||||
)
|
||||
)
|
||||
structure.defaultFragmentName.set("a")
|
||||
|
||||
val sourceArguments = K2JVMCompilerArguments()
|
||||
sourceArguments.configureK2Multiplatform(structure)
|
||||
@@ -98,6 +103,53 @@ class K2MultiplatformStructureTest {
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `test - extra sources that were added to compile task directly is included into default source set fragment`() {
|
||||
val targets = listOf(kotlin.jvm(), kotlin.js(), kotlin.linuxX64())
|
||||
kotlin.writeSource("commonMain")
|
||||
kotlin.writeSource("jvmMain")
|
||||
kotlin.writeSource("linuxX64Main")
|
||||
kotlin.writeSource("jsMain")
|
||||
|
||||
// Add extra source file
|
||||
targets.forEach { target ->
|
||||
val compileTask = target.compilations.get("main").compileTaskProvider.get() as KotlinCompileTool
|
||||
val extraSourceFile = project.file("${target.disambiguateName("generated")}.kt").also {
|
||||
it.parentFile.mkdirs()
|
||||
it.writeText("fun generated() {}")
|
||||
}
|
||||
compileTask.source(extraSourceFile)
|
||||
}
|
||||
|
||||
project.evaluate()
|
||||
|
||||
val actualFragmentSources = targets.associate { target ->
|
||||
val compileTask = target.compilations.get("main").compileTaskProvider.get() as K2MultiplatformCompilationTask
|
||||
val args = compileTask.buildCompilerArguments()
|
||||
|
||||
target.name to args.fragmentSources?.toList().orEmpty().map {
|
||||
val fragment = it.substringBefore(":")
|
||||
val filePath = it.substringAfter(":")
|
||||
"$fragment:${File(filePath).name}"
|
||||
}
|
||||
}
|
||||
|
||||
assertEquals(
|
||||
mapOf(
|
||||
"jvm" to listOf("jvmMain:jvmMain.kt", "commonMain:commonMain.kt", "jvmMain:jvmGenerated.kt"),
|
||||
"js" to listOf("jsMain:jsMain.kt", "commonMain:commonMain.kt", "jsMain:jsGenerated.kt"),
|
||||
"linuxX64" to listOf("linuxX64Main:linuxX64Main.kt", "commonMain:commonMain.kt", "linuxX64Main:linuxX64Generated.kt"),
|
||||
),
|
||||
actualFragmentSources
|
||||
)
|
||||
}
|
||||
|
||||
private fun KotlinMultiplatformExtension.writeSource(sourceSet: String, fileName: String = "${sourceSet}.kt") {
|
||||
val srcDir = sourceSets.maybeCreate(sourceSet).kotlin.srcDirs.first()
|
||||
srcDir.mkdirs()
|
||||
srcDir.resolve(fileName).writeText("""fun $sourceSet() {}""")
|
||||
}
|
||||
|
||||
private fun `test compilations multiplatformStructure configuration`(compilation: KotlinCompilation<*>) {
|
||||
val defaultSourceSet = compilation.defaultSourceSet
|
||||
/* Create an additional intermediate source set for testing */
|
||||
@@ -172,6 +224,6 @@ private fun K2MultiplatformCompilationTask.buildCompilerArguments(): CommonCompi
|
||||
|
||||
internal fun CommonCompilerArguments.configureK2Multiplatform(multiplatformStructure: K2MultiplatformStructure) {
|
||||
fragments = multiplatformStructure.fragmentsCompilerArgs
|
||||
fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs()
|
||||
fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs(emptyList())
|
||||
fragmentRefines = multiplatformStructure.fragmentRefinesCompilerArgs
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user