[Gradle Native] Added Kotlin Native Provider to all native tasks

This provider is a first step of "Kotlin Native Toolchain".
This solves several problems:
1) Resolving K/N bundle during configuration phase ->
now it happens during execution phase
2) Downloading K/N bundle with internal mechanisms ->
now it uses Gradle dependency resolvers and Transform Artifact

^KT-58303
^KT-52567
^KT-49268
This commit is contained in:
Dmitrii Krasnov
2023-11-24 16:18:23 +01:00
committed by Space Team
parent 48f5e1d05c
commit 7165d15d59
32 changed files with 787 additions and 115 deletions
@@ -20,7 +20,12 @@ import org.gradle.api.logging.LogLevel
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.report.BuildReportType import org.jetbrains.kotlin.gradle.report.BuildReportType
import org.jetbrains.kotlin.gradle.testbase.* import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.capitalize
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.presetName
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.io.TempDir
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.readText import kotlin.io.path.readText
import kotlin.io.path.relativeTo import kotlin.io.path.relativeTo
@@ -144,6 +149,33 @@ class BuildCacheIT : KGPBaseTest() {
} }
} }
@DisplayName("Changing native toolchain location should not break build cache")
@GradleTest
fun testNativeToolchainWithBuildCache(gradleVersion: GradleVersion, @TempDir customNativeHomePath: Path) {
nativeProject("native-simple-project", gradleVersion) {
enableLocalBuildCache(localBuildCacheDir)
val buildOptionsBeforeCaching = defaultBuildOptions.copy(
nativeOptions = super.defaultBuildOptions.nativeOptions.copy(
version = TestVersions.Kotlin.STABLE_RELEASE,
distributionDownloadFromMaven = true
)
)
val nativeCompileTask = ":compileKotlin${HostManager.host.presetName.capitalize()}"
build(nativeCompileTask, buildOptions = buildOptionsBeforeCaching) {
assertTasksPackedToCache(nativeCompileTask)
}
val buildOptionsAfterCaching = buildOptionsBeforeCaching.copy(
konanDataDir = customNativeHomePath,
)
build("clean", nativeCompileTask, buildOptions = buildOptionsAfterCaching) {
assertTasksFromCache(nativeCompileTask)
}
}
}
//doesn't work for build history files approach //doesn't work for build history files approach
@DisplayName("Restore from build cache should not break incremental compilation") @DisplayName("Restore from build cache should not break incremental compilation")
@GradleTest @GradleTest
@@ -20,8 +20,13 @@ import org.gradle.api.logging.LogLevel
import org.gradle.testkit.runner.BuildResult import org.gradle.testkit.runner.BuildResult
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.testbase.* import org.jetbrains.kotlin.gradle.testbase.*
import org.jetbrains.kotlin.gradle.util.capitalize
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.presetName
import org.junit.jupiter.api.DisplayName import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.io.TempDir
import java.io.File import java.io.File
import java.nio.file.Path
import kotlin.io.path.* import kotlin.io.path.*
@DisplayName("Build cache relocation") @DisplayName("Build cache relocation")
@@ -204,9 +209,16 @@ class BuildCacheRelocationIT : KGPBaseTest() {
@DisplayName("with native project") @DisplayName("with native project")
@GradleTest @GradleTest
fun testRelocationNative(gradleVersion: GradleVersion) { fun testRelocationNative(gradleVersion: GradleVersion) {
val buildOptionsBeforeCaching = defaultBuildOptions.copy(
nativeOptions = super.defaultBuildOptions.nativeOptions.copy(
version = TestVersions.Kotlin.STABLE_RELEASE,
distributionDownloadFromMaven = true
)
)
val (firstProject, secondProject) = prepareTestProjects( val (firstProject, secondProject) = prepareTestProjects(
"native-build-cache", "native-build-cache",
gradleVersion gradleVersion,
buildOptions = buildOptionsBeforeCaching
) { ) {
val localRepoUri = it.projectPath.resolve("repo").toUri() val localRepoUri = it.projectPath.resolve("repo").toUri()
it.subProject("build-cache-app").buildGradleKts.append( it.subProject("build-cache-app").buildGradleKts.append(
@@ -276,12 +288,12 @@ class BuildCacheRelocationIT : KGPBaseTest() {
buildJdk: File? = null, buildJdk: File? = null,
additionalConfiguration: (TestProject) -> Unit = {} additionalConfiguration: (TestProject) -> Unit = {}
): Pair<TestProject, TestProject> { ): Pair<TestProject, TestProject> {
val firstProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk) { val firstProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk, forceOutput = true) {
enableLocalBuildCache(localBuildCacheDir) enableLocalBuildCache(localBuildCacheDir)
additionalConfiguration(this) additionalConfiguration(this)
} }
val secondProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk) { val secondProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk, forceOutput = true) {
enableLocalBuildCache(localBuildCacheDir) enableLocalBuildCache(localBuildCacheDir)
additionalConfiguration(this) additionalConfiguration(this)
} }
@@ -0,0 +1,144 @@
/*
* 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.jetbrains.kotlin.gradle.testbase.TestVersions.Kotlin.STABLE_RELEASE
import org.jetbrains.kotlin.gradle.util.capitalize
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.presetName
import org.junit.jupiter.api.DisplayName
import org.junit.jupiter.api.io.TempDir
import java.nio.file.Path
import kotlin.io.path.absolutePathString
import kotlin.io.path.appendText
import kotlin.test.assertContains
@DisplayName("This test class contains different scenarios with downloading Kotlin Native Compiler during build.")
@NativeGradlePluginTests
class KotlinNativeCompilerDownloadIT : KGPBaseTest() {
private val currentPlatform = HostManager.platformName()
private val nativeHostTargetName = HostManager.host.presetName
private val UNPUCK_KONAN_FINISHED_LOG =
"Moving Kotlin/Native bundle from tmp directory"
private val STABLE_VERSION_DIR_NAME = "kotlin-native-prebuilt-$currentPlatform-$STABLE_RELEASE"
private val DOWNLOAD_KONAN_FINISHED_LOG =
"Download $STABLE_VERSION_DIR_NAME.${if (HostManager.hostIsMingw) "zip" else "tar.gz"} finished,"
override val defaultBuildOptions: BuildOptions
get() = super.defaultBuildOptions.copy(
nativeOptions = super.defaultBuildOptions.nativeOptions.copy(
version = STABLE_RELEASE,
distributionDownloadFromMaven = true
)
)
@DisplayName("KT-58303: Kotlin Native must not be downloaded during configuration phase")
@GradleTest
fun shouldNotDownloadKotlinNativeOnConfigurationPhase(gradleVersion: GradleVersion, @TempDir konanTemp: Path) {
nativeProject(
"native-simple-project",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
konanDataDir = konanTemp,
),
) {
build("help") {
assertOutputDoesNotContain(DOWNLOAD_KONAN_FINISHED_LOG)
assertOutputDoesNotContain(UNPUCK_KONAN_FINISHED_LOG)
assertOutputDoesNotContain("Please wait while Kotlin/Native")
}
}
}
@DisplayName("KT-58303: Kotlin Native must be downloaded during execution phase")
@GradleTest
fun shouldDownloadKotlinNativeOnExecutionPhase(gradleVersion: GradleVersion, @TempDir konanTemp: Path) {
nativeProject(
"native-simple-project",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
konanDataDir = konanTemp,
),
) {
build("assemble") {
assertOutputDoesNotContain(DOWNLOAD_KONAN_FINISHED_LOG)
assertOutputContains(UNPUCK_KONAN_FINISHED_LOG)
assertOutputDoesNotContain("Please wait while Kotlin/Native")
}
}
}
@DisplayName("KT-58303: Downloading Kotlin Native on configuration phase(deprecated version)")
@GradleTest
fun shouldDownloadKotlinNativeOnConfigurationPhaseWithToolchainDisabled(gradleVersion: GradleVersion, @TempDir konanTemp: Path) {
nativeProject(
"native-simple-project",
gradleVersion,
buildOptions = defaultBuildOptions.copy(
konanDataDir = konanTemp,
freeArgs = listOf("-Pkotlin.native.toolchain.enabled=false"),
),
) {
build("assemble") {
assertOutputContains(DOWNLOAD_KONAN_FINISHED_LOG)
assertOutputContains("Please wait while Kotlin/Native")
}
}
}
@DisplayName("Checking multi-module native project with different path to kotlin native compiler in each module")
@GradleTest
fun multiModuleProjectWithDifferentKotlinNativeCompilers(gradleVersion: GradleVersion, @TempDir customNativeHomePath: Path) {
nativeProject("native-multi-module-project", gradleVersion, configureSubProjects = true) {
val defaultKotlinNativeHomePath =
defaultBuildOptions.konanDataDir?.toAbsolutePath()?.normalize()
?: error("Default konan data dir must be set in this test before overriding")
// setting different konan home in different subprojects
subProject("native1").gradleProperties.appendKonanToGradleProperties(customNativeHomePath.absolutePathString())
subProject("native2").gradleProperties.appendKonanToGradleProperties(defaultKotlinNativeHomePath.absolutePathString())
val buildOptions = defaultBuildOptions.copy(
konanDataDir = null,
)
build("assemble", buildOptions = buildOptions) {
// check that in first project we use k/n from custom konan location
assertNativeTasksClasspath(":native1:compileKotlin${nativeHostTargetName.capitalize()}") {
val konanLibsPath = customNativeHomePath.resolve(STABLE_VERSION_DIR_NAME).resolve("konan").resolve("lib")
assertContains(it, konanLibsPath.resolve("kotlin-native-compiler-embeddable.jar").absolutePathString())
assertContains(it, konanLibsPath.resolve("trove4j.jar").absolutePathString())
}
// check that in second project we use k/n from default konan location
assertNativeTasksClasspath(":native2:compileKotlin${nativeHostTargetName.capitalize()}") {
val konanLibsPath = defaultKotlinNativeHomePath.resolve(STABLE_VERSION_DIR_NAME).resolve("konan").resolve("lib")
assertContains(it, konanLibsPath.resolve("kotlin-native-compiler-embeddable.jar").absolutePathString())
assertContains(it, konanLibsPath.resolve("trove4j.jar").absolutePathString())
}
}
}
}
private fun Path.appendKonanToGradleProperties(konanAbsolutePathString: String) {
this.appendText(
"""
kotlin.native.home=${konanAbsolutePathString}
konan.data.dir=${konanAbsolutePathString}
""".trimIndent()
)
}
}
@@ -27,6 +27,15 @@ import kotlin.io.path.appendText
) )
@DisplayName("Tests for K/N builds with native downloading and platform libs") @DisplayName("Tests for K/N builds with native downloading and platform libs")
@NativeGradlePluginTests @NativeGradlePluginTests
@Deprecated(
message =
"""
This is deprecated test class with regression checks for old downloading logic.
We support it during migration to kotlin native toolchain.
If you want to add test here, be sure that you have added similar test with `-Pkotlin.native.toolchain.enabled=true`.
""",
ReplaceWith("NativeDownloadAndPlatformLibsIT")
)
class NativeDownloadAndPlatformLibsIT : KGPBaseTest() { class NativeDownloadAndPlatformLibsIT : KGPBaseTest() {
private val platformName: String = HostManager.platformName() private val platformName: String = HostManager.platformName()
@@ -34,6 +43,8 @@ class NativeDownloadAndPlatformLibsIT : KGPBaseTest() {
override val defaultBuildOptions: BuildOptions override val defaultBuildOptions: BuildOptions
get() = super.defaultBuildOptions.withBundledKotlinNative().copy( get() = super.defaultBuildOptions.withBundledKotlinNative().copy(
// Disabling toolchain feature for checking stable logic with downloading kotlin native
freeArgs = listOf("-Pkotlin.native.toolchain.enabled=false"),
// For each test in this class, we need to provide an isolated .konan directory, // For each test in this class, we need to provide an isolated .konan directory,
// so we create it within each test project folder // so we create it within each test project folder
konanDataDir = workingDir.resolve(".konan") konanDataDir = workingDir.resolve(".konan")
@@ -36,7 +36,7 @@ interface TestVersions {
} }
object Kotlin { object Kotlin {
const val STABLE_RELEASE = "1.9.20" const val STABLE_RELEASE = "1.9.21"
// Copied from KOTLIN_VERSION.kt file // Copied from KOTLIN_VERSION.kt file
val CURRENT val CURRENT
@@ -62,17 +62,20 @@ fun getOutputForTask(taskPath: String, output: String, logLevel: LogLevel = LogL
LogLevel.DEBUG -> taskOutputRegexForDebugLog(taskPath) LogLevel.DEBUG -> taskOutputRegexForDebugLog(taskPath)
else -> throw throw IllegalStateException("Unsupported log lever for task output was given: $logLevel") else -> throw throw IllegalStateException("Unsupported log lever for task output was given: $logLevel")
}) })
.find(output) .findAll(output)
?.let { it.groupValues[1] } .map { it.groupValues[1] }
?: error( .joinToString(System.lineSeparator())
""" .ifEmpty {
Could not find output for task $taskPath. error(
================= """
Build output is: Could not find output for task $taskPath.
$output =================
================= Build output is:
""".trimIndent() $output
) =================
""".trimIndent()
)
}
class CommandLineArguments( class CommandLineArguments(
val args: List<String>, val args: List<String>,
@@ -0,0 +1,8 @@
plugins {
kotlin("multiplatform") apply false
}
repositories {
mavenCentral()
mavenLocal()
}
@@ -0,0 +1,12 @@
plugins {
kotlin("multiplatform")
}
repositories {
mavenLocal()
mavenCentral()
}
kotlin {
<SingleNativeTarget>()
}
@@ -0,0 +1,8 @@
/*
* 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.
*/
fun main() {
println("Hello from first")
}
@@ -0,0 +1,13 @@
plugins {
kotlin("multiplatform")
}
repositories {
mavenLocal()
mavenCentral()
}
kotlin {
<SingleNativeTarget>()
}
@@ -0,0 +1,8 @@
/*
* 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.
*/
fun main() {
println("Hello from second")
}
@@ -0,0 +1,3 @@
rootProject.name = "native-multi-module-project"
include("native1")
include("native2")
@@ -0,0 +1,12 @@
plugins {
kotlin("multiplatform")
}
repositories {
mavenCentral()
mavenLocal()
}
kotlin {
<SingleNativeTarget>()
}
@@ -0,0 +1,3 @@
fun main() {
println("Hello from simple native project")
}
@@ -32,10 +32,10 @@ import java.util.*
private val Project.jvmArgs private val Project.jvmArgs
get() = PropertiesProvider(this).nativeJvmArgs?.split("\\s+".toRegex()).orEmpty() get() = PropertiesProvider(this).nativeJvmArgs?.split("\\s+".toRegex()).orEmpty()
internal val Project.konanHome: String internal val Project.konanHome: File
get() = PropertiesProvider(this).konanDataDir?.let { NativeCompilerDownloader(project).compilerDirectory.absolutePath } get() = (PropertiesProvider(this).konanDataDir?.let { NativeCompilerDownloader(project).compilerDirectory }
?: PropertiesProvider(this).nativeHome?.let { file(it).absolutePath } ?: PropertiesProvider(this).nativeHome?.let { file(it) }
?: NativeCompilerDownloader(project).compilerDirectory.absolutePath ?: NativeCompilerDownloader(project).compilerDirectory).absoluteFile
internal val Project.disableKonanDaemon: Boolean internal val Project.disableKonanDaemon: Boolean
get() = PropertiesProvider(this).nativeDisableCompilerDaemon == true get() = PropertiesProvider(this).nativeDisableCompilerDaemon == true
@@ -47,6 +47,9 @@ internal val Project.konanVersion: String
internal val Project.konanDataDir: String? internal val Project.konanDataDir: String?
get() = PropertiesProvider(this).konanDataDir get() = PropertiesProvider(this).konanDataDir
internal val Project.kotlinNativeToolchainEnabled: Boolean
get() = PropertiesProvider(this).kotlinNativeToolchainEnabled && PropertiesProvider(this).nativeDownloadFromMaven
internal fun Project.getKonanCacheKind(target: KonanTarget): NativeCacheKind { internal fun Project.getKonanCacheKind(target: KonanTarget): NativeCacheKind {
val commonCacheKind = PropertiesProvider(this).nativeCacheKind val commonCacheKind = PropertiesProvider(this).nativeCacheKind
val targetCacheKind = PropertiesProvider(this).nativeCacheKindForTarget(target) val targetCacheKind = PropertiesProvider(this).nativeCacheKindForTarget(target)
@@ -71,9 +74,9 @@ internal fun Project.getKonanParallelThreads(): Int {
private val Project.kotlinNativeCompilerJar: String private val Project.kotlinNativeCompilerJar: String
get() = if (nativeUseEmbeddableCompilerJar) get() = if (nativeUseEmbeddableCompilerJar)
"$konanHome/konan/lib/kotlin-native-compiler-embeddable.jar" "${konanHome.absolutePath}/konan/lib/kotlin-native-compiler-embeddable.jar"
else else
"$konanHome/konan/lib/kotlin-native.jar" "${konanHome.absolutePath}/konan/lib/kotlin-native.jar"
internal abstract class KotlinNativeToolRunner( internal abstract class KotlinNativeToolRunner(
protected val toolName: String, protected val toolName: String,
@@ -271,7 +274,7 @@ internal class KotlinNativeLibraryGenerationRunner(
companion object { companion object {
@Suppress("DEPRECATION") // TODO(Dmitrii Krasnov): after KT-52567 it will be possible to use GradleExecutionContext#fromTaskContext here @Suppress("DEPRECATION") // TODO(Dmitrii Krasnov): after KT-52567 it will be possible to use GradleExecutionContext#fromTaskContext here
fun fromProject(project: Project) = KotlinNativeLibraryGenerationRunner( fun fromProject(project: Project) = KotlinNativeLibraryGenerationRunner(
settings = Settings.of(project.konanHome, project.konanDataDir, project), settings = Settings.of(project.konanHome.absolutePath, project.konanDataDir, project),
executionContext = GradleExecutionContext.fromProject(project), executionContext = GradleExecutionContext.fromProject(project),
metricsReporter = GradleBuildMetricsReporter() metricsReporter = GradleBuildMetricsReporter()
) )
@@ -41,6 +41,7 @@ const val NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME = "kotlinNativeCom
const val COMPILER_CLASSPATH_CONFIGURATION_NAME = "kotlinCompilerClasspath" const val COMPILER_CLASSPATH_CONFIGURATION_NAME = "kotlinCompilerClasspath"
internal const val BUILD_TOOLS_API_CLASSPATH_CONFIGURATION_NAME = "kotlinBuildToolsApiClasspath" internal const val BUILD_TOOLS_API_CLASSPATH_CONFIGURATION_NAME = "kotlinBuildToolsApiClasspath"
internal const val KLIB_COMMONIZER_CLASSPATH_CONFIGURATION_NAME = "kotlinKlibCommonizerClasspath" internal const val KLIB_COMMONIZER_CLASSPATH_CONFIGURATION_NAME = "kotlinKlibCommonizerClasspath"
internal const val KOTLIN_NATIVE_BUNDLE_CONFIGURATION_NAME = "kotlinNativeBundleConfiguration"
private const val JAVA_TEST_FIXTURES_PLUGIN_ID = "java-test-fixtures" private const val JAVA_TEST_FIXTURES_PLUGIN_ID = "java-test-fixtures"
internal abstract class AbstractKotlinPlugin( internal abstract class AbstractKotlinPlugin(
@@ -23,6 +23,7 @@ import org.gradle.api.Project
import org.gradle.api.logging.Logger import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging import org.gradle.api.logging.Logging
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.compilerRunner.kotlinNativeToolchainEnabled
import org.jetbrains.kotlin.compilerRunner.maybeCreateCommonizerClasspathConfiguration import org.jetbrains.kotlin.compilerRunner.maybeCreateCommonizerClasspathConfiguration
import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.internal.KOTLIN_BUILD_TOOLS_API_IMPL import org.jetbrains.kotlin.gradle.internal.KOTLIN_BUILD_TOOLS_API_IMPL
@@ -43,6 +44,7 @@ import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnab
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerArtifactTypeAttribute import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropCommonizerArtifactTypeAttribute
import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropKlibLibraryElements import org.jetbrains.kotlin.gradle.targets.native.internal.CInteropKlibLibraryElements
import org.jetbrains.kotlin.gradle.targets.native.internal.CommonizerTargetAttribute import org.jetbrains.kotlin.gradle.targets.native.internal.CommonizerTargetAttribute
import org.jetbrains.kotlin.gradle.targets.native.toolchain.KotlinNativeBundleArtifactFormat
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestsRegistry import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestsRegistry
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
@@ -68,6 +70,9 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
addKotlinCompilerConfiguration(project) addKotlinCompilerConfiguration(project)
if (project.kotlinNativeToolchainEnabled) {
addKotlinNativeBundleConfiguration(project)
}
project.configurations.maybeCreateResolvable(PLUGIN_CLASSPATH_CONFIGURATION_NAME).apply { project.configurations.maybeCreateResolvable(PLUGIN_CLASSPATH_CONFIGURATION_NAME).apply {
isVisible = false isVisible = false
@@ -115,6 +120,19 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
} }
} }
private fun addKotlinNativeBundleConfiguration(project: Project) {
project.configurations
.maybeCreateResolvable(KOTLIN_NATIVE_BUNDLE_CONFIGURATION_NAME).also { configuration ->
configuration.defaultDependencies {
it.add(project.dependencies.create(NativeCompilerDownloader.getCompilerDependencyNotation(project)))
}
configuration.attributes.setAttribute(
KotlinNativeBundleArtifactFormat.attribute,
KotlinNativeBundleArtifactFormat.KotlinNativeBundleArtifactsTypes.DIRECTORY
)
}
}
private fun Project.registerDefaultVariantImplementations() { private fun Project.registerDefaultVariantImplementations() {
val factories = VariantImplementationFactoriesConfigurator.get(project.gradle) val factories = VariantImplementationFactoriesConfigurator.get(project.gradle)
factories.putIfAbsent( factories.putIfAbsent(
@@ -206,6 +224,11 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
CommonizerTargetAttribute.setupAttributesMatchingStrategy(this) CommonizerTargetAttribute.setupAttributesMatchingStrategy(this)
CInteropCommonizerArtifactTypeAttribute.setupTransform(project) CInteropCommonizerArtifactTypeAttribute.setupTransform(project)
} }
if (project.kotlinNativeToolchainEnabled) {
KotlinNativeBundleArtifactFormat.setupAttributesMatchingStrategy(this)
KotlinNativeBundleArtifactFormat.setupTransform(project)
}
} }
open fun whenBuildEvaluated(project: Project) { open fun whenBuildEvaluated(project: Project) {
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_SLOW_SOURCES_JAR_RESOLVER import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_MPP_IMPORT_ENABLE_SLOW_SOURCES_JAR_RESOLVER
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_TOOLCHAIN_ENABLED
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_USE_XCODE_MESSAGE_STYLE import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_NATIVE_USE_XCODE_MESSAGE_STYLE
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_PUBLISH_JVM_ENVIRONMENT_ATTRIBUTE import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_PUBLISH_JVM_ENVIRONMENT_ATTRIBUTE
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_RUN_COMPILER_VIA_BUILD_TOOLS_API import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_RUN_COMPILER_VIA_BUILD_TOOLS_API
@@ -501,6 +502,12 @@ internal class PropertiesProvider private constructor(private val project: Proje
val appleCopyFrameworkToBuiltProductsDir: Boolean val appleCopyFrameworkToBuiltProductsDir: Boolean
get() = booleanProperty(PropertyNames.KOTLIN_APPLE_COPY_FRAMEWORK_TO_BUILT_PRODUCTS_DIR) ?: true get() = booleanProperty(PropertyNames.KOTLIN_APPLE_COPY_FRAMEWORK_TO_BUILT_PRODUCTS_DIR) ?: true
/**
* Enables kotlin native toolchain in native projects.
*/
val kotlinNativeToolchainEnabled: Boolean
get() = booleanProperty(KOTLIN_NATIVE_TOOLCHAIN_ENABLED) ?: true
/** /**
* Allows suppressing the diagnostic [KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency]. * Allows suppressing the diagnostic [KotlinToolingDiagnostics.BuildToolsApiVersionInconsistency].
* Required only for Kotlin repo bootstrapping. * Required only for Kotlin repo bootstrapping.
@@ -643,6 +650,7 @@ internal class PropertiesProvider private constructor(private val project: Proje
val KOTLIN_USER_HOME_DIR = property("kotlin.user.home") val KOTLIN_USER_HOME_DIR = property("kotlin.user.home")
val KOTLIN_PROJECT_PERSISTENT_DIR = property("kotlin.project.persistent.dir") val KOTLIN_PROJECT_PERSISTENT_DIR = property("kotlin.project.persistent.dir")
val KOTLIN_PROJECT_PERSISTENT_DIR_GRADLE_DISABLE_WRITE = property("kotlin.project.persistent.dir.gradle.disableWrite") val KOTLIN_PROJECT_PERSISTENT_DIR_GRADLE_DISABLE_WRITE = property("kotlin.project.persistent.dir.gradle.disableWrite")
val KOTLIN_NATIVE_TOOLCHAIN_ENABLED = property("kotlin.native.toolchain.enabled")
val KOTLIN_APPLE_COPY_FRAMEWORK_TO_BUILT_PRODUCTS_DIR = property("kotlin.apple.copyFrameworkToBuiltProductsDir") val KOTLIN_APPLE_COPY_FRAMEWORK_TO_BUILT_PRODUCTS_DIR = property("kotlin.apple.copyFrameworkToBuiltProductsDir")
/** /**
@@ -69,7 +69,7 @@ abstract class KonanPropertiesBuildService : BuildService<KonanPropertiesBuildSe
companion object { companion object {
fun registerIfAbsent(project: Project): Provider<KonanPropertiesBuildService> = fun registerIfAbsent(project: Project): Provider<KonanPropertiesBuildService> =
project.gradle.sharedServices.registerIfAbsent(serviceName, KonanPropertiesBuildService::class.java) { service -> project.gradle.sharedServices.registerIfAbsent(serviceName, KonanPropertiesBuildService::class.java) { service ->
service.parameters.konanHome.set(project.rootProject.konanHome) service.parameters.konanHome.set(project.rootProject.konanHome.absolutePath)
}.also { serviceProvider -> }.also { serviceProvider ->
SingleActionPerProject.run(project, UsesKonanPropertiesBuildService::class.java.name) { SingleActionPerProject.run(project, UsesKonanPropertiesBuildService::class.java.name) {
project.tasks.withType<UsesKonanPropertiesBuildService>().configureEach { task -> project.tasks.withType<UsesKonanPropertiesBuildService>().configureEach { task ->
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project import org.gradle.api.Project
import org.jetbrains.kotlin.compilerRunner.konanHome import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.compilerRunner.kotlinNativeToolchainEnabled
import org.jetbrains.kotlin.gradle.DeprecatedTargetPresetApi import org.jetbrains.kotlin.gradle.DeprecatedTargetPresetApi
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.targets.android.internal.InternalKotlinTargetPreset import org.jetbrains.kotlin.gradle.targets.android.internal.InternalKotlinTargetPreset
@@ -36,7 +37,7 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
private fun setupNativeHomePrivateProperty() = with(project) { private fun setupNativeHomePrivateProperty() = with(project) {
if (!hasProperty(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY)) if (!hasProperty(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY))
extensions.extraProperties.set(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY, konanHome) extensions.extraProperties.set(KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY, konanHome.absolutePath)
} }
protected abstract fun createTargetConfigurator(): AbstractKotlinTargetConfigurator<T> protected abstract fun createTargetConfigurator(): AbstractKotlinTargetConfigurator<T>
@@ -44,7 +45,9 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
protected abstract fun instantiateTarget(name: String): T protected abstract fun instantiateTarget(name: String): T
override fun createTargetInternal(name: String): T { override fun createTargetInternal(name: String): T {
project.setupNativeCompiler(konanTarget) if (!project.kotlinNativeToolchainEnabled) {
project.setupNativeCompiler(konanTarget)
}
val result = instantiateTarget(name).apply { val result = instantiateTarget(name).apply {
targetName = name targetName = name
@@ -22,7 +22,6 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor import org.jetbrains.kotlin.gradle.plugin.internal.configurationTimePropertiesAccessor
import org.jetbrains.kotlin.gradle.plugin.internal.usedAtConfigurationTime 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.NativeDistributionTypeProvider
import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGenerator import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGenerator
import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.HostManager
@@ -34,7 +33,6 @@ import java.nio.file.Files
class NativeCompilerDownloader( class NativeCompilerDownloader(
val project: Project, val project: Project,
private val compilerVersion: String = project.konanVersion,
) { ) {
companion object { companion object {
@@ -46,27 +44,36 @@ class NativeCompilerDownloader(
internal const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds" internal const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
internal const val KOTLIN_GROUP_ID = "org.jetbrains.kotlin" internal const val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
}
val compilerDirectory: File internal fun getCompilerDependencyNotation(project: Project): Map<String, String> {
get() = DependencyDirectories return mapOf(
.getLocalKonanDir(project.konanDataDir) "group" to KOTLIN_GROUP_ID,
.resolve(dependencyNameWithOsAndVersion) "name" to getDependencyName(project),
"version" to getCompilerVersion(project),
"classifier" to simpleOsName,
"ext" to archiveExtension
)
}
private val logger: Logger internal fun getCompilerDirectory(project: Project): File {
get() = project.logger return DependencyDirectories
.getLocalKonanDir(project.konanDataDir)
.resolve(getDependencyNameWithOsAndVersion(project))
}
private val kotlinProperties get() = PropertiesProvider(project) internal fun getDependencyNameWithOsAndVersion(project: Project): String {
return "${getDependencyName(project)}-$simpleOsName-${getCompilerVersion(project)}"
}
private val distributionType: NativeDistributionType
get() = NativeDistributionTypeProvider(project).getDistributionType()
private val simpleOsName: String private val simpleOsName = HostManager.platformName()
get() = HostManager.platformName()
private val dependencyName: String private fun getCompilerVersion(project: Project): String {
get() { return project.konanVersion
val dependencySuffix = distributionType.suffix }
private fun getDependencyName(project: Project): String {
val dependencySuffix = NativeDistributionTypeProvider(project).getDistributionType().suffix
return if (dependencySuffix != null) { return if (dependencySuffix != null) {
"kotlin-native-$dependencySuffix" "kotlin-native-$dependencySuffix"
} else { } else {
@@ -74,22 +81,32 @@ class NativeCompilerDownloader(
} }
} }
private val archiveExtension
get() = if (useZip) {
"zip"
} else {
"tar.gz"
}
private val useZip = HostManager.hostIsMingw
}
val compilerDirectory: File
get() = getCompilerDirectory(project)
private val logger: Logger
get() = project.logger
private val kotlinProperties get() = PropertiesProvider(project)
private val dependencyNameWithOsAndVersion: String private val dependencyNameWithOsAndVersion: String
get() = "$dependencyName-$simpleOsName-$compilerVersion" get() = getDependencyNameWithOsAndVersion(project)
private val dependencyFileName: String private val dependencyFileName: String
get() = "$dependencyNameWithOsAndVersion.$archiveExtension" get() = "$dependencyNameWithOsAndVersion.$archiveExtension"
private val useZip
get() = HostManager.hostIsMingw
private val archiveExtension
get() = if (useZip) {
"zip"
} else {
"tar.gz"
}
private fun archiveFileTree(archive: File): FileTree = private fun archiveFileTree(archive: File): FileTree =
if (useZip) { if (useZip) {
project.zipTree(archive) project.zipTree(archive)
@@ -114,11 +131,11 @@ class NativeCompilerDownloader(
} }
private val repoUrl by lazy { private val repoUrl by lazy {
val maturity = KotlinToolingVersion(compilerVersion).maturity val maturity = KotlinToolingVersion(getCompilerVersion(project)).maturity
buildString { buildString {
append("${kotlinProperties.nativeBaseDownloadUrl}/") append("${kotlinProperties.nativeBaseDownloadUrl}/")
append(if (maturity == KotlinToolingVersion.Maturity.DEV) "dev/" else "releases/") append(if (maturity == KotlinToolingVersion.Maturity.DEV) "dev/" else "releases/")
append("$compilerVersion/") append("${getCompilerVersion(project)}/")
append(simpleOsName) append(simpleOsName)
} }
} }
@@ -129,27 +146,19 @@ class NativeCompilerDownloader(
} else null } else null
val compilerDependency = if (kotlinProperties.nativeDownloadFromMaven) { val compilerDependency = if (kotlinProperties.nativeDownloadFromMaven) {
project.dependencies.create( project.dependencies.create(getCompilerDependencyNotation(project))
mapOf(
"group" to KOTLIN_GROUP_ID,
"name" to dependencyName,
"version" to compilerVersion,
"classifier" to simpleOsName,
"ext" to archiveExtension
)
)
} else { } else {
project.dependencies.create( project.dependencies.create(
mapOf( mapOf(
"name" to "$dependencyName-$simpleOsName", "name" to "${getDependencyName(project)}-$simpleOsName",
"version" to compilerVersion, "version" to getCompilerVersion(project),
"ext" to archiveExtension "ext" to archiveExtension
) )
) )
} }
val configuration = project.configurations.detachedResolvable(compilerDependency) val configuration = project.configurations.detachedResolvable(compilerDependency)
logger.lifecycle("\nPlease wait while Kotlin/Native compiler $compilerVersion is being installed.") logger.lifecycle("\nPlease wait while Kotlin/Native compiler ${getCompilerVersion(project)} is being installed.")
if (!kotlinProperties.nativeDownloadFromMaven) { if (!kotlinProperties.nativeDownloadFromMaven) {
val dependencyUrl = "$repoUrl/$dependencyFileName" val dependencyUrl = "$repoUrl/$dependencyFileName"
@@ -162,6 +171,12 @@ class NativeCompilerDownloader(
configuration.files.single() configuration.files.single()
} }
extractKotlinNativeFromArchive(archive)
if (repo != null) removeRepo(repo)
}
private fun extractKotlinNativeFromArchive(archive: File) {
logger.kotlinInfo("Using Kotlin/Native compiler archive: ${archive.absolutePath}") logger.kotlinInfo("Using Kotlin/Native compiler archive: ${archive.absolutePath}")
logger.lifecycle("Unpack Kotlin/Native compiler to $compilerDirectory") logger.lifecycle("Unpack Kotlin/Native compiler to $compilerDirectory")
@@ -186,8 +201,6 @@ class NativeCompilerDownloader(
tmpDir.deleteRecursively() tmpDir.deleteRecursively()
} }
} }
if (repo != null) removeRepo(repo)
} }
fun downloadIfNeeded() { fun downloadIfNeeded() {
@@ -199,11 +212,12 @@ class NativeCompilerDownloader(
private fun checkClassPath() { private fun checkClassPath() {
project.providers.of(NativeCompilerDownloaderClassPathChecker::class.java) { project.providers.of(NativeCompilerDownloaderClassPathChecker::class.java) {
it.parameters.classPath.setFrom(KotlinNativeToolRunner.Settings.of(project.konanHome, project.konanDataDir, project).classpath) it.parameters.classPath.setFrom(KotlinNativeToolRunner.Settings.of(project.konanHome.absolutePath, project.konanDataDir, project).classpath)
}.usedAtConfigurationTime(project.configurationTimePropertiesAccessor).get() }.usedAtConfigurationTime(project.configurationTimePropertiesAccessor).get()
} }
internal abstract class NativeCompilerDownloaderClassPathChecker : ValueSource<Boolean, NativeCompilerDownloaderClassPathChecker.Params> { internal abstract class NativeCompilerDownloaderClassPathChecker :
ValueSource<Boolean, NativeCompilerDownloaderClassPathChecker.Params> {
interface Params : ValueSourceParameters { interface Params : ValueSourceParameters {
val classPath: ConfigurableFileCollection val classPath: ConfigurableFileCollection
@@ -216,6 +230,19 @@ class NativeCompilerDownloader(
} }
} }
/**
* Sets up the Kotlin/Native compiler for the given project.
*
* @param konanTarget The target platform for the Kotlin/Native compiler.
*/
@Deprecated(
message = "This is old k/n downloading method that is used on configuration phase",
replaceWith = ReplaceWith(
"KotlinNativeInstaller",
"org.jetbrains.kotlin.gradle.targets.native.toolchain.KotlinNativeInstaller"
),
level = DeprecationLevel.WARNING
)
internal fun Project.setupNativeCompiler(konanTarget: KonanTarget) { internal fun Project.setupNativeCompiler(konanTarget: KonanTarget) {
val isKonanHomeOverridden = kotlinPropertiesProvider.nativeHome != null val isKonanHomeOverridden = kotlinPropertiesProvider.nativeHome != null
if (!isKonanHomeOverridden) { if (!isKonanHomeOverridden) {
@@ -227,9 +254,9 @@ internal fun Project.setupNativeCompiler(konanTarget: KonanTarget) {
} }
downloader.downloadIfNeeded() downloader.downloadIfNeeded()
logger.info("Kotlin/Native distribution: $konanHome") logger.info("Kotlin/Native distribution: ${konanHome.absolutePath}")
} else { } else {
logger.info("User-provided Kotlin/Native distribution: $konanHome") logger.info("User-provided Kotlin/Native distribution: ${konanHome.absolutePath}")
} }
val distributionType = NativeDistributionTypeProvider(project).getDistributionType() val distributionType = NativeDistributionTypeProvider(project).getDistributionType()
@@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentHashMap
internal class PlatformLibrariesGenerator(val project: Project, val konanTarget: KonanTarget) { internal class PlatformLibrariesGenerator(val project: Project, val konanTarget: KonanTarget) {
private val distribution = private val distribution =
customerDistribution(project.konanHome, konanDataDir = project.konanDataDir) customerDistribution(project.konanHome.absolutePath, konanDataDir = project.konanDataDir)
private val platformLibsDirectory = private val platformLibsDirectory =
File(distribution.platformLibs(konanTarget)).absoluteFile File(distribution.platformLibs(konanTarget)).absoluteFile
@@ -77,7 +77,7 @@ internal class PlatformLibrariesGenerator(val project: Project, val konanTarget:
} }
val cacheDirectory = CacheBuilder.getRootCacheDirectory( val cacheDirectory = CacheBuilder.getRootCacheDirectory(
File(project.konanHome), konanTarget, true, konanCacheKind project.konanHome, konanTarget, true, konanCacheKind
) )
return presentDefs.toPlatformLibNames().all { return presentDefs.toPlatformLibNames().all {
cacheDirectory.resolve(CacheBuilder.getCacheFileName(it, konanCacheKind)).listFilesOrEmpty().isNotEmpty() cacheDirectory.resolve(CacheBuilder.getCacheFileName(it, konanCacheKind)).listFilesOrEmpty().isNotEmpty()
@@ -115,7 +115,7 @@ internal class PlatformLibrariesGenerator(val project: Project, val konanTarget:
args.addArg("-cache-kind", konanCacheKind.produce!!) args.addArg("-cache-kind", konanCacheKind.produce!!)
args.addArg( args.addArg(
"-cache-directory", "-cache-directory",
CacheBuilder.getRootCacheDirectory(File(konanHome), konanTarget, true, konanCacheKind).absolutePath CacheBuilder.getRootCacheDirectory(konanHome, konanTarget, true, konanCacheKind).absolutePath
) )
args.addArg("-cache-arg", "-g") args.addArg("-cache-arg", "-g")
val additionalCacheFlags = konanPropertiesService.additionalCacheFlags(konanTarget) val additionalCacheFlags = konanPropertiesService.additionalCacheFlags(konanTarget)
@@ -32,6 +32,7 @@ import org.jetbrains.kotlin.gradle.plugin.usesPlatformOf
import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService
import org.jetbrains.kotlin.gradle.targets.native.UsesKonanPropertiesBuildService import org.jetbrains.kotlin.gradle.targets.native.UsesKonanPropertiesBuildService
import org.jetbrains.kotlin.gradle.targets.native.tasks.CompilerPluginData import org.jetbrains.kotlin.gradle.targets.native.tasks.CompilerPluginData
import org.jetbrains.kotlin.gradle.targets.native.toolchain.KotlinNativeProvider
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -62,14 +63,6 @@ constructor(
val compilation: KotlinNativeCompilation val compilation: KotlinNativeCompilation
get() = binary.compilation get() = binary.compilation
@get:Internal
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir }
@get:Internal
val konanHome: Provider<String> = project.provider { project.konanHome }
private val runnerSettings = KotlinNativeCompilerRunner.Settings.of(konanHome.get(), konanDataDir.getOrNull(), project)
final override val toolOptions: KotlinCommonCompilerToolOptions = objectFactory final override val toolOptions: KotlinCommonCompilerToolOptions = objectFactory
.newInstance<KotlinCommonCompilerToolOptionsDefault>() .newInstance<KotlinCommonCompilerToolOptionsDefault>()
@@ -206,17 +199,29 @@ constructor(
private val externalDependenciesArgs by lazy { ExternalDependenciesBuilder(project, compilation).buildCompilerArgs() } private val externalDependenciesArgs by lazy { ExternalDependenciesBuilder(project, compilation).buildCompilerArgs() }
private val cacheBuilderSettings by lazy { private val cacheBuilderSettings by lazy {
CacheBuilder.Settings.createWithProject(konanHome.get(), konanDataDir.getOrNull(), project, binary, konanTarget, toolOptions, externalDependenciesArgs) CacheBuilder.Settings.createWithProject(
kotlinNativeProvider.get().bundleDirectory.getFile().absolutePath,
kotlinNativeProvider.get().konanDataDir.orNull,
project,
binary,
konanTarget,
toolOptions,
externalDependenciesArgs
)
} }
private class CacheSettings(val orchestration: NativeCacheOrchestration, val kind: NativeCacheKind, private class CacheSettings(
val icEnabled: Boolean, val threads: Int, val orchestration: NativeCacheOrchestration, val kind: NativeCacheKind,
val gradleUserHomeDir: File, val gradleBuildDir: File) val icEnabled: Boolean, val threads: Int,
val gradleUserHomeDir: File, val gradleBuildDir: File,
)
private val cacheSettings by lazy { private val cacheSettings by lazy {
CacheSettings(project.getKonanCacheOrchestration(), project.getKonanCacheKind(konanTarget), CacheSettings(
project.isKonanIncrementalCompilationEnabled(), project.getKonanParallelThreads(), project.getKonanCacheOrchestration(), project.getKonanCacheKind(konanTarget),
project.gradle.gradleUserHomeDir, project.layout.buildDirectory.get().asFile) project.isKonanIncrementalCompilationEnabled(), project.getKonanParallelThreads(),
project.gradle.gradleUserHomeDir, project.layout.buildDirectory.get().asFile
)
} }
override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create<K2NativeCompilerArguments> { override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create<K2NativeCompilerArguments> {
@@ -343,6 +348,31 @@ constructor(
@get:Nested @get:Nested
var kotlinPluginData: Provider<KotlinCompilerPluginData>? = null var kotlinPluginData: Provider<KotlinCompilerPluginData>? = null
@get:Nested
internal val kotlinNativeProvider: Provider<KotlinNativeProvider> = project.provider {
KotlinNativeProvider(project, konanTarget)
}
@Deprecated(
message = "This property as a konanHome will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.konanDataDir")
)
@get:Internal
val konanDataDir: Provider<String?> = kotlinNativeProvider.flatMap { it.konanDataDir }
@Deprecated(
message = "This property as a konanDataDir will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.compilerDirectory")
)
@get:Internal
val konanHome: Provider<String> = kotlinNativeProvider.map { it.bundleDirectory.get().asFile.absolutePath }
private val runnerSettings = KotlinNativeCompilerRunner.Settings.of(
kotlinNativeProvider.get().bundleDirectory.getFile().absolutePath,
kotlinNativeProvider.get().konanDataDir.orNull,
project
)
@TaskAction @TaskAction
fun compile() { fun compile() {
val metricsReporter = metrics.get() val metricsReporter = metrics.get()
@@ -39,9 +39,9 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.statistics.UsesBuildFusService import org.jetbrains.kotlin.gradle.plugin.statistics.UsesBuildFusService
import org.jetbrains.kotlin.gradle.report.* import org.jetbrains.kotlin.gradle.report.*
import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService
import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService
import org.jetbrains.kotlin.gradle.targets.native.tasks.* import org.jetbrains.kotlin.gradle.targets.native.tasks.*
import org.jetbrains.kotlin.gradle.targets.native.toolchain.KotlinNativeProvider
import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.GradleLoggerAdapter import org.jetbrains.kotlin.gradle.utils.GradleLoggerAdapter
import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty
@@ -276,11 +276,6 @@ abstract class AbstractKotlinNativeCompile<
} }
// Remove it once actual K2NativeCompilerArguments will be available without 'kotlin.native.enabled = true' flag
class StubK2NativeCompilerArguments : CommonCompilerArguments() {
override fun copyOf(): Freezable = copyCommonCompilerArguments(this, StubK2NativeCompilerArguments())
}
/** /**
* A task producing a klibrary from a compilation. * A task producing a klibrary from a compilation.
*/ */
@@ -336,11 +331,24 @@ internal constructor(
@get:Internal // these sources are normally a subset of `source` ones which are already tracked @get:Internal // these sources are normally a subset of `source` ones which are already tracked
val commonSources: ConfigurableFileCollection = project.files() val commonSources: ConfigurableFileCollection = project.files()
@get:Internal @get:Nested
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir } internal val kotlinNativeProvider: Provider<KotlinNativeProvider> = project.provider {
KotlinNativeProvider(project, konanTarget)
}
@Deprecated(
message = "This property as a konanHome will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.konanDataDir")
)
@get:Internal @get:Internal
val konanHome: Provider<String> = project.provider { project.konanHome } val konanDataDir: Provider<String?> = kotlinNativeProvider.flatMap { it.konanDataDir }
@Deprecated(
message = "This property as a konanDataDir will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.compilerDirectory")
)
@get:Internal
val konanHome: Provider<String> = kotlinNativeProvider.map { it.bundleDirectory.get().asFile.absolutePath }
@get:Nested @get:Nested
override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance() override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance()
@@ -410,7 +418,11 @@ internal constructor(
override val additionalCompilerOptions: Provider<Collection<String>> override val additionalCompilerOptions: Provider<Collection<String>>
get() = compilerOptions.freeCompilerArgs as Provider<Collection<String>> get() = compilerOptions.freeCompilerArgs as Provider<Collection<String>>
private val runnerSettings = KotlinNativeCompilerRunner.Settings.of(konanHome.get(), konanDataDir.getOrNull(), project) private val runnerSettings = KotlinNativeCompilerRunner.Settings.of(
kotlinNativeProvider.get().bundleDirectory.getFile().absolutePath,
kotlinNativeProvider.get().konanDataDir.orNull,
project
)
// endregion. // endregion.
@Suppress("DeprecatedCallableAddReplaceWith") @Suppress("DeprecatedCallableAddReplaceWith")
@@ -1077,13 +1089,30 @@ abstract class CInteropProcess @Inject internal constructor(params: Params) :
val outputFile: File val outputFile: File
get() = outputFileProvider.get() get() = outputFileProvider.get()
@get:Internal @get:Nested
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir } internal val kotlinNativeProvider: Provider<KotlinNativeProvider> = project.provider {
KotlinNativeProvider(project, konanTarget)
}
@Deprecated(
message = "This property as a konanHome will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.konanDataDir")
)
@get:Internal @get:Internal
val konanHome: Provider<String> = project.provider { project.konanHome } val konanDataDir: Provider<String?> = kotlinNativeProvider.flatMap { it.konanDataDir }
private val runnerSettings = KotlinNativeToolRunner.Settings.of(konanHome.get(), konanDataDir.getOrNull(), project) @Deprecated(
message = "This property as a konanDataDir will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.compilerDirectory")
)
@get:Internal
val konanHome: Provider<String> = kotlinNativeProvider.map { it.bundleDirectory.get().asFile.absolutePath }
private val runnerSettings = KotlinNativeToolRunner.Settings.of(
kotlinNativeProvider.get().bundleDirectory.getFile().absolutePath,
kotlinNativeProvider.get().konanDataDir.orNull,
project
)
// Inputs and outputs. // Inputs and outputs.
@OutputFile @OutputFile
@@ -23,10 +23,8 @@ import org.gradle.work.DisableCachingByDefault
import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter import org.jetbrains.kotlin.build.report.metrics.BuildMetricsReporter
import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric import org.jetbrains.kotlin.build.report.metrics.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.compilerRunner.*
import org.jetbrains.kotlin.compilerRunner.KotlinNativeCompilerRunner import org.jetbrains.kotlin.compilerRunner.KotlinNativeCompilerRunner
import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner
import org.jetbrains.kotlin.compilerRunner.konanDataDir
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.compilerRunner.addBuildMetricsForTaskAction import org.jetbrains.kotlin.compilerRunner.addBuildMetricsForTaskAction
import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated import org.jetbrains.kotlin.gradle.internal.ensureParentDirsCreated
@@ -35,8 +33,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.BitcodeEmbeddingMode
import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter import org.jetbrains.kotlin.gradle.report.GradleBuildMetricsReporter
import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService import org.jetbrains.kotlin.gradle.report.UsesBuildMetricsService
import org.jetbrains.kotlin.gradle.targets.native.tasks.buildKotlinNativeBinaryLinkerArgs import org.jetbrains.kotlin.gradle.targets.native.tasks.buildKotlinNativeBinaryLinkerArgs
import org.jetbrains.kotlin.gradle.targets.native.toolchain.KotlinNativeProvider
import org.jetbrains.kotlin.gradle.tasks.KotlinToolTask import org.jetbrains.kotlin.gradle.tasks.KotlinToolTask
import org.jetbrains.kotlin.gradle.utils.XcodeUtils import org.jetbrains.kotlin.gradle.utils.XcodeUtils
import org.jetbrains.kotlin.gradle.utils.getFile
import org.jetbrains.kotlin.gradle.utils.newInstance import org.jetbrains.kotlin.gradle.utils.newInstance
import org.jetbrains.kotlin.gradle.utils.property import org.jetbrains.kotlin.gradle.utils.property
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -170,13 +170,30 @@ abstract class KotlinNativeLinkArtifactTask @Inject constructor(
val metrics: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>> = project.objects val metrics: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>> = project.objects
.property(GradleBuildMetricsReporter()) .property(GradleBuildMetricsReporter())
@get:Internal @get:Nested
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir } internal val kotlinNativeProvider: Provider<KotlinNativeProvider> = project.provider {
KotlinNativeProvider(project, konanTarget)
}
@Deprecated(
message = "This property as a konanHome will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.konanDataDir")
)
@get:Internal @get:Internal
val konanHome: Provider<String> = project.provider { project.konanHome } val konanDataDir: Provider<String?> = kotlinNativeProvider.flatMap { it.konanDataDir }
private val runnerSettings = KotlinNativeCompilerRunner.Settings.of(konanHome.get(), konanDataDir.getOrNull(), project) @Deprecated(
message = "This property as a konanDataDir will be squashed into one in future releases.",
replaceWith = ReplaceWith("kotlinNativeProvider.compilerDirectory")
)
@get:Internal
val konanHome: Provider<String> = kotlinNativeProvider.map { it.bundleDirectory.get().asFile.absolutePath }
private val runnerSettings = KotlinNativeCompilerRunner.Settings.of(
kotlinNativeProvider.get().bundleDirectory.getFile().absolutePath,
kotlinNativeProvider.get().konanDataDir.orNull,
project
)
init { init {
baseName.convention(project.name) baseName.convention(project.name)
@@ -0,0 +1,57 @@
/*
* 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.targets.native.toolchain
import org.gradle.api.Project
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributesSchema
import org.jetbrains.kotlin.gradle.utils.setAttribute
/**
* This class provides functionality for setting up attributes matching strategy and
* transformation for a Kotlin Native Bundle configurations.
*
* @property attribute The attribute object representing the Kotlin Native Bundle type.
*/
internal object KotlinNativeBundleArtifactFormat {
val attribute: Attribute<KotlinNativeBundleArtifactsTypes> =
Attribute.of("kotlin.native.bundle.type", KotlinNativeBundleArtifactsTypes::class.java)
internal enum class KotlinNativeBundleArtifactsTypes {
ARCHIVE,
DIRECTORY
}
/**
* Sets up the attributes matching strategy for the given attributes schema.
*
* @param attributesSchema The attributes schema to set up the matching strategy for.
*/
internal fun setupAttributesMatchingStrategy(attributesSchema: AttributesSchema) {
attributesSchema.attribute(attribute)
}
/**
* Sets up the necessary transformations for handling artifact types "tar.gz" and "zip" in the given project.
*
* @param project The project in which to set up the transformations.
*/
internal fun setupTransform(project: Project) {
project.dependencies.artifactTypes.maybeCreate("tar.gz").also { artifactType ->
artifactType.attributes.setAttribute(attribute, KotlinNativeBundleArtifactsTypes.ARCHIVE)
}
project.dependencies.artifactTypes.maybeCreate("zip").also { artifactType ->
artifactType.attributes.setAttribute(attribute, KotlinNativeBundleArtifactsTypes.ARCHIVE)
}
project.dependencies.registerTransform(UnzipTransformationAction::class.java) { transform ->
transform.from.setAttribute(attribute, KotlinNativeBundleArtifactsTypes.ARCHIVE)
transform.to.setAttribute(attribute, KotlinNativeBundleArtifactsTypes.DIRECTORY)
}
}
}
@@ -0,0 +1,110 @@
/*
* 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.targets.native.toolchain
import org.gradle.api.Project
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.Internal
import org.jetbrains.kotlin.compilerRunner.konanDataDir
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.compilerRunner.kotlinNativeToolchainEnabled
import org.jetbrains.kotlin.gradle.plugin.KOTLIN_NATIVE_BUNDLE_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.targets.native.internal.NativeDistributionTypeProvider
import org.jetbrains.kotlin.gradle.targets.native.internal.PlatformLibrariesGenerator
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
import org.jetbrains.kotlin.gradle.utils.filesProvider
import org.jetbrains.kotlin.gradle.utils.property
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
/**
* This is a nested provider for all native tasks
*/
internal class KotlinNativeProvider(project: Project, konanTarget: KonanTarget) {
@get:Internal
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir }
@get:Internal
val bundleDirectory: DirectoryProperty = project.objects.directoryProperty().fileProvider(
project.provider {
project.konanHome
}
)
@get:Internal
val reinstallBundle: Property<Boolean> = project.objects.property(project.kotlinPropertiesProvider.nativeReinstall)
@get:Input
internal val kotlinNativeBundleVersion: Provider<String> = bundleDirectory.zip(reinstallBundle) { bundleDir, reinstallFlag ->
val kotlinNativeVersion = NativeCompilerDownloader.getDependencyNameWithOsAndVersion(project)
if (project.kotlinNativeToolchainEnabled && (reinstallFlag || !bundleDir.asFile.exists())) {
val kotlinNativeCompilerExtractedFolder =
kotlinNativeCompilerConfiguration
.singleOrNull()
?.resolve(kotlinNativeVersion)
?: error(
"Kotlin Native dependency has not been properly resolved. " +
"Please, make sure that you've declared the repository, which contains $kotlinNativeVersion."
)
project.prepareKotlinNativeBundle(
bundleDir.asFile,
reinstallFlag,
kotlinNativeCompilerExtractedFolder,
konanTarget
)
}
kotlinNativeVersion
}
private val kotlinNativeCompilerConfiguration: ConfigurableFileCollection = project.filesProvider {
// without enabled there is no configuration with this name, so we should return empty provider to support configuraiton cache
if (project.kotlinNativeToolchainEnabled) {
project.configurations.named(
KOTLIN_NATIVE_BUNDLE_CONFIGURATION_NAME
)
} else {
null
}
}
private fun Project.prepareKotlinNativeBundle(
bundleDir: File,
reinstallFlag: Boolean,
gradleCachesKotlinNativeDir: File,
konanTarget: KonanTarget,
) {
if (reinstallFlag) {
NativeCompilerDownloader.getCompilerDirectory(project).deleteRecursively()
}
if (!bundleDir.exists()) {
logger.info("Moving Kotlin/Native bundle from tmp directory $gradleCachesKotlinNativeDir to ${bundleDir.absolutePath}")
copy {
it.from(gradleCachesKotlinNativeDir)
it.into(bundleDir)
}
logger.info("Moved Kotlin/Native bundle from $gradleCachesKotlinNativeDir to ${bundleDir.absolutePath}")
}
setupKotlinNativeDependencies(konanTarget)
}
private fun Project.setupKotlinNativeDependencies(konanTarget: KonanTarget) {
val distributionType = NativeDistributionTypeProvider(this).getDistributionType()
if (distributionType.mustGeneratePlatformLibs) {
PlatformLibrariesGenerator(project, konanTarget).generatePlatformLibsIfNeeded()
}
}
}
@@ -0,0 +1,59 @@
/*
* 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.targets.native.toolchain
import org.gradle.api.artifacts.transform.InputArtifact
import org.gradle.api.artifacts.transform.TransformAction
import org.gradle.api.artifacts.transform.TransformOutputs
import org.gradle.api.artifacts.transform.TransformParameters
import org.gradle.api.file.ArchiveOperations
import org.gradle.api.file.FileSystemLocation
import org.gradle.api.file.FileSystemOperations
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.PathSensitive
import org.gradle.api.tasks.PathSensitivity
import org.gradle.work.DisableCachingByDefault
import java.io.File
import javax.inject.Inject
private const val EXTRACTED_ARCHIVE_RELATED_PATH = "extracted"
/**
* An implementation of a gradle [TransformAction] to unzip configurations' artifacts in `tar.gz` and `zip` formats.
*/
@DisableCachingByDefault(because = "Does only I/O")
abstract class UnzipTransformationAction : TransformAction<TransformParameters.None> {
@get:Inject
abstract val archiveOperations: ArchiveOperations
@get:Inject
abstract val fileSystemOperations: FileSystemOperations
@get:InputArtifact
@get:PathSensitive(PathSensitivity.RELATIVE)
abstract val inputArtifact: Provider<FileSystemLocation>
override fun transform(outputs: TransformOutputs) {
val input = inputArtifact.get().asFile
val unzipDir = outputs.dir(EXTRACTED_ARCHIVE_RELATED_PATH)
unzipTo(input, unzipDir)
}
private fun unzipTo(archive: File, outputDir: File) {
fileSystemOperations.copy {
it.from(
when {
archive.name.endsWith("zip") -> archiveOperations.zipTree(archive)
archive.name.endsWith(".tar.gz") -> archiveOperations.tarTree(archive)
else -> error("Unsupported format for unzipping $archive")
}
)
it.into(outputDir)
}
}
}
@@ -0,0 +1,39 @@
/*
* Copyright 2010-2024 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.unitTests
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.extraProperties
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP
import org.jetbrains.kotlin.konan.target.HostManager
import kotlin.test.Ignore
import kotlin.test.Test
import kotlin.test.assertEquals
private const val STABLE_VERSION = "1.9.20"
@Ignore(value = "We need to provide proper way of validating k/n dependencies: KT-52483")
class KotlinNativeToolchainTest {
@Test
fun `check that kotlin native compiler stable version has been resolved correctly`() {
val project = buildProjectWithMPP {
project.multiplatformExtension.linuxX64()
project.extraProperties.set("kotlin.native.version", STABLE_VERSION)
project.extraProperties.set("kotlin.native.distribution.downloadFromMaven", true)
}
project.evaluate()
val compileTask = project.tasks.withType(KotlinNativeCompile::class.java).first()
assertEquals(
"kotlin-native-prebuilt-${HostManager.platformName()}-$STABLE_VERSION",
compileTask.kotlinNativeProvider.get().kotlinNativeBundleVersion.get()
)
}
}
@@ -20,9 +20,6 @@ internal val konanHome: File by lazy {
.run { .run {
project.plugins.apply("kotlin-multiplatform") project.plugins.apply("kotlin-multiplatform")
// TODO(Dmitrii Krasnov): remove this, when KT-58303 is done
project.extraProperties.set("kotlin.native.distribution.downloadFromMaven","false")
(project.kotlinExtension as KotlinMultiplatformExtension).apply { (project.kotlinExtension as KotlinMultiplatformExtension).apply {
macosX64() macosX64()
macosArm64() macosArm64()