diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt index a0f0867e285..d5ad0beb16f 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt @@ -6,10 +6,7 @@ package org.jetbrains.kotlin.compilerRunner import org.gradle.api.Project -import org.gradle.api.tasks.Classpath -import org.gradle.api.tasks.Input -import org.gradle.api.tasks.InputFile -import org.gradle.api.tasks.Nested +import org.gradle.api.tasks.* import org.jetbrains.kotlin.cli.common.messages.MessageRenderer import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider @@ -68,6 +65,7 @@ internal abstract class KotlinNativeToolRunner( @get:Input val konanHome: String, @get:InputFile + @get:PathSensitive(PathSensitivity.ABSOLUTE) val konanPropertiesFile: File, @get:Input val jvmArgs: List, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index e30d54d2375..c25391f187e 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -62,6 +62,9 @@ open class KotlinNativeTargetConfigurator : AbstractKotl it.group = BasePlugin.BUILD_GROUP it.description = "Links ${binary.outputKind.description} '${binary.name}' for a target '${target.name}'." it.enabled = binary.konanTarget.enabledOnCurrentHost + val konanPropertiesBuildService = KonanPropertiesBuildService.registerIfAbsent(project.gradle) + it.konanPropertiesService.set(konanPropertiesBuildService) + it.usesService(konanPropertiesBuildService) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt index d55a796a3b5..f3a0f4a3df7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerDownloader.kt @@ -10,7 +10,7 @@ import org.gradle.api.Project import org.gradle.api.artifacts.repositories.ArtifactRepository import org.gradle.api.file.FileTree import org.gradle.api.logging.Logger -import org.jetbrains.kotlin.compilerRunner.KotlinNativeCompilerRunner +import org.jetbrains.kotlin.compilerRunner.KotlinNativeToolRunner import org.jetbrains.kotlin.compilerRunner.konanHome import org.jetbrains.kotlin.compilerRunner.konanVersion import org.jetbrains.kotlin.gradle.logging.kotlinInfo @@ -169,7 +169,7 @@ class NativeCompilerDownloader( fun downloadIfNeeded() { - val classpath = KotlinNativeCompilerRunner(project).classpath + val classpath = KotlinNativeToolRunner.Settings(project).classpath if (classpath.isEmpty() || classpath.any { !it.exists() }) { downloadAndExtract() } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt index f2903766eb3..56c65539d21 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/CInteropCommonizerTask.kt @@ -5,12 +5,16 @@ package org.jetbrains.kotlin.gradle.targets.native.internal +import org.gradle.api.model.ObjectFactory import org.gradle.api.provider.Provider import org.gradle.api.tasks.* +import org.gradle.process.ExecOperations import org.jetbrains.kotlin.commonizer.CommonizerDependency import org.jetbrains.kotlin.commonizer.TargetedCommonizerDependency import org.jetbrains.kotlin.commonizer.allLeaves import org.jetbrains.kotlin.compilerRunner.GradleCliCommonizer +import org.jetbrains.kotlin.compilerRunner.KotlinNativeCommonizerToolRunner +import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner import org.jetbrains.kotlin.compilerRunner.konanHome import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation @@ -22,9 +26,14 @@ import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerTas import org.jetbrains.kotlin.gradle.tasks.CInteropProcess import org.jetbrains.kotlin.konan.target.KonanTarget import java.io.File +import javax.inject.Inject @CacheableTask -internal open class CInteropCommonizerTask : AbstractCInteropCommonizerTask() { +internal open class CInteropCommonizerTask +@Inject constructor ( + private val objectFactory: ObjectFactory, + private val execOperations: ExecOperations, +) : AbstractCInteropCommonizerTask() { internal data class CInteropGist( @get:Input val identifier: CInteropIdentifier, @@ -42,6 +51,9 @@ internal open class CInteropCommonizerTask : AbstractCInteropCommonizerTask() { override val outputDirectory: File = project.buildDir.resolve("classes/kotlin/commonizer") + @get:Nested + internal val runnerSettings = KotlinNativeCommonizerToolRunner.Settings(project) + @get:Nested internal var cinterops = setOf() private set @@ -81,7 +93,12 @@ internal open class CInteropCommonizerTask : AbstractCInteropCommonizerTask() { outputDirectory(group).deleteRecursively() if (cinteropsForTarget.isEmpty()) return - GradleCliCommonizer(project).commonizeLibraries( + val commonizerRunner = KotlinNativeCommonizerToolRunner( + context = KotlinToolRunner.GradleExecutionContext.fromTaskContext(objectFactory, execOperations, logger), + settings = runnerSettings + ) + + GradleCliCommonizer(commonizerRunner).commonizeLibraries( konanHome = project.file(project.konanHome), outputTargets = group.targets, inputLibraries = cinteropsForTarget.map { it.libraryFile.get() }.filter { it.exists() }.toSet(), diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt index 49a2c0d7caa..556ff058f55 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/CInteropRunnerExecutionContextFactory.kt @@ -5,30 +5,34 @@ package org.jetbrains.kotlin.gradle.targets.native.tasks -import org.gradle.api.Project import org.gradle.api.Task import org.jetbrains.kotlin.compilerRunner.KotlinNativeCInteropRunner -import org.jetbrains.kotlin.gradle.internal.isInIdeaSync +import org.jetbrains.kotlin.compilerRunner.KotlinNativeToolRunner +import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner internal fun KotlinNativeCInteropRunner.Companion.createExecutionContext( - task: Task + task: Task, + isInIdeaSync: Boolean, + runnerSettings: KotlinNativeToolRunner.Settings, + gradleExecutionContext: KotlinToolRunner.GradleExecutionContext ): KotlinNativeCInteropRunner.ExecutionContext { - return if (task.project.isInIdeaSync) IdeaSyncKotlinNativeCInteropRunnerExecutionContext(task) - else DefaultKotlinNativeCInteropRunnerExecutionContext(task.project) + return if (isInIdeaSync) IdeaSyncKotlinNativeCInteropRunnerExecutionContext(runnerSettings, gradleExecutionContext, task) + else DefaultKotlinNativeCInteropRunnerExecutionContext(runnerSettings, gradleExecutionContext) } private class DefaultKotlinNativeCInteropRunnerExecutionContext( - override val project: Project + override val runnerSettings: KotlinNativeToolRunner.Settings, + override val gradleExecutionContext: KotlinToolRunner.GradleExecutionContext ) : KotlinNativeCInteropRunner.ExecutionContext { override fun runWithContext(action: () -> Unit) = action() } private class IdeaSyncKotlinNativeCInteropRunnerExecutionContext( + override val runnerSettings: KotlinNativeToolRunner.Settings, + override val gradleExecutionContext: KotlinToolRunner.GradleExecutionContext, private val task: Task ) : KotlinNativeCInteropRunner.ExecutionContext { - override val project: Project = task.project - override fun runWithContext(action: () -> Unit) { try { action() 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 81387910295..e092fc76a8d 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 @@ -19,8 +19,10 @@ import org.gradle.api.file.DirectoryProperty import org.gradle.api.file.FileCollection import org.gradle.api.file.FileTree import org.gradle.api.model.ObjectFactory +import org.gradle.api.provider.Property import org.gradle.api.provider.Provider import org.gradle.api.tasks.* +import org.gradle.process.ExecOperations import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments import org.jetbrains.kotlin.compilerRunner.* @@ -30,6 +32,7 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions import org.jetbrains.kotlin.gradle.dsl.KotlinCompile import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated +import org.jetbrains.kotlin.gradle.internal.isInIdeaSync import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName @@ -158,12 +161,8 @@ abstract class AbstractKotlinNativeCompile< compilation.konanTarget } - init { - notCompatibleWithConfigurationCache("Task $name does not support Gradle Configuration Cache. Check KT-43293 for more info") - } - @get:Classpath - override val libraries: ConfigurableFileCollection by project.provider { + override val libraries: ConfigurableFileCollection by lazy { // Avoid resolving these dependencies during task graph construction when we can't build the target: if (konanTarget.enabledOnCurrentHost) objectFactory.fileCollection().from( @@ -173,9 +172,7 @@ abstract class AbstractKotlinNativeCompile< } @get:Classpath - protected val friendModule: FileCollection by project.provider { - project.files(compilation.friendPaths) - } + protected val friendModule: FileCollection = project.files({ compilation.friendPaths }) @get:Input val target: String by project.provider { compilation.konanTarget.name } @@ -187,7 +184,7 @@ abstract class AbstractKotlinNativeCompile< abstract fun kotlinOptions(fn: Closure<*>) @get:Input - abstract val additionalCompilerOptions: Provider> + abstract val additionalCompilerOptions: Collection @get:Internal val languageSettings: LanguageSettings by project.provider { @@ -271,7 +268,7 @@ abstract class AbstractKotlinNativeCompile< override var allWarningsAsErrors = kotlinOptions.allWarningsAsErrors override var suppressWarnings = kotlinOptions.suppressWarnings override var verbose = kotlinOptions.verbose - override var freeCompilerArgs = if (defaultsOnly) emptyList() else additionalCompilerOptions.get().toList() + override var freeCompilerArgs = if (defaultsOnly) emptyList() else additionalCompilerOptions.toList() } return buildKotlinNativeCommonArgs( @@ -293,11 +290,10 @@ abstract class AbstractKotlinNativeCompile< } @get:Internal - internal val manifestFile: Provider - get() = project.provider { - val inputManifestFile = project.buildDir.resolve("tmp/$name/inputManifest") - inputManifestFile - } + internal val manifestFile: File by lazy { + val inputManifestFile = project.buildDir.resolve("tmp/$name/inputManifest") + inputManifestFile + } } // Remove it once actual K2NativeCompilerArguments will be available without 'kotlin.native.enabled = true' flag @@ -313,7 +309,8 @@ constructor( @Internal @Transient // can't be serialized for Gradle configuration cache final override val compilation: KotlinNativeCompilationData<*>, - objectFactory: ObjectFactory + private val objectFactory: ObjectFactory, + private val execOperations: ExecOperations ) : AbstractKotlinNativeCompile, StubK2NativeCompilerArguments>(objectFactory), KotlinCompile { @@ -327,7 +324,7 @@ constructor( override val debuggable = true @get:Internal - override val baseName: String by project.provider { + override val baseName: String by lazy { if (compilation.isMainCompilationData()) project.name else "${project.name}_${compilation.compilationPurpose}" @@ -337,7 +334,7 @@ constructor( // private val allSourceProvider = compilation.map { project.files(it.allSources).asFileTree } @get:Input - val moduleName: String by project.provider { + val moduleName: String by lazy { project.klibModuleName(baseName) } @@ -384,10 +381,14 @@ constructor( } @get:Input - override val additionalCompilerOptions: Provider> = project.provider { + override val additionalCompilerOptions: Collection by lazy { kotlinOptions.freeCompilerArgs + ((languageSettings as? DefaultLanguageSettingsBuilder)?.freeCompilerArgs ?: emptyList()) } + @get:Nested + internal val runnerSettings = KotlinNativeCompilerRunner.Settings(project) + private val isAllowCommonizer: Boolean by lazy { project.isAllowCommonizer() } + override fun kotlinOptions(fn: KotlinCommonOptions.() -> Unit) { kotlinOptions.fn() } @@ -413,7 +414,7 @@ constructor( var sharedCompilationData: SharedCompilationData? = null if (compilation is KotlinNativeFragmentMetadataCompilationData) { - val manifestFile: File = manifestFile.get() + val manifestFile: File = manifestFile manifestFile.ensureParentDirsCreated() val properties = java.util.Properties() properties[KLIB_PROPERTY_NATIVE_TARGETS] = konanTargetsForManifest @@ -421,7 +422,7 @@ constructor( sharedCompilationData = SharedCompilationData( manifestFile, - project.isAllowCommonizer() + isAllowCommonizer ) } @@ -429,7 +430,7 @@ constructor( override var allWarningsAsErrors = kotlinOptions.allWarningsAsErrors override var suppressWarnings = kotlinOptions.suppressWarnings override var verbose = kotlinOptions.verbose - override var freeCompilerArgs = additionalCompilerOptions.get().toList() + override var freeCompilerArgs = additionalCompilerOptions.toList() } val plugins = listOfNotNull( @@ -455,7 +456,10 @@ constructor( commonSourcesTree ) - KotlinNativeCompilerRunner(project).run(buildArgs) + KotlinNativeCompilerRunner( + settings = runnerSettings, + executionContext = KotlinToolRunner.GradleExecutionContext.fromTaskContext(objectFactory, execOperations, logger) + ).run(buildArgs) } } @@ -468,12 +472,16 @@ abstract class KotlinNativeLink constructor( @Internal val binary: NativeBinary, - objectFactory: ObjectFactory + private val objectFactory: ObjectFactory, + private val execOperations: ExecOperations ) : AbstractKotlinNativeCompile(objectFactory) { @get:Internal final override val compilation: KotlinNativeCompilation get() = binary.compilation + @get:Nested + internal val runnerSettings = KotlinNativeCompilerRunner.Settings(project) + init { dependsOn(project.provider { compilation.compileKotlinTaskProvider }) // Frameworks actively uses symlinks. @@ -502,7 +510,7 @@ constructor( @Input get() = binary.baseName @get:Input - protected val konanCacheKind: NativeCacheKind by project.provider { + protected val konanCacheKind: NativeCacheKind by lazy { project.getKonanCacheKind(konanTarget) } @@ -515,7 +523,7 @@ constructor( // We propagate compilation free args to the link task for now (see KT-33717). @get:Input - override val additionalCompilerOptions: Provider> = project.provider { + override val additionalCompilerOptions: Collection by lazy { kotlinOptions.freeCompilerArgs + compilation.kotlinOptions.freeCompilerArgs + ((languageSettings as? DefaultLanguageSettingsBuilder)?.freeCompilerArgs ?: emptyList()) + @@ -542,17 +550,17 @@ constructor( val linkerOpts: List @Input get() = binary.linkerOpts - val binaryOptions: Map - @Input get() = PropertiesProvider(project).nativeBinaryOptions + binary.binaryOptions + @get:Input + val binaryOptions: Map by lazy { PropertiesProvider(project).nativeBinaryOptions + binary.binaryOptions } val processTests: Boolean @Input get() = binary is TestExecutable @get:Classpath - val exportLibraries: FileCollection by project.provider { + val exportLibraries: FileCollection by lazy { binary.let { if (it is AbstractNativeLibrary) { - project.configurations.getByName(it.exportConfigurationName) + project.files(project.configurations.getByName(it.exportConfigurationName)) } else { objectFactory.fileCollection() } @@ -570,8 +578,22 @@ constructor( } @get:Internal - val apiFilesProvider = project.provider { - project.configurations.getByName(compilation.apiConfigurationName).files.filterKlibsPassedToCompiler() + val apiFiles by lazy { + project.files(project.configurations.getByName(compilation.apiConfigurationName)).files.filterKlibsPassedToCompiler() + } + + private val localKotlinOptions get() = + object : KotlinCommonToolOptions { + override var allWarningsAsErrors = kotlinOptions.allWarningsAsErrors + override var suppressWarnings = kotlinOptions.suppressWarnings + override var verbose = kotlinOptions.verbose + override var freeCompilerArgs = additionalCompilerOptions.toList() + } + + private val externalDependenciesArgs by lazy { ExternalDependenciesBuilder(project, compilation).buildCompilerArgs() } + + private val cacheBuilderSettings by lazy { + CacheBuilder.Settings(project, binary, konanTarget, localKotlinOptions, externalDependenciesArgs) } override fun createCompilerArgs(): StubK2NativeCompilerArguments = StubK2NativeCompilerArguments() @@ -584,7 +606,6 @@ constructor( private fun validatedExportedLibraries() { val exportConfiguration = exportLibraries as? Configuration ?: return - val apiFiles = apiFilesProvider.get() val failed = mutableSetOf() exportConfiguration.allDependencies.forEach { @@ -613,6 +634,14 @@ constructor( } } + @get:Internal + internal abstract val konanPropertiesService: Property + + private val compileDependencyFiles = FilesWithResolvedDependencyGraph( + project, + project.configurations.getByName(compilation.compileDependencyConfigurationName) + ) + @TaskAction fun compile() { validatedExportedLibraries() @@ -625,15 +654,12 @@ constructor( kotlinPluginData?.orNull?.let { CompilerPluginData(it.classpath, it.options) } ) - val localKotlinOptions = object : KotlinCommonToolOptions { - override var allWarningsAsErrors = kotlinOptions.allWarningsAsErrors - override var suppressWarnings = kotlinOptions.suppressWarnings - override var verbose = kotlinOptions.verbose - override var freeCompilerArgs = additionalCompilerOptions.get().toList() - } - - val externalDependenciesArgs = ExternalDependenciesBuilder(project, compilation).buildCompilerArgs() - val cacheArgs = CacheBuilder(project, binary, konanTarget, localKotlinOptions, externalDependenciesArgs).buildCompilerArgs() + val executionContext = KotlinToolRunner.GradleExecutionContext.fromTaskContext(objectFactory, execOperations, logger) + val cacheArgs = CacheBuilder( + executionContext = executionContext, + settings = cacheBuilderSettings, + konanPropertiesService = konanPropertiesService.get() + ).buildCompilerArgs(compileDependencyFiles) val buildArgs = buildKotlinNativeBinaryLinkerArgs( output, @@ -657,7 +683,10 @@ constructor( externalDependenciesArgs + cacheArgs ) - KotlinNativeCompilerRunner(project).run(buildArgs) + KotlinNativeCompilerRunner( + settings = runnerSettings, + executionContext = executionContext + ).run(buildArgs) } } @@ -838,19 +867,53 @@ private class ExternalDependenciesBuilder( } internal class CacheBuilder( - val project: Project, - val binary: NativeBinary, - val konanTarget: KonanTarget, - val kotlinOptions: KotlinCommonToolOptions, - val externalDependenciesArgs: List + private val executionContext: KotlinToolRunner.GradleExecutionContext, + private val settings: Settings, + private val konanPropertiesService: KonanPropertiesBuildService, ) { + class Settings( + val runnerSettings: KotlinNativeCompilerRunner.Settings, + val konanCacheKind: NativeCacheKind, + val libraries: FileCollection, + val rootCacheDirectory: File, + val gradleUserHomeDir: File, + val binary: NativeBinary, + val konanTarget: KonanTarget, + val kotlinOptions: KotlinCommonToolOptions, + val externalDependenciesArgs: List + ) { + companion object { + operator fun invoke( + project: Project, + binary: NativeBinary, + konanTarget: KonanTarget, + kotlinOptions: KotlinCommonToolOptions, + externalDependenciesArgs: List + ): Settings { + val konanCacheKind = project.getKonanCacheKind(konanTarget) + return Settings( + runnerSettings = KotlinNativeCompilerRunner.Settings(project), + konanCacheKind = konanCacheKind, + libraries = binary.compilation.compileDependencyFiles.filterOutPublishableInteropLibs(project), + rootCacheDirectory = getRootCacheDirectory(File(project.konanHome), konanTarget, binary.debuggable, konanCacheKind), + gradleUserHomeDir = project.gradle.gradleUserHomeDir, + binary, konanTarget, kotlinOptions, externalDependenciesArgs + ) + } + } + } + private val nativeSingleFileResolveStrategy: SingleFileKlibResolveStrategy get() = CompilerSingleFileKlibResolveAllowingIrProvidersStrategy( listOf(KLIB_INTEROP_IR_PROVIDER_IDENTIFIER) ) - private val compilation: KotlinNativeCompilation - get() = binary.compilation + + private val binary: NativeBinary + get() = settings.binary + + private val konanTarget: KonanTarget + get() = settings.konanTarget private val optimized: Boolean get() = binary.optimized @@ -858,25 +921,21 @@ internal class CacheBuilder( private val debuggable: Boolean get() = binary.debuggable - private val konanPropertiesService: KonanPropertiesBuildService - get() = KonanPropertiesBuildService.registerIfAbsent(project.gradle).get() - private val konanCacheKind: NativeCacheKind - get() = project.getKonanCacheKind(konanTarget) + get() = settings.konanCacheKind // Inputs and outputs private val libraries: FileCollection - get() = compilation.compileDependencyFiles.filterOutPublishableInteropLibs(project) + get() = settings.libraries private val target: String get() = konanTarget.name - private val rootCacheDirectory by project.provider { - getRootCacheDirectory(File(project.konanHome), konanTarget, debuggable, konanCacheKind) - } + private val rootCacheDirectory: File + get() = settings.rootCacheDirectory private val partialLinkage: Boolean - get() = PARTIAL_LINKAGE in kotlinOptions.freeCompilerArgs + get() = PARTIAL_LINKAGE in settings.kotlinOptions.freeCompilerArgs private fun getCacheDirectory(dependency: ResolvedDependency): File = getCacheDirectory( rootCacheDirectory = rootCacheDirectory, @@ -886,7 +945,7 @@ internal class CacheBuilder( ) private fun needCache(libraryPath: String) = - libraryPath.startsWith(project.gradle.gradleUserHomeDir.absolutePath) && libraryPath.endsWith(".klib") + libraryPath.startsWith(settings.gradleUserHomeDir.absolutePath) && libraryPath.endsWith(".klib") private fun ensureDependencyPrecached(dependency: ResolvedDependency, visitedDependencies: MutableSet) { if (dependency in visitedDependencies) @@ -911,7 +970,7 @@ internal class CacheBuilder( .map { resolveSingleFileKlib( KFile(it.file.absolutePath), - logger = GradleLoggerAdapter(project.logger), + logger = GradleLoggerAdapter(executionContext.logger), strategy = nativeSingleFileResolveStrategy ) } @@ -939,14 +998,14 @@ internal class CacheBuilder( for (library in sortedLibraries) { if (File(cacheDirectory, library.uniqueName.cachedName).listFilesOrEmpty().isNotEmpty()) continue - project.logger.info("Compiling ${library.uniqueName} to cache") + executionContext.logger.info("Compiling ${library.uniqueName} to cache") val args = mutableListOf( "-p", konanCacheKind.produce!!, "-target", target ) if (debuggable) args += "-g" args += konanPropertiesService.additionalCacheFlags(konanTarget) - args += externalDependenciesArgs + args += settings.externalDependenciesArgs if (partialLinkage) args += PARTIAL_LINKAGE args += "-Xadd-cache=${library.libraryFile.absolutePath}" args += "-Xcache-directory=${cacheDirectory.absolutePath}" @@ -969,7 +1028,7 @@ internal class CacheBuilder( args += "-l" args += it.libraryFile.absolutePath } - KotlinNativeCompilerRunner(project).run(args) + KotlinNativeCompilerRunner(settings.runnerSettings, executionContext).run(args) } } @@ -989,12 +1048,12 @@ internal class CacheBuilder( return val unresolvedDependencies = resolveSingleFileKlib( KFile(platformLib.absolutePath), - logger = GradleLoggerAdapter(project.logger), + logger = GradleLoggerAdapter(executionContext.logger), strategy = nativeSingleFileResolveStrategy ).unresolvedDependencies for (dependency in unresolvedDependencies) ensureCompilerProvidedLibPrecached(dependency.path, platformLibs, visitedLibs) - project.logger.info("Compiling $platformLibName (${visitedLibs.size}/${platformLibs.size}) to cache") + executionContext.logger.info("Compiling $platformLibName (${visitedLibs.size}/${platformLibs.size}) to cache") val args = mutableListOf( "-p", konanCacheKind.produce!!, "-target", target @@ -1010,11 +1069,11 @@ internal class CacheBuilder( } args += "-Xadd-cache=${platformLib.absolutePath}" args += "-Xcache-directory=${rootCacheDirectory.absolutePath}" - KotlinNativeCompilerRunner(project).run(args) + KotlinNativeCompilerRunner(settings.runnerSettings, executionContext).run(args) } private fun ensureCompilerProvidedLibsPrecached() { - val distribution = Distribution(project.konanHome) + val distribution = Distribution(settings.runnerSettings.parent.konanHome) val platformLibs = mutableListOf().apply { this += File(distribution.stdlib) this += File(distribution.platformLibs(konanTarget)).listFiles().orEmpty() @@ -1024,15 +1083,14 @@ internal class CacheBuilder( ensureCompilerProvidedLibPrecached(platformLibName, platformLibs, visitedLibs) } - fun buildCompilerArgs(): List = mutableListOf().apply { + fun buildCompilerArgs(compileDependencyFiles: FilesWithResolvedDependencyGraph): List = mutableListOf().apply { if (konanCacheKind != NativeCacheKind.NONE && !optimized && konanPropertiesService.cacheWorksFor(konanTarget)) { rootCacheDirectory.mkdirs() ensureCompilerProvidedLibsPrecached() add("-Xcache-directory=${rootCacheDirectory.absolutePath}") val visitedDependencies = mutableSetOf() val allCacheDirectories = mutableSetOf() - val compileDependencyConfiguration = project.configurations.getByName(compilation.compileDependencyConfigurationName) - for (root in compileDependencyConfiguration.resolvedConfiguration.firstLevelModuleDependencies) { + for (root in compileDependencyFiles.graphRoot.firstLevelModuleDependencies) { ensureDependencyPrecached(root, visitedDependencies) for (dependency in listOf(root) + getAllDependencies(root)) { val cacheDirectory = getCacheDirectory(dependency) @@ -1062,7 +1120,12 @@ internal class CacheBuilder( } @CacheableTask -open class CInteropProcess @Inject constructor(@get:Internal val settings: DefaultCInteropSettings) : DefaultTask() { +open class CInteropProcess +@Inject constructor( + @get:Internal val settings: DefaultCInteropSettings, + private val objectFactory: ObjectFactory, + private val execOperations: ExecOperations +) : DefaultTask() { @Internal // Taken into account in the outputFileProvider property lateinit var destinationDir: Provider @@ -1093,9 +1156,8 @@ open class CInteropProcess @Inject constructor(@get:Internal val settings: Defau val outputFile: File get() = outputFileProvider.get() - init { - notCompatibleWithConfigurationCache("Task $name does not support Gradle Configuration Cache. Check KT-43293 for more info") - } + @get:Nested + internal val runnerSettings = KotlinNativeToolRunner.Settings(project) // Inputs and outputs. @@ -1137,8 +1199,7 @@ open class CInteropProcess @Inject constructor(@get:Internal val settings: Defau val extraOpts: List @Input get() = settings.extraOpts - val kotlinNativeVersion: String - @Input get() = project.konanVersion.toString() + private val isInIdeaSync = project.isInIdeaSync // Task action. @TaskAction @@ -1175,6 +1236,11 @@ open class CInteropProcess @Inject constructor(@get:Internal val settings: Defau } outputFile.parentFile.mkdirs() - KotlinNativeCInteropRunner.createExecutionContext(this).run(args) + KotlinNativeCInteropRunner.createExecutionContext( + task = this, + isInIdeaSync = isInIdeaSync, + runnerSettings = runnerSettings, + gradleExecutionContext = KotlinToolRunner.GradleExecutionContext.fromTaskContext(objectFactory, execOperations, logger) + ).run(args) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeLinkArtifactTask.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeLinkArtifactTask.kt index 7d882b3e8ca..08f22567863 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeLinkArtifactTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/artifact/KotlinNativeLinkArtifactTask.kt @@ -5,18 +5,19 @@ package org.jetbrains.kotlin.gradle.targets.native.tasks.artifact -import groovy.lang.Closure import org.gradle.api.Action import org.gradle.api.DefaultTask import org.gradle.api.file.FileCollection +import org.gradle.api.model.ObjectFactory import org.gradle.api.tasks.* +import org.gradle.process.ExecOperations import org.jetbrains.kotlin.compilerRunner.KotlinNativeCompilerRunner +import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner import org.jetbrains.kotlin.gradle.dsl.KotlinCommonToolOptions import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode import org.jetbrains.kotlin.gradle.targets.native.tasks.buildKotlinNativeBinaryLinkerArgs -import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.util.visibleName @@ -25,7 +26,9 @@ import javax.inject.Inject open class KotlinNativeLinkArtifactTask @Inject constructor( @get:Input val konanTarget: KonanTarget, - @get:Input val outputKind: CompilerOutputKind + @get:Input val outputKind: CompilerOutputKind, + private val objectFactory: ObjectFactory, + private val execOperations: ExecOperations ) : DefaultTask() { @get:Input @@ -74,7 +77,7 @@ open class KotlinNativeLinkArtifactTask @Inject constructor( var librariesConfiguration: String? = null @get:Classpath - val libraries: FileCollection by project.provider { + val libraries: FileCollection by lazy { librariesConfiguration?.let { project.configurations.getByName(it) } ?: project.objects.fileCollection() @@ -84,7 +87,7 @@ open class KotlinNativeLinkArtifactTask @Inject constructor( var exportLibrariesConfiguration: String? = null @get:Classpath - val exportLibraries: FileCollection by project.provider { + val exportLibraries: FileCollection by lazy { exportLibrariesConfiguration?.let { project.configurations.getByName(it) } ?: project.objects.fileCollection() @@ -94,7 +97,7 @@ open class KotlinNativeLinkArtifactTask @Inject constructor( var includeLibrariesConfiguration: String? = null @get:Classpath - val includeLibraries: FileCollection by project.provider { + val includeLibraries: FileCollection by lazy { includeLibrariesConfiguration?.let { project.configurations.getByName(it) } ?: project.objects.fileCollection() @@ -145,6 +148,9 @@ open class KotlinNativeLinkArtifactTask @Inject constructor( return destinationDir.resolve(outFileName) } + @get:Nested + internal val runnerSettings = KotlinNativeCompilerRunner.Settings(project) + @TaskAction fun link() { val outFile = outputFile @@ -176,6 +182,9 @@ open class KotlinNativeLinkArtifactTask @Inject constructor( additionalOptions = emptyList()//todo support org.jetbrains.kotlin.gradle.tasks.CacheBuilder and org.jetbrains.kotlin.gradle.tasks.ExternalDependenciesBuilder ) - KotlinNativeCompilerRunner(project).run(buildArgs) + KotlinNativeCompilerRunner( + settings = runnerSettings, + executionContext = KotlinToolRunner.GradleExecutionContext.fromTaskContext(objectFactory, execOperations, logger) + ).run(buildArgs) } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt index fee5db0c130..6ad555bf5c9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/utils/configurations.kt @@ -5,6 +5,14 @@ package org.jetbrains.kotlin.gradle.utils +import org.gradle.api.Project +import org.gradle.api.artifacts.Configuration +import org.gradle.api.artifacts.ResolvedConfiguration +import org.gradle.api.artifacts.ResolvedDependency +import org.gradle.api.artifacts.result.ResolvedComponentResult +import org.gradle.api.file.FileCollection +import org.gradle.api.provider.Provider + const val COMPILE_ONLY = "compileOnly" const val COMPILE = "compile" const val IMPLEMENTATION = "implementation" @@ -12,3 +20,27 @@ const val API = "api" const val RUNTIME_ONLY = "runtimeOnly" const val RUNTIME = "runtime" internal const val INTRANSITIVE = "intransitive" + +/** + * Gradle Configuration Cache-friendly holder of resolved Configuration + */ +class FilesWithResolvedDependencyGraph +private constructor ( + val files: FileCollection, + val graphRootProvider: Provider +) { + val graphRoot get() = graphRootProvider.get() + + companion object { + operator fun invoke(project: Project, configuration: Configuration) = FilesWithResolvedDependencyGraph( + files = project.files(configuration), + graphRootProvider = configuration.incoming.resolutionResult.let { rr -> project.provider { rr.root } } + ) + } +} + +/** + * Configuration Cache-friendly alternative of [ResolvedConfiguration.getFirstLevelModuleDependencies] + */ +internal val ResolvedComponentResult.firstLevelModuleDependencies: Set get() = + dependencies.filterIsInstance().toSet() \ No newline at end of file