[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.jetbrains.kotlin.gradle.report.BuildReportType
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.io.TempDir
import java.nio.file.Path
import kotlin.io.path.ExperimentalPathApi
import kotlin.io.path.readText
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
@DisplayName("Restore from build cache should not break incremental compilation")
@GradleTest
@@ -20,8 +20,13 @@ import org.gradle.api.logging.LogLevel
import org.gradle.testkit.runner.BuildResult
import org.gradle.util.GradleVersion
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.io.TempDir
import java.io.File
import java.nio.file.Path
import kotlin.io.path.*
@DisplayName("Build cache relocation")
@@ -204,9 +209,16 @@ class BuildCacheRelocationIT : KGPBaseTest() {
@DisplayName("with native project")
@GradleTest
fun testRelocationNative(gradleVersion: GradleVersion) {
val buildOptionsBeforeCaching = defaultBuildOptions.copy(
nativeOptions = super.defaultBuildOptions.nativeOptions.copy(
version = TestVersions.Kotlin.STABLE_RELEASE,
distributionDownloadFromMaven = true
)
)
val (firstProject, secondProject) = prepareTestProjects(
"native-build-cache",
gradleVersion
gradleVersion,
buildOptions = buildOptionsBeforeCaching
) {
val localRepoUri = it.projectPath.resolve("repo").toUri()
it.subProject("build-cache-app").buildGradleKts.append(
@@ -276,12 +288,12 @@ class BuildCacheRelocationIT : KGPBaseTest() {
buildJdk: File? = null,
additionalConfiguration: (TestProject) -> Unit = {}
): Pair<TestProject, TestProject> {
val firstProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk) {
val firstProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk, forceOutput = true) {
enableLocalBuildCache(localBuildCacheDir)
additionalConfiguration(this)
}
val secondProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk) {
val secondProject = project(projectName, gradleVersion, buildOptions, buildJdk = buildJdk, forceOutput = true) {
enableLocalBuildCache(localBuildCacheDir)
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")
@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() {
private val platformName: String = HostManager.platformName()
@@ -34,6 +43,8 @@ class NativeDownloadAndPlatformLibsIT : KGPBaseTest() {
override val defaultBuildOptions: BuildOptions
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,
// so we create it within each test project folder
konanDataDir = workingDir.resolve(".konan")
@@ -36,7 +36,7 @@ interface TestVersions {
}
object Kotlin {
const val STABLE_RELEASE = "1.9.20"
const val STABLE_RELEASE = "1.9.21"
// Copied from KOTLIN_VERSION.kt file
val CURRENT
@@ -62,17 +62,20 @@ fun getOutputForTask(taskPath: String, output: String, logLevel: LogLevel = LogL
LogLevel.DEBUG -> taskOutputRegexForDebugLog(taskPath)
else -> throw throw IllegalStateException("Unsupported log lever for task output was given: $logLevel")
})
.find(output)
?.let { it.groupValues[1] }
?: error(
"""
Could not find output for task $taskPath.
=================
Build output is:
$output
=================
""".trimIndent()
)
.findAll(output)
.map { it.groupValues[1] }
.joinToString(System.lineSeparator())
.ifEmpty {
error(
"""
Could not find output for task $taskPath.
=================
Build output is:
$output
=================
""".trimIndent()
)
}
class CommandLineArguments(
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
get() = PropertiesProvider(this).nativeJvmArgs?.split("\\s+".toRegex()).orEmpty()
internal val Project.konanHome: String
get() = PropertiesProvider(this).konanDataDir?.let { NativeCompilerDownloader(project).compilerDirectory.absolutePath }
?: PropertiesProvider(this).nativeHome?.let { file(it).absolutePath }
?: NativeCompilerDownloader(project).compilerDirectory.absolutePath
internal val Project.konanHome: File
get() = (PropertiesProvider(this).konanDataDir?.let { NativeCompilerDownloader(project).compilerDirectory }
?: PropertiesProvider(this).nativeHome?.let { file(it) }
?: NativeCompilerDownloader(project).compilerDirectory).absoluteFile
internal val Project.disableKonanDaemon: Boolean
get() = PropertiesProvider(this).nativeDisableCompilerDaemon == true
@@ -47,6 +47,9 @@ internal val Project.konanVersion: String
internal val Project.konanDataDir: String?
get() = PropertiesProvider(this).konanDataDir
internal val Project.kotlinNativeToolchainEnabled: Boolean
get() = PropertiesProvider(this).kotlinNativeToolchainEnabled && PropertiesProvider(this).nativeDownloadFromMaven
internal fun Project.getKonanCacheKind(target: KonanTarget): NativeCacheKind {
val commonCacheKind = PropertiesProvider(this).nativeCacheKind
val targetCacheKind = PropertiesProvider(this).nativeCacheKindForTarget(target)
@@ -71,9 +74,9 @@ internal fun Project.getKonanParallelThreads(): Int {
private val Project.kotlinNativeCompilerJar: String
get() = if (nativeUseEmbeddableCompilerJar)
"$konanHome/konan/lib/kotlin-native-compiler-embeddable.jar"
"${konanHome.absolutePath}/konan/lib/kotlin-native-compiler-embeddable.jar"
else
"$konanHome/konan/lib/kotlin-native.jar"
"${konanHome.absolutePath}/konan/lib/kotlin-native.jar"
internal abstract class KotlinNativeToolRunner(
protected val toolName: String,
@@ -271,7 +274,7 @@ internal class KotlinNativeLibraryGenerationRunner(
companion object {
@Suppress("DEPRECATION") // TODO(Dmitrii Krasnov): after KT-52567 it will be possible to use GradleExecutionContext#fromTaskContext here
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),
metricsReporter = GradleBuildMetricsReporter()
)
@@ -41,6 +41,7 @@ const val NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME = "kotlinNativeCom
const val COMPILER_CLASSPATH_CONFIGURATION_NAME = "kotlinCompilerClasspath"
internal const val BUILD_TOOLS_API_CLASSPATH_CONFIGURATION_NAME = "kotlinBuildToolsApiClasspath"
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"
internal abstract class AbstractKotlinPlugin(
@@ -23,6 +23,7 @@ import org.gradle.api.Project
import org.gradle.api.logging.Logger
import org.gradle.api.logging.Logging
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.compilerRunner.kotlinNativeToolchainEnabled
import org.jetbrains.kotlin.compilerRunner.maybeCreateCommonizerClasspathConfiguration
import org.jetbrains.kotlin.gradle.dsl.*
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.CInteropKlibLibraryElements
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.testing.internal.KotlinTestsRegistry
import org.jetbrains.kotlin.gradle.utils.*
@@ -68,6 +70,9 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
addKotlinCompilerConfiguration(project)
if (project.kotlinNativeToolchainEnabled) {
addKotlinNativeBundleConfiguration(project)
}
project.configurations.maybeCreateResolvable(PLUGIN_CLASSPATH_CONFIGURATION_NAME).apply {
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() {
val factories = VariantImplementationFactoriesConfigurator.get(project.gradle)
factories.putIfAbsent(
@@ -206,6 +224,11 @@ abstract class DefaultKotlinBasePlugin : KotlinBasePlugin {
CommonizerTargetAttribute.setupAttributesMatchingStrategy(this)
CInteropCommonizerArtifactTypeAttribute.setupTransform(project)
}
if (project.kotlinNativeToolchainEnabled) {
KotlinNativeBundleArtifactFormat.setupAttributesMatchingStrategy(this)
KotlinNativeBundleArtifactFormat.setupTransform(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_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_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_PUBLISH_JVM_ENVIRONMENT_ATTRIBUTE
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
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].
* 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_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_NATIVE_TOOLCHAIN_ENABLED = property("kotlin.native.toolchain.enabled")
val KOTLIN_APPLE_COPY_FRAMEWORK_TO_BUILT_PRODUCTS_DIR = property("kotlin.apple.copyFrameworkToBuiltProductsDir")
/**
@@ -69,7 +69,7 @@ abstract class KonanPropertiesBuildService : BuildService<KonanPropertiesBuildSe
companion object {
fun registerIfAbsent(project: Project): Provider<KonanPropertiesBuildService> =
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 ->
SingleActionPerProject.run(project, UsesKonanPropertiesBuildService::class.java.name) {
project.tasks.withType<UsesKonanPropertiesBuildService>().configureEach { task ->
@@ -10,6 +10,7 @@ package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.compilerRunner.kotlinNativeToolchainEnabled
import org.jetbrains.kotlin.gradle.DeprecatedTargetPresetApi
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.targets.android.internal.InternalKotlinTargetPreset
@@ -36,7 +37,7 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
private fun setupNativeHomePrivateProperty() = with(project) {
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>
@@ -44,7 +45,9 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
protected abstract fun instantiateTarget(name: String): T
override fun createTargetInternal(name: String): T {
project.setupNativeCompiler(konanTarget)
if (!project.kotlinNativeToolchainEnabled) {
project.setupNativeCompiler(konanTarget)
}
val result = instantiateTarget(name).apply {
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.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
import org.jetbrains.kotlin.konan.target.HostManager
@@ -34,7 +33,6 @@ import java.nio.file.Files
class NativeCompilerDownloader(
val project: Project,
private val compilerVersion: String = project.konanVersion,
) {
companion object {
@@ -46,27 +44,36 @@ class NativeCompilerDownloader(
internal const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
internal const val KOTLIN_GROUP_ID = "org.jetbrains.kotlin"
}
val compilerDirectory: File
get() = DependencyDirectories
.getLocalKonanDir(project.konanDataDir)
.resolve(dependencyNameWithOsAndVersion)
internal fun getCompilerDependencyNotation(project: Project): Map<String, String> {
return mapOf(
"group" to KOTLIN_GROUP_ID,
"name" to getDependencyName(project),
"version" to getCompilerVersion(project),
"classifier" to simpleOsName,
"ext" to archiveExtension
)
}
private val logger: Logger
get() = project.logger
internal fun getCompilerDirectory(project: Project): File {
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
get() = HostManager.platformName()
private val simpleOsName = HostManager.platformName()
private val dependencyName: String
get() {
val dependencySuffix = distributionType.suffix
private fun getCompilerVersion(project: Project): String {
return project.konanVersion
}
private fun getDependencyName(project: Project): String {
val dependencySuffix = NativeDistributionTypeProvider(project).getDistributionType().suffix
return if (dependencySuffix != null) {
"kotlin-native-$dependencySuffix"
} 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
get() = "$dependencyName-$simpleOsName-$compilerVersion"
get() = getDependencyNameWithOsAndVersion(project)
private val dependencyFileName: String
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 =
if (useZip) {
project.zipTree(archive)
@@ -114,11 +131,11 @@ class NativeCompilerDownloader(
}
private val repoUrl by lazy {
val maturity = KotlinToolingVersion(compilerVersion).maturity
val maturity = KotlinToolingVersion(getCompilerVersion(project)).maturity
buildString {
append("${kotlinProperties.nativeBaseDownloadUrl}/")
append(if (maturity == KotlinToolingVersion.Maturity.DEV) "dev/" else "releases/")
append("$compilerVersion/")
append("${getCompilerVersion(project)}/")
append(simpleOsName)
}
}
@@ -129,27 +146,19 @@ class NativeCompilerDownloader(
} else null
val compilerDependency = if (kotlinProperties.nativeDownloadFromMaven) {
project.dependencies.create(
mapOf(
"group" to KOTLIN_GROUP_ID,
"name" to dependencyName,
"version" to compilerVersion,
"classifier" to simpleOsName,
"ext" to archiveExtension
)
)
project.dependencies.create(getCompilerDependencyNotation(project))
} else {
project.dependencies.create(
mapOf(
"name" to "$dependencyName-$simpleOsName",
"version" to compilerVersion,
"name" to "${getDependencyName(project)}-$simpleOsName",
"version" to getCompilerVersion(project),
"ext" to archiveExtension
)
)
}
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) {
val dependencyUrl = "$repoUrl/$dependencyFileName"
@@ -162,6 +171,12 @@ class NativeCompilerDownloader(
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.lifecycle("Unpack Kotlin/Native compiler to $compilerDirectory")
@@ -186,8 +201,6 @@ class NativeCompilerDownloader(
tmpDir.deleteRecursively()
}
}
if (repo != null) removeRepo(repo)
}
fun downloadIfNeeded() {
@@ -199,11 +212,12 @@ class NativeCompilerDownloader(
private fun checkClassPath() {
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()
}
internal abstract class NativeCompilerDownloaderClassPathChecker : ValueSource<Boolean, NativeCompilerDownloaderClassPathChecker.Params> {
internal abstract class NativeCompilerDownloaderClassPathChecker :
ValueSource<Boolean, NativeCompilerDownloaderClassPathChecker.Params> {
interface Params : ValueSourceParameters {
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) {
val isKonanHomeOverridden = kotlinPropertiesProvider.nativeHome != null
if (!isKonanHomeOverridden) {
@@ -227,9 +254,9 @@ internal fun Project.setupNativeCompiler(konanTarget: KonanTarget) {
}
downloader.downloadIfNeeded()
logger.info("Kotlin/Native distribution: $konanHome")
logger.info("Kotlin/Native distribution: ${konanHome.absolutePath}")
} else {
logger.info("User-provided Kotlin/Native distribution: $konanHome")
logger.info("User-provided Kotlin/Native distribution: ${konanHome.absolutePath}")
}
val distributionType = NativeDistributionTypeProvider(project).getDistributionType()
@@ -29,7 +29,7 @@ import java.util.concurrent.ConcurrentHashMap
internal class PlatformLibrariesGenerator(val project: Project, val konanTarget: KonanTarget) {
private val distribution =
customerDistribution(project.konanHome, konanDataDir = project.konanDataDir)
customerDistribution(project.konanHome.absolutePath, konanDataDir = project.konanDataDir)
private val platformLibsDirectory =
File(distribution.platformLibs(konanTarget)).absoluteFile
@@ -77,7 +77,7 @@ internal class PlatformLibrariesGenerator(val project: Project, val konanTarget:
}
val cacheDirectory = CacheBuilder.getRootCacheDirectory(
File(project.konanHome), konanTarget, true, konanCacheKind
project.konanHome, konanTarget, true, konanCacheKind
)
return presentDefs.toPlatformLibNames().all {
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-directory",
CacheBuilder.getRootCacheDirectory(File(konanHome), konanTarget, true, konanCacheKind).absolutePath
CacheBuilder.getRootCacheDirectory(konanHome, konanTarget, true, konanCacheKind).absolutePath
)
args.addArg("-cache-arg", "-g")
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.targets.native.UsesKonanPropertiesBuildService
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.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -62,14 +63,6 @@ constructor(
val compilation: KotlinNativeCompilation
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
.newInstance<KotlinCommonCompilerToolOptionsDefault>()
@@ -206,17 +199,29 @@ constructor(
private val externalDependenciesArgs by lazy { ExternalDependenciesBuilder(project, compilation).buildCompilerArgs() }
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,
val icEnabled: Boolean, val threads: Int,
val gradleUserHomeDir: File, val gradleBuildDir: File)
private class CacheSettings(
val orchestration: NativeCacheOrchestration, val kind: NativeCacheKind,
val icEnabled: Boolean, val threads: Int,
val gradleUserHomeDir: File, val gradleBuildDir: File,
)
private val cacheSettings by lazy {
CacheSettings(project.getKonanCacheOrchestration(), project.getKonanCacheKind(konanTarget),
project.isKonanIncrementalCompilationEnabled(), project.getKonanParallelThreads(),
project.gradle.gradleUserHomeDir, project.layout.buildDirectory.get().asFile)
CacheSettings(
project.getKonanCacheOrchestration(), project.getKonanCacheKind(konanTarget),
project.isKonanIncrementalCompilationEnabled(), project.getKonanParallelThreads(),
project.gradle.gradleUserHomeDir, project.layout.buildDirectory.get().asFile
)
}
override fun createCompilerArguments(context: CreateCompilerArgumentsContext) = context.create<K2NativeCompilerArguments> {
@@ -343,6 +348,31 @@ constructor(
@get:Nested
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
fun compile() {
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.statistics.UsesBuildFusService
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.tasks.*
import org.jetbrains.kotlin.gradle.targets.native.toolchain.KotlinNativeProvider
import org.jetbrains.kotlin.gradle.utils.*
import org.jetbrains.kotlin.gradle.utils.GradleLoggerAdapter
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.
*/
@@ -336,11 +331,24 @@ internal constructor(
@get:Internal // these sources are normally a subset of `source` ones which are already tracked
val commonSources: ConfigurableFileCollection = project.files()
@get:Internal
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir }
@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 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
override val multiplatformStructure: K2MultiplatformStructure = objectFactory.newInstance()
@@ -410,7 +418,11 @@ internal constructor(
override val additionalCompilerOptions: 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.
@Suppress("DeprecatedCallableAddReplaceWith")
@@ -1077,13 +1089,30 @@ abstract class CInteropProcess @Inject internal constructor(params: Params) :
val outputFile: File
get() = outputFileProvider.get()
@get:Internal
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir }
@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 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.
@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.GradleBuildPerformanceMetric
import org.jetbrains.kotlin.build.report.metrics.GradleBuildTime
import org.jetbrains.kotlin.compilerRunner.*
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.gradle.dsl.*
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.UsesBuildMetricsService
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.utils.XcodeUtils
import org.jetbrains.kotlin.gradle.utils.getFile
import org.jetbrains.kotlin.gradle.utils.newInstance
import org.jetbrains.kotlin.gradle.utils.property
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -170,13 +170,30 @@ abstract class KotlinNativeLinkArtifactTask @Inject constructor(
val metrics: Property<BuildMetricsReporter<GradleBuildTime, GradleBuildPerformanceMetric>> = project.objects
.property(GradleBuildMetricsReporter())
@get:Internal
val konanDataDir: Provider<String?> = project.provider { project.konanDataDir }
@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 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 {
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 {
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 {
macosX64()
macosArm64()