diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt index 1d2177de3d5..d459b4c503d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt @@ -11,10 +11,9 @@ import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.mpp.isAtLeast import org.jetbrains.kotlin.gradle.plugin.mpp.nativeUseEmbeddableCompilerJar -import org.jetbrains.kotlin.gradle.tasks.CacheBuilder +import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader import org.jetbrains.kotlin.konan.CompilerVersion -import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.properties.resolvablePropertyString import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget @@ -42,7 +41,7 @@ internal fun Project.getKonanCacheKind(target: KonanTarget): NativeCacheKind { return when { targetCacheKind != null -> targetCacheKind commonCacheKind != null -> commonCacheKind - else -> CacheBuilder.defaultCacheKindForTarget(target) + else -> KonanPropertiesBuildService.registerIfAbsent(gradle).get().defaultCacheKindForTarget(target) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KonanPropertiesBuildService.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KonanPropertiesBuildService.kt new file mode 100644 index 00000000000..d52e01c275a --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/KonanPropertiesBuildService.kt @@ -0,0 +1,72 @@ +/* + * Copyright 2010-2021 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.targets.native + +import org.gradle.api.invocation.Gradle +import org.gradle.api.provider.Property +import org.gradle.api.provider.Provider +import org.gradle.api.services.BuildService +import org.gradle.api.services.BuildServiceParameters +import org.jetbrains.kotlin.compilerRunner.konanHome +import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind +import org.jetbrains.kotlin.konan.properties.resolvablePropertyList +import org.jetbrains.kotlin.konan.target.Distribution +import org.jetbrains.kotlin.konan.target.HostManager +import org.jetbrains.kotlin.konan.target.KonanTarget +import java.util.* + +abstract class KonanPropertiesBuildService : BuildService { + + internal interface Parameters : BuildServiceParameters { + val konanHome: Property + } + + private val properties: Properties by lazy { + Distribution(parameters.konanHome.get()).properties + } + + private val cacheableTargets: List by lazy { + properties + .resolvablePropertyList("cacheableTargets", HostManager.hostName) + .map { KonanTarget.predefinedTargets.getValue(it) } + } + + private val targetsWithOptInStaticCaches: List by lazy { + properties + .resolvablePropertyList("optInCacheableTargets", HostManager.hostName) + .map { KonanTarget.predefinedTargets.getValue(it) } + } + + internal fun defaultCacheKindForTarget(target: KonanTarget): NativeCacheKind = + if (target in cacheableTargets && target !in targetsWithOptInStaticCaches) { + NativeCacheKind.STATIC + } else { + NativeCacheKind.NONE + } + + internal fun cacheWorksFor(target: KonanTarget): Boolean = + target in cacheableTargets + + internal fun additionalCacheFlags(target: KonanTarget): List = + properties.resolvablePropertyList("additionalCacheFlags", target.visibleName) + + internal val compilerVersion: String? by lazy { + properties["compilerVersion"]?.toString() + } + + companion object { + fun registerIfAbsent(gradle: Gradle): Provider = + gradle.sharedServices.registerIfAbsent(serviceName, KonanPropertiesBuildService::class.java) { service -> + service.parameters.konanHome.set(gradle.rootProject.konanHome) + } + + private val serviceName: String + get() { + val clazz = KonanPropertiesBuildService::class.java + return "${clazz}_${clazz.classLoader.hashCode()}" + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/PlatformLibrariesGenerator.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/PlatformLibrariesGenerator.kt index 402254a2d41..958af118959 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/PlatformLibrariesGenerator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/internal/PlatformLibrariesGenerator.kt @@ -11,6 +11,7 @@ import org.jetbrains.kotlin.compilerRunner.getKonanCacheKind import org.jetbrains.kotlin.compilerRunner.konanHome import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider +import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService import org.jetbrains.kotlin.gradle.tasks.CacheBuilder import org.jetbrains.kotlin.gradle.tasks.addArg import org.jetbrains.kotlin.gradle.utils.lifecycleWithDuration @@ -35,12 +36,15 @@ internal class PlatformLibrariesGenerator(val project: Project, val konanTarget: private val defDirectory = File(distribution.platformDefs(konanTarget)).absoluteFile + private val konanPropertiesService: KonanPropertiesBuildService + get() = KonanPropertiesBuildService.registerIfAbsent(project.gradle).get() + private val konanCacheKind: NativeCacheKind by lazy { project.getKonanCacheKind(konanTarget) } private val shouldBuildCaches: Boolean = - CacheBuilder.cacheWorksFor(konanTarget, project) && konanCacheKind != NativeCacheKind.NONE + konanPropertiesService.cacheWorksFor(konanTarget) && konanCacheKind != NativeCacheKind.NONE private val mode: String? by lazy { PropertiesProvider(project).nativePlatformLibrariesMode @@ -117,6 +121,10 @@ internal class PlatformLibrariesGenerator(val project: Project, val konanTarget: CacheBuilder.getRootCacheDirectory(File(konanHome), konanTarget, true, konanCacheKind).absolutePath ) args.addArg("-cache-arg", "-g") + val additionalCacheFlags = konanPropertiesService.additionalCacheFlags(konanTarget) + additionalCacheFlags.forEach { + args.addArg("-cache-arg", it) + } } mode?.let { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 54406b8000d..15f3e8b151b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -33,31 +33,29 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.KotlinNativeFragmentMetadataCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.isMainCompilationData import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer import org.jetbrains.kotlin.gradle.utils.* -import org.jetbrains.kotlin.gradle.utils.klibModuleName import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty import org.jetbrains.kotlin.konan.CompilerVersion import org.jetbrains.kotlin.konan.library.KLIB_INTEROP_IR_PROVIDER_IDENTIFIER -import org.jetbrains.kotlin.konan.properties.resolvablePropertyList import org.jetbrains.kotlin.konan.properties.saveToFile import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind.* import org.jetbrains.kotlin.konan.target.Distribution -import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.library.* import org.jetbrains.kotlin.project.model.LanguageSettings -import org.jetbrains.kotlin.utils.ResolvedDependency as KResolvedDependency -import org.jetbrains.kotlin.utils.ResolvedDependencyId as KResolvedDependencyId -import org.jetbrains.kotlin.utils.ResolvedDependencies as KResolvedDependencies -import org.jetbrains.kotlin.utils.ResolvedDependenciesSupport as KResolvedDependenciesSupport -import org.jetbrains.kotlin.utils.ResolvedDependencyArtifactPath as KResolvedDependencyArtifactPath -import org.jetbrains.kotlin.utils.ResolvedDependencyVersion as KResolvedDependencyVersion import java.io.File import java.nio.file.Files import javax.inject.Inject import org.jetbrains.kotlin.konan.file.File as KFile +import org.jetbrains.kotlin.utils.ResolvedDependencies as KResolvedDependencies +import org.jetbrains.kotlin.utils.ResolvedDependenciesSupport as KResolvedDependenciesSupport +import org.jetbrains.kotlin.utils.ResolvedDependency as KResolvedDependency +import org.jetbrains.kotlin.utils.ResolvedDependencyArtifactPath as KResolvedDependencyArtifactPath +import org.jetbrains.kotlin.utils.ResolvedDependencyId as KResolvedDependencyId +import org.jetbrains.kotlin.utils.ResolvedDependencyVersion as KResolvedDependencyVersion // TODO: It's just temporary tasks used while KN isn't integrated with Big Kotlin compilation infrastructure. // region Useful extensions @@ -730,8 +728,12 @@ private class ExternalDependenciesBuilder( private val sourceCodeModuleId: KResolvedDependencyId = intermediateLibraryName?.let { KResolvedDependencyId(it) } ?: KResolvedDependencyId.DEFAULT_SOURCE_CODE_MODULE_ID + private val konanPropertiesService: KonanPropertiesBuildService + get() = KonanPropertiesBuildService.registerIfAbsent(project.gradle).get() + fun buildCompilerArgs(): List { - val konanVersion = Distribution(project.konanHome).compilerVersion?.let(CompilerVersion.Companion::fromString) + val compilerVersion = Distribution.getCompilerVersion(konanPropertiesService.compilerVersion, project.konanHome) + val konanVersion = compilerVersion?.let(CompilerVersion.Companion::fromString) ?: project.konanVersion if (konanVersion.isAtLeast(1, 6, 0)) { @@ -907,6 +909,9 @@ 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) @@ -986,13 +991,7 @@ internal class CacheBuilder( ) if (debuggable) args += "-g" - // It's a dirty workaround, but we need a Gradle Build Service for a proper solution, - // which is too big to put in 1.6.0, so let's use ad-hoc solution for now. - // TODO: https://youtrack.jetbrains.com/issue/KT-48553. - if (konanTarget == KonanTarget.IOS_ARM64) { - // See https://youtrack.jetbrains.com/issue/KT-48552 - args += "-Xembed-bitcode-marker" - } + args += konanPropertiesService.additionalCacheFlags(konanTarget) args += externalDependenciesArgs args += "-Xadd-cache=${library.libraryFile.absolutePath}" args += "-Xcache-directory=${cacheDirectory.absolutePath}" @@ -1071,7 +1070,7 @@ internal class CacheBuilder( } fun buildCompilerArgs(): List = mutableListOf().apply { - if (konanCacheKind != NativeCacheKind.NONE && !optimized && cacheWorksFor(konanTarget, project)) { + if (konanCacheKind != NativeCacheKind.NONE && !optimized && konanPropertiesService.cacheWorksFor(konanTarget)) { rootCacheDirectory.mkdirs() ensureCompilerProvidedLibsPrecached() add("-Xcache-directory=${rootCacheDirectory.absolutePath}") @@ -1102,36 +1101,6 @@ internal class CacheBuilder( cacheKind.outputKind?.let { "${baseName}-cache" } ?: error("No output for kind $cacheKind") - - private fun getCacheableTargets(project: Project) = - Distribution(project.konanHome) - .properties - .resolvablePropertyList("cacheableTargets", HostManager.hostName) - .map { KonanTarget.predefinedTargets.getValue(it) } - - // Targets with well-tested static caches that can be enabled by default. - // TODO: There is a corresponding property in konan.properties (optInCacheableTargets), - // but naïve implementation makes build slower because it makes reading of konan.properties significantly more frequent. - // One possible solution is to use [Gradle Build service](https://docs.gradle.org/current/userguide/build_services.html). - // Tracking issue: https://youtrack.jetbrains.com/issue/KT-47529 - private val targetsWithStableStaticCaches = setOf( - KonanTarget.IOS_X64, - KonanTarget.MACOS_X64, - KonanTarget.IOS_SIMULATOR_ARM64, - KonanTarget.MACOS_ARM64, - KonanTarget.IOS_ARM64, - KonanTarget.LINUX_X64 - ) - - internal fun cacheWorksFor(target: KonanTarget, project: Project) = - target in getCacheableTargets(project) - - internal fun defaultCacheKindForTarget(target: KonanTarget): NativeCacheKind = - if (target in targetsWithStableStaticCaches) { - NativeCacheKind.STATIC - } else { - NativeCacheKind.NONE - } } } diff --git a/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt b/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt index 0af11afe2fe..16d6985d5c1 100644 --- a/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt +++ b/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt @@ -69,13 +69,11 @@ class Distribution( result } + /** + * Consider using [org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService] in case of Gradle. + */ val compilerVersion by lazy { - val propertyVersion = properties["compilerVersion"]?.toString() - val bundleVersion = if (konanHome.contains("-1")) - konanHome.substring(konanHome.lastIndexOf("-1") + 1) - else - null - propertyVersion ?: bundleVersion + getCompilerVersion(properties["compilerVersion"]?.toString(), konanHome) } val klib = "$konanHome/klib" @@ -98,6 +96,20 @@ class Distribution( override fun availableSubTarget(genericName: String) = additionalPropertyFiles(genericName).map { it.name } } + + companion object { + /** + * Try to guess compiler version using [konanHome]. + */ + private fun getBundleVersion(konanHome: String): String? = + if (konanHome.contains("-1")) + konanHome.substring(konanHome.lastIndexOf("-1") + 1) + else + null + + fun getCompilerVersion(propertyVersion: String?, konanHome: String): String? = + propertyVersion ?: getBundleVersion(konanHome) + } } // TODO: Move into K/N?