Skip to content

Commit

Permalink
Set Kotlin/Native cache kind based on Kotlin version
Browse files Browse the repository at this point in the history
Resolves #2046
Resolves #2386
  • Loading branch information
AlexeyTsvetkov committed Aug 10, 2023
1 parent 44376fd commit 1939de0
Show file tree
Hide file tree
Showing 12 changed files with 243 additions and 1 deletion.
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import org.jetbrains.compose.desktop.preview.internal.initializePreview
import org.jetbrains.compose.experimental.dsl.ExperimentalExtension
import org.jetbrains.compose.experimental.internal.configureExperimentalTargetsFlagsCheck
import org.jetbrains.compose.experimental.internal.configureExperimental
import org.jetbrains.compose.experimental.internal.configureNativeCompilerCaching
import org.jetbrains.compose.experimental.uikit.internal.resources.configureSyncTask
import org.jetbrains.compose.internal.KOTLIN_MPP_PLUGIN_ID
import org.jetbrains.compose.internal.mppExt
Expand All @@ -32,6 +33,7 @@ import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.dsl.KotlinCompile
import org.jetbrains.kotlin.gradle.dsl.KotlinJsCompile
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType
import java.util.*

internal val composeVersion get() = ComposeBuildConfig.composeVersion

Expand All @@ -52,6 +54,7 @@ class ComposePlugin : Plugin<Project> {
composeExtension.extensions.create("web", WebExtension::class.java)

project.plugins.apply(ComposeCompilerKotlinSupportPlugin::class.java)
project.configureNativeCompilerCaching()

project.afterEvaluate {
configureDesktop(project, desktopExtension)
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/*
* Copyright 2020-2023 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/

package org.jetbrains.compose.experimental.internal

import org.gradle.api.Project
import org.jetbrains.compose.internal.KOTLIN_MPP_PLUGIN_ID
import org.jetbrains.compose.internal.mppExt
import org.jetbrains.compose.internal.utils.KGPPropertyFinder
import org.jetbrains.compose.internal.utils.configureEachWithType
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
import org.jetbrains.kotlin.konan.target.presetName

private const val KOTLIN_NATIVE_CACHE_KIND = "kotlin.native.cacheKind"
private const val COMPOSE_NATIVE_MANAGE_CACHE_KIND = "compose.kotlin.native.manageCacheKind"
private const val NONE_VALUE = "none"
internal fun Project.configureNativeCompilerCaching() {
if (findProperty(COMPOSE_NATIVE_MANAGE_CACHE_KIND) == "false") return

plugins.withId(KOTLIN_MPP_PLUGIN_ID) {
val propertyFinders = listOf(
KGPPropertyFinder.GradleProperties(this),
KGPPropertyFinder.LocalProperties(this)
)

val (majorKotlinVer, minorKotlinVer) = kotlinVersionNumbers(this)

val isKotlinVersionAtLeast19 = majorKotlinVer > 1 || (majorKotlinVer == 1 && minorKotlinVer >= 9)
val isKotlinVersionBefore19 = !isKotlinVersionAtLeast19

mppExt.targets.configureEachWithType<KotlinNativeTarget> {
configureCompilerCache(propertyFinders, isKotlinVersionBefore19)
}
}
}

private fun KotlinNativeTarget.configureCompilerCache(
propertyProviders: List<KGPPropertyFinder>,
isKotlinVersionBefore19: Boolean
) {
fun String?.isNone(): Boolean =
NONE_VALUE.equals(this, ignoreCase = true)

val targetCacheKindProperty = "$KOTLIN_NATIVE_CACHE_KIND.${konanTarget.presetName}"
for (cacheKindProperty in listOf(targetCacheKindProperty, KOTLIN_NATIVE_CACHE_KIND)) {
for (provider in propertyProviders) {
val value = provider.findProperty(cacheKindProperty)
if (value.isNone()) {
project.logger.warn(
"""
|Warning: '$cacheKindProperty' is explicitly set to `none`.
|This option significantly slows the Kotlin/Native compiler.
|Compose Multiplatform Gradle plugin can set this property automatically,
|when it is necessary.
| * Recommended action: remove explicit '$cacheKindProperty=none' from ${provider.location}.
| * Alternative action: if you are sure you need '$cacheKindProperty=none', disable
|this warning by adding '$COMPOSE_NATIVE_MANAGE_CACHE_KIND=false' to your 'gradle.properties'.
""".trimMargin()
)
}

if (value != null) break
}
}

if (isKotlinVersionBefore19) {
if (project.hasProperty(targetCacheKindProperty)) {
project.setProperty(targetCacheKindProperty, NONE_VALUE)
} else {
project.extensions.extraProperties.set(targetCacheKindProperty, NONE_VALUE)
}
}
}

private data class KotlinVersionNumbers(val major: Int, val minor: Int)

private fun kotlinVersionNumbers(project: Project): KotlinVersionNumbers {
val version = project.getKotlinPluginVersion()
val versionNumbers = version.trim()
.split(".")
.take(2)
val majorPart = versionNumbers.getOrNull(0)
val minorPart = versionNumbers.getOrNull(1)
return KotlinVersionNumbers(
major = majorPart?.toIntOrNull() ?: error("Could not parse major part '$majorPart' of Kotlin plugin version: '$version'"),
minor = minorPart?.toIntOrNull() ?: error("Could not parse minor part '$minorPart' of Kotlin plugin version: '$version'"),
)
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
/*
* Copyright 2020-2023 JetBrains s.r.o. and respective authors and developers.
* Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE.txt file.
*/

package org.jetbrains.compose.internal.utils

import org.gradle.api.Project
import java.util.*

/**
* Reads Kotlin Gradle plugin properties.
*
* Kotlin Gradle plugin supports reading property from two sources:
* 1. Gradle properties. Normally located in gradle.properties file,
* but can also be provided via command-line, <GRADLE_HOME>/gradle.properties
* or can be set via Gradle API.
* 2. local.properties file. local.properties file is not supported by Gradle out-of-the-box.
* Nevertheless, it became a widespread convention.
*/
internal abstract class KGPPropertyFinder {
abstract fun findProperty(propertyName: String): String?
abstract val location: String

class GradleProperties(private val project: Project) : KGPPropertyFinder() {
override fun findProperty(propertyName: String): String? = project.findProperty(propertyName)?.toString()
override val location: String = "gradle.properties"
}

class LocalProperties(project: Project) : KGPPropertyFinder() {
private val localProperties: Properties by lazyLoadProperties(project.localPropertiesFile)
override fun findProperty(propertyName: String): String? = localProperties.getProperty(propertyName)
override val location: String = "local.properties"
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import org.gradle.api.file.FileSystemOperations
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Provider
import java.io.File
import java.util.*

internal fun Provider<String>.toDir(project: Project): Provider<Directory> =
project.layout.dir(map { File(it) })
Expand Down Expand Up @@ -55,4 +56,14 @@ internal fun FileSystemOperations.clearDirs(vararg dirs: Provider<out FileSystem
}

private fun Array<out Provider<out FileSystemLocation>>.ioFiles(): Array<File> =
let { providers -> Array(size) { i -> providers[i].ioFile } }
let { providers -> Array(size) { i -> providers[i].ioFile } }

internal fun lazyLoadProperties(propertiesFile: File): Lazy<Properties> = lazy {
Properties().apply {
if (propertiesFile.isFile) {
propertiesFile.inputStream().use {
load(it)
}
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

package org.jetbrains.compose.internal.utils

import org.gradle.api.DomainObjectCollection
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration
import org.gradle.api.logging.Logger
Expand Down Expand Up @@ -61,3 +62,13 @@ internal fun Project.detachedDependency(

internal fun Configuration.excludeTransitiveDependencies(): Configuration =
apply { isTransitive = false }

internal inline fun <reified SubT> DomainObjectCollection<*>.configureEachWithType(
crossinline fn: SubT.() -> Unit
) {
configureEach {
if (it is SubT) {
it.fn()
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -108,6 +108,31 @@ class GradlePluginTest : GradlePluginTestBase() {
}
}

@Test
fun nativeCacheKind() {
Assumptions.assumeTrue(currentOS == OS.MacOS)
fun nativeCacheKindProject(kotlinVersion: String) = testProject(
TestProjects.nativeCacheKind,
defaultTestEnvironment.copy(kotlinVersion = kotlinVersion, useGradleConfigurationCache = false)
)

val task = ":linkDebugFrameworkIosX64"
with(nativeCacheKindProject(kotlinVersion = TestKotlinVersions.v1_8_20)) {
gradle(task, "--info").checks {
check.taskSuccessful(task)
check.logDoesntContain("-Xauto-cache-from=")
}
}
testWorkDir.deleteRecursively()
testWorkDir.mkdirs()
with(nativeCacheKindProject(kotlinVersion = TestKotlinVersions.v1_9_0) ) {
gradle(task, "--info").checks {
check.taskSuccessful(task)
check.logContains("-Xauto-cache-from=")
}
}
}

@Test
fun skikoWasm() = with(
testProject(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,6 @@ package org.jetbrains.compose.test.utils

object TestKotlinVersions {
val Default = TestProperties.composeCompilerCompatibleKotlinVersion
val v1_8_20 = "1.8.20"
val v1_9_0 = "1.9.0"
}
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,5 @@ object TestProjects {
const val jvmPreview = "misc/jvmPreview"
const val iosResources = "misc/iosResources"
const val iosMokoResources = "misc/iosMokoResources"
const val nativeCacheKind = "misc/nativeCacheKind"
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
plugins {
id "org.jetbrains.kotlin.multiplatform"
id "org.jetbrains.compose"
}

kotlin {
iosX64 {
binaries.framework {
isStatic = true
baseName = "shared"
}
}
iosArm64 {
binaries.framework {
isStatic = true
baseName = "shared"
}
}

sourceSets {
commonMain {
dependencies {
implementation(compose.runtime)
implementation(compose.material)
implementation(compose.foundation)
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
org.jetbrains.compose.experimental.uikit.enabled=true
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
pluginManagement {
plugins {
id 'org.jetbrains.kotlin.multiplatform' version 'KOTLIN_VERSION_PLACEHOLDER'
id 'org.jetbrains.compose' version 'COMPOSE_GRADLE_PLUGIN_VERSION_PLACEHOLDER'
}
repositories {
mavenLocal()
gradlePluginPortal()
maven { url "https://maven.pkg.jetbrains.space/kotlin/p/kotlin/dev" }
}
}
rootProject.name = "nativeCacheKind"
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
import androidx.compose.material.Button
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue

@Composable
fun App() {
var text by remember { mutableStateOf("Hello, World!") }

MaterialTheme {
Button(onClick = {
text = "Hello, Desktop!"
}) {
Text(text)
}
}
}

0 comments on commit 1939de0

Please sign in to comment.