diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt index e2fca4a23c7..ead9b0fc2bc 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/GradleKotlinCompilerRunner.kt @@ -78,7 +78,6 @@ internal open class GradleCompilerRunner( */ fun runJvmCompilerAsync( sourcesToCompile: List, - commonSources: List, javaPackagePrefix: String?, args: K2JVMCompilerArguments, environment: GradleCompilerEnvironment, @@ -86,7 +85,6 @@ internal open class GradleCompilerRunner( taskOutputsBackup: TaskOutputsBackup? ): WorkQueue? { args.freeArgs += sourcesToCompile.map { it.absolutePath } - args.commonSources = commonSources.map { it.absolutePath }.toTypedArray() args.javaPackagePrefix = javaPackagePrefix if (args.jdkHome == null && !args.noJdk) args.jdkHome = jdkHome.absolutePath loggerProvider.kotlinInfo("Kotlin compilation 'jdkHome' argument: ${args.jdkHome}") @@ -99,13 +97,11 @@ internal open class GradleCompilerRunner( */ fun runJsCompilerAsync( kotlinSources: List, - kotlinCommonSources: List, args: K2JSCompilerArguments, environment: GradleCompilerEnvironment, taskOutputsBackup: TaskOutputsBackup? ): WorkQueue? { args.freeArgs += kotlinSources.map { it.absolutePath } - args.commonSources = kotlinCommonSources.map { it.absolutePath }.toTypedArray() return runCompilerAsync(KotlinCompilerClass.JS, args, environment, taskOutputsBackup) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinCommonCompilerOptionsExtensions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinCommonCompilerOptionsExtensions.kt new file mode 100644 index 00000000000..e48f5689fcd --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/dsl/KotlinCommonCompilerOptionsExtensions.kt @@ -0,0 +1,13 @@ +/* + * 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.dsl + +import org.gradle.api.provider.Provider + +internal val KotlinCommonCompilerOptions.usesK2: Provider + get() = this.languageVersion + .orElse(KotlinVersion.DEFAULT) + .map { version -> version >= KotlinVersion.KOTLIN_2_0 } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationK2MultiplatformConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationK2MultiplatformConfigurator.kt new file mode 100644 index 00000000000..3aa126f1c79 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationK2MultiplatformConfigurator.kt @@ -0,0 +1,32 @@ +/* + * 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.plugin.mpp.compilationImpl + +import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory +import org.jetbrains.kotlin.gradle.tasks.K2Compile +import org.jetbrains.kotlin.gradle.tasks.K2MultiplatformStructure + +internal object KotlinCompilationK2MultiplatformConfigurator : KotlinCompilationImplFactory.PreConfigure { + override fun configure(compilation: KotlinCompilationImpl) { + compilation.project.tasks.matching { it.name == compilation.compileKotlinTaskName }.configureEach { compileTask -> + if (compileTask !is K2Compile) return@configureEach + + compileTask.multiplatformStructure.dependsOnEdges.set(compilation.project.provider { + compilation.allKotlinSourceSets.flatMap { sourceSet -> + sourceSet.dependsOn.map { dependsOn -> + K2MultiplatformStructure.DependsOnEdge(sourceSet.name, dependsOn.name) + } + } + }) + + compileTask.multiplatformStructure.fragments.set(compilation.project.provider { + compilation.allKotlinSourceSets.map { sourceSet -> + K2MultiplatformStructure.Fragment(sourceSet.name, sourceSet.kotlin.asFileTree) + } + }) + } + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationImplFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationImplFactory.kt index 2141f53fd1a..66c9b576b72 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationImplFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/factory/KotlinCompilationImplFactory.kt @@ -42,7 +42,7 @@ internal class KotlinCompilationImplFactory( DefaultProcessResourcesTaskNameFactory, private val preConfigureAction: PreConfigure = - EmptyPreConfigure, + KotlinCompilationK2MultiplatformConfigurator, private val postConfigureAction: PostConfigure = DefaultKotlinCompilationPostConfigure diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeCompilerArgBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeCompilerArgBuilder.kt index 4eade97b7d0..2f013a9a73c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeCompilerArgBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeCompilerArgBuilder.kt @@ -10,8 +10,11 @@ import org.gradle.api.file.FileTree import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerToolOptions import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions +import org.jetbrains.kotlin.gradle.dsl.usesK2 import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode -import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions +import org.jetbrains.kotlin.gradle.tasks.* +import org.jetbrains.kotlin.gradle.tasks.fragmentSourcesCompilerArgs +import org.jetbrains.kotlin.gradle.tasks.fragmentsCompilerArgs import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.project.model.LanguageSettings @@ -46,7 +49,8 @@ internal fun buildKotlinNativeKlibCompilerArgs( libraryVersion: String, sharedCompilationData: SharedCompilationData?, source: FileTree, - commonSourcesTree: FileTree + commonSourcesTree: FileTree, + k2MultiplatformCompilationData: K2MultiplatformStructure ): List = mutableListOf().apply { addAll(buildKotlinNativeMainArgs(outFile, optimized, debuggable, target, CompilerOutputKind.LIBRARY, libraries)) @@ -76,10 +80,23 @@ internal fun buildKotlinNativeKlibCompilerArgs( } } + if (compilerOptions.usesK2.get()) { + /* + For now, we only pass multiplatform structure to K2 for platform compilations + Metadata compilations will compile against pre-compiled klibs from their dependsOn + */ + if (sharedCompilationData == null) { + add("-Xfragments=${k2MultiplatformCompilationData.fragmentsCompilerArgs.joinToString(",")}") + add("-Xfragment-sources=${k2MultiplatformCompilationData.fragmentSourcesCompilerArgs.joinToString(",")}") + add("-Xdepends-on=${k2MultiplatformCompilationData.dependsOnCompilerArgs.joinToString(",")}") + } + } + addAll(buildKotlinNativeCompileCommonArgs(languageSettings, compilerOptions, compilerPlugins)) addAll(source.map { it.absolutePath }) - if (!commonSourcesTree.isEmpty) { + + if (!compilerOptions.usesK2.get() && !commonSourcesTree.isEmpty) { add("-Xcommon-sources=${commonSourcesTree.joinToString(separator = ",") { it.absolutePath }}") } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index fcdae637a64..c1b2be732ef 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -37,7 +37,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmMetadataCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmNativeCompilationData import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder -import org.jetbrains.kotlin.gradle.plugin.tcsOrNull import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer import org.jetbrains.kotlin.gradle.targets.native.tasks.* @@ -314,6 +313,7 @@ internal constructor( private val execOperations: ExecOperations ) : AbstractKotlinNativeCompile(objectFactory), KotlinCompile, + K2Compile, KotlinCompilationTask { @get:Input @@ -354,6 +354,9 @@ internal constructor( @get:Internal // these sources are normally a subset of `source` ones which are already tracked val commonSources: ConfigurableFileCollection = project.files() + @get:Nested + override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance() + private val commonSourcesTree: FileTree get() = commonSources.asFileTree @@ -454,33 +457,33 @@ internal constructor( return SharedCompilationData(manifestFile, isAllowCommonizer, refinesModule) } + internal fun buildKotlinNativeKlibCompilerArgs(): List = buildKotlinNativeKlibCompilerArgs( + outFile = outputFile.get(), + optimized = optimized, + debuggable = debuggable, + target = konanTarget, + libraries = libraries.files.filterKlibsPassedToCompiler(), + languageSettings = languageSettings, + compilerOptions = compilerOptions, + compilerPlugins = listOfNotNull( + compilerPluginClasspath?.let { CompilerPluginData(it, compilerPluginOptions) }, + kotlinPluginData?.orNull?.let { CompilerPluginData(it.classpath, it.options) } + ), + shortModuleName = shortModuleName, + friendModule = friendModule, + libraryVersion = artifactVersion, + sharedCompilationData = createSharedCompilationDataOrNull(), + source = sources.asFileTree, + commonSourcesTree = commonSourcesTree, + k2MultiplatformCompilationData = multiplatformStructure + ) @TaskAction fun compile() { val output = outputFile.get() output.parentFile.mkdirs() - val plugins = listOfNotNull( - compilerPluginClasspath?.let { CompilerPluginData(it, compilerPluginOptions) }, - kotlinPluginData?.orNull?.let { CompilerPluginData(it.classpath, it.options) } - ) - - val buildArgs = buildKotlinNativeKlibCompilerArgs( - output, - optimized, - debuggable, - konanTarget, - libraries.files.filterKlibsPassedToCompiler(), - languageSettings, - compilerOptions, - plugins, - shortModuleName, - friendModule, - artifactVersion, - createSharedCompilationDataOrNull(), - sources.asFileTree, - commonSourcesTree - ) + val buildArgs = buildKotlinNativeKlibCompilerArgs() KotlinNativeCompilerRunner( settings = runnerSettings, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/K2Compile.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/K2Compile.kt new file mode 100644 index 00000000000..5bd5e19977d --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/K2Compile.kt @@ -0,0 +1,25 @@ +/* + * 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.tasks + +import org.gradle.api.Task +import org.gradle.api.tasks.Internal +import org.gradle.api.tasks.Nested +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinCompile + +/** + * Analogous to [KotlinCompile] for K2 + * This does not extend [KotlinCompile], since [KotlinCompile] carries an unwanted/conflicting + * type parameter `` + */ +internal interface K2Compile : Task { + @get:Internal + val kotlinOptions: KotlinCommonOptions + + @get:Nested + val multiplatformStructure: K2MultiplatformStructure +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/K2MultiplatformStructure.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/K2MultiplatformStructure.kt new file mode 100644 index 00000000000..1c094f8cf0a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/K2MultiplatformStructure.kt @@ -0,0 +1,79 @@ +/* + * 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.tasks + +import org.gradle.api.file.FileCollection +import org.gradle.api.provider.ListProperty +import org.gradle.api.provider.SetProperty +import org.gradle.api.tasks.* +import org.gradle.work.Incremental +import org.gradle.work.NormalizeLineEndings +import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments +import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions +import org.jetbrains.kotlin.gradle.dsl.usesK2 + +@InternalKotlinGradlePluginApi +abstract class K2MultiplatformStructure { + + @InternalKotlinGradlePluginApi + data class DependsOnEdge( + @Input + val fromFragmentName: String, + @Input + val toFragmentName: String + ) + + @InternalKotlinGradlePluginApi + data class Fragment( + @Input + val fragmentName: String, + + @get:InputFiles + @get:IgnoreEmptyDirectories + @get:Incremental + @get:NormalizeLineEndings + @get:PathSensitive(PathSensitivity.RELATIVE) + val sources: FileCollection + ) + + @get:Nested + abstract val dependsOnEdges: SetProperty + + @get:Nested + abstract val fragments: ListProperty +} + +internal val K2MultiplatformStructure.fragmentsCompilerArgs: Array + get() = fragments.get().map { it.fragmentName }.toSet().toTypedArray() + +internal val K2MultiplatformStructure.fragmentSourcesCompilerArgs: Array + get() = fragments.get().flatMap { sourceSet -> + sourceSet.sources.files.map { sourceFile -> "${sourceSet.fragmentName};${sourceFile.absolutePath}" } + }.toTypedArray() + +internal val K2MultiplatformStructure.dependsOnCompilerArgs: Array + get() = dependsOnEdges.get().map { edge -> + "${edge.fromFragmentName}:${edge.toFragmentName}" + }.toTypedArray() + +internal fun CommonCompilerArguments.configureK2Multiplatform(multiplatformStructure: K2MultiplatformStructure) { + fragments = multiplatformStructure.fragmentsCompilerArgs + fragmentSources = multiplatformStructure.fragmentSourcesCompilerArgs + dependsOnDependencies = multiplatformStructure.dependsOnCompilerArgs +} + +internal fun CommonCompilerArguments.configureMultiplatform( + options: KotlinCommonCompilerOptions, + k1CommonSources: FileCollection, + k2MultiplatformFragments: K2MultiplatformStructure +) { + if (options.usesK2.get()) { + configureK2Multiplatform(k2MultiplatformFragments) + } else { + commonSources = k1CommonSources.map { it.absolutePath }.toTypedArray() + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index af6570eacda..40eceb356f8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -526,6 +526,7 @@ abstract class KotlinCompile @Inject constructor( workerExecutor: WorkerExecutor, objectFactory: ObjectFactory ) : AbstractKotlinCompile(objectFactory, workerExecutor), + K2Compile, @Suppress("TYPEALIAS_EXPANSION_DEPRECATION") KotlinJvmCompileDsl, KotlinCompilationTask, UsesKotlinJavaToolchain { @@ -546,6 +547,9 @@ abstract class KotlinCompile @Inject constructor( .property(kotlinOptions) .chainedDisallowChanges() + @get:Nested + override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance() + /** A package prefix that is used for locating Java sources in a directory structure with non-full-depth packages. * * Example: a Java source file with `package com.example.my.package` is located in directory `src/main/java/my/package`. @@ -689,6 +693,12 @@ abstract class KotlinCompile @Inject constructor( ) ) + args.configureMultiplatform( + compilerOptions, + k1CommonSources = commonSourceSet.asFileTree, + k2MultiplatformFragments = multiplatformStructure + ) + if (reportingSettings().buildReportMode == BuildReportMode.VERBOSE) { args.reportPerf = true } @@ -714,7 +724,7 @@ abstract class KotlinCompile @Inject constructor( val scriptSources = scriptSources.asFileTree.files val javaSources = javaSources.files - val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors,) + val gradlePrintingMessageCollector = GradlePrintingMessageCollector(logger, args.allWarningsAsErrors) val gradleMessageCollector = GradleErrorMessageCollector(gradlePrintingMessageCollector, kotlinPluginVersion = getKotlinPluginVersion(logger)) val outputItemCollector = OutputItemsCollectorImpl() val compilerRunner = compilerRunner.get() @@ -751,7 +761,6 @@ abstract class KotlinCompile @Inject constructor( logger.info("Script file extensions: ${scriptExtensions.get().joinToString()}") compilerRunner.runJvmCompilerAsync( (kotlinSources + scriptSources + javaSources).toList(), - commonSourceSet.toList(), javaPackagePrefix, args, environment, @@ -913,7 +922,8 @@ abstract class Kotlin2JsCompile @Inject constructor( ) : AbstractKotlinCompile(objectFactory, workerExecutor), KotlinCompilationTask, UsesLibraryFilterCachingService, - KotlinJsCompile { + KotlinJsCompile, + K2Compile { init { incremental = true @@ -977,6 +987,9 @@ abstract class Kotlin2JsCompile @Inject constructor( @get:Internal internal var executionTimeFreeCompilerArgs: List? = null + @get:Nested + override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance() + override fun createCompilerArgs(): K2JSCompilerArguments = K2JSCompilerArguments() @@ -1003,6 +1016,13 @@ abstract class Kotlin2JsCompile @Inject constructor( } else { args.outputFile = outputFileProperty.get().absoluteFile.normalize().absolutePath } + + args.configureMultiplatform( + compilerOptions, + k1CommonSources = commonSourceSet.asFileTree, + k2MultiplatformFragments = multiplatformStructure + ) + // Overriding freeArgs from compilerOptions with enhanced one + additional one set on execution phase // containing additional arguments based on the js compilation configuration val localExecutionTimeFreeCompilerArgs = executionTimeFreeCompilerArgs @@ -1155,7 +1175,6 @@ abstract class Kotlin2JsCompile @Inject constructor( processArgs(args) compilerRunner.runJsCompilerAsync( kotlinSources.toList(), - commonSourceSet.toList(), args, environment, taskOutputsBackup