Fixed configuration cache misses for the second build, when K/N compiler has been downloaded with the first build

KT-61154 Fixed
This commit is contained in:
Dmitrii Krasnov
2023-08-15 12:34:42 +02:00
committed by Space Team
parent f8b789164c
commit 304cbf1aea
4 changed files with 100 additions and 4 deletions
@@ -0,0 +1,38 @@
/*
* 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.native
import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.*
import org.junit.jupiter.api.DisplayName
@DisplayName("Tests for K/N with enabled configuration cache")
@NativeGradlePluginTests
class NativeWithConfigurationCacheIT : KGPBaseTest() {
override val defaultBuildOptions: BuildOptions = super.defaultBuildOptions.copy(configurationCache = true)
@DisplayName(
"Configuration phase should be reused from configuration cache for the second build " +
"(downloading konan does not affect cache inputs)"
)
@GradleTestVersions(minVersion = TestVersions.Gradle.G_8_1) // Since 8.1 Gradle on configuration cache it detects when the build logic accesses the "outside world" more strict https://docs.gradle.org/8.1.1/release-notes.html#configuration-inputs-detection-improvements
@GradleTest
fun testConfigurationCacheReusedSecondTime(gradleVersion: GradleVersion) {
nativeProject("native-with-configuration-cache", gradleVersion, enableGradleDebug = true) {
// we need to download compiler on the first build, that is why we are setting custom konan home dir without any compiler inside
val localKonan = workingDir.resolve(".konan")
build("help", "-Pkonan.data.dir=$localKonan") {
assertOutputContains("Configure project")
assertOutputContains("Unpack Kotlin/Native compiler to")
}
build("help", "-Pkonan.data.dir=$localKonan") {
assertOutputContains("Reusing configuration cache.")
}
}
}
}
@@ -0,0 +1,22 @@
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeTarget
plugins {
kotlin("multiplatform")
}
repositories {
mavenLocal()
mavenCentral()
}
kotlin {
val nativeMain by sourceSets.creating {
dependsOn(sourceSets["commonMain"])
}
targets.withType(KotlinNativeTarget::class.java).all {
compilations["main"].defaultSourceSet.dependsOn(nativeMain)
}
<SingleNativeTarget>()
}
@@ -0,0 +1,10 @@
/*
* Copyright 2010-2020 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.
*/
import platform.posix.*
fun main() {
printf("Hello world %d", 42)
}
@@ -8,14 +8,19 @@ package org.jetbrains.kotlin.gradle.utils
import org.gradle.api.Project
import org.gradle.api.artifacts.repositories.ArtifactRepository
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.FileTree
import org.gradle.api.logging.Logger
import org.gradle.api.provider.ValueSource
import org.gradle.api.provider.ValueSourceParameters
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
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime
import org.jetbrains.kotlin.gradle.targets.native.internal.NativeDistributionType
import org.jetbrains.kotlin.gradle.targets.native.internal.NativeDistributionTypeProvider
import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGenerator
@@ -27,7 +32,7 @@ import java.nio.file.Files
class NativeCompilerDownloader(
val project: Project,
private val compilerVersion: String = project.konanVersion
private val compilerVersion: String = project.konanVersion,
) {
companion object {
@@ -35,6 +40,8 @@ class NativeCompilerDownloader(
loadPropertyFromResources("project.properties", "kotlin.native.version")
}
internal var NEED_TO_DOWNLOAD_FLAG: Boolean = true
internal const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
internal const val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
}
@@ -185,12 +192,29 @@ class NativeCompilerDownloader(
}
fun downloadIfNeeded() {
val classpath = KotlinNativeToolRunner.Settings.fromProject(project).classpath
if (classpath.isEmpty() || classpath.any { !it.exists() }) {
checkClassPath() // This is workaround to avoid double execution configuration phase. See KT-61154 for more details
if (NEED_TO_DOWNLOAD_FLAG) {
downloadAndExtract()
}
}
private fun checkClassPath() {
project.providers.of(NativeCompilerDownloaderClassPathChecker::class.java) {
it.parameters.classPath.setFrom(KotlinNativeToolRunner.Settings.fromProject(project).classpath)
}.usedAtConfigurationTime(project.configurationTimePropertiesAccessor).get()
}
internal abstract class NativeCompilerDownloaderClassPathChecker : ValueSource<Boolean, NativeCompilerDownloaderClassPathChecker.Params> {
interface Params : ValueSourceParameters {
val classPath: ConfigurableFileCollection
}
override fun obtain(): Boolean {
NEED_TO_DOWNLOAD_FLAG = parameters.classPath.files.none { it.exists() }
return true
}
}
}
internal fun Project.setupNativeCompiler(konanTarget: KonanTarget) {
@@ -204,6 +228,7 @@ internal fun Project.setupNativeCompiler(konanTarget: KonanTarget) {
}
downloader.downloadIfNeeded()
logger.info("Kotlin/Native distribution: $konanHome")
} else {
logger.info("User-provided Kotlin/Native distribution: $konanHome")
@@ -214,3 +239,4 @@ internal fun Project.setupNativeCompiler(konanTarget: KonanTarget) {
PlatformLibrariesGenerator(project, konanTarget).generatePlatformLibsIfNeeded()
}
}