Download native compiler in configuration stage

This commit is contained in:
Ilya Matveev
2018-09-12 13:48:58 +03:00
committed by Ilya Matveev
parent 5a64067601
commit 80bec0898f
7 changed files with 149 additions and 128 deletions
@@ -17,6 +17,7 @@ import org.junit.Test
import java.util.jar.JarFile
import java.util.zip.ZipFile
import kotlin.test.assertEquals
import kotlin.test.assertFalse
import kotlin.test.assertTrue
class NewMultiplatformIT : BaseGradleIT() {
@@ -607,4 +608,21 @@ class NewMultiplatformIT : BaseGradleIT() {
assertTrue(output.contains("Dependent: Published print"), "No test output found")
}
}
@Test
fun testNativeCompilerDownloading() {
// The plugin shouldn't download the K/N compiler if there is no corresponding targets in the project.
with(Project("new-mpp-lib-with-tests", gradleVersion)) {
build("tasks") {
assertSuccessful()
assertFalse(output.contains("Kotlin/Native distribution: "))
}
}
with(Project("new-mpp-native-libraries", gradleVersion)) {
build("tasks") {
assertSuccessful()
assertTrue(output.contains("Kotlin/Native distribution: "))
}
}
}
}
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.compilerRunner
import org.gradle.api.Named
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.DependencyDirectories
@@ -26,10 +27,9 @@ import org.jetbrains.kotlin.konan.util.DependencyDirectories
/** Copied from Kotlin/Native repository. */
internal enum class KotlinNativeProjectProperty(val propertyName: String) {
KONAN_HOME ("org.jetbrains.kotlin.native.home"),
KONAN_HOME_OVERRIDE ("org.jetbrains.kotlin.native.home"),
KONAN_JVM_ARGS ("org.jetbrains.kotlin.native.jvmArgs"),
KONAN_USE_ENVIRONMENT_VARIABLES("org.jetbrains.kotlin.native.useEnvironmentVariables"),
DOWNLOAD_COMPILER ("org.jetbrains.kotlin.native.download.compiler"),
KONAN_USE_ENVIRONMENT_VARIABLES("org.jetbrains.kotlin.native.useEnvironmentVariables")
}
internal fun Project.hasProperty(property: KotlinNativeProjectProperty) = hasProperty(property.propertyName)
@@ -44,12 +44,10 @@ internal fun Project.getProperty(property: KotlinNativeProjectProperty) = findPr
internal val Project.jvmArgs
get() = (findProperty(KotlinNativeProjectProperty.KONAN_JVM_ARGS) as String?)?.split("\\s+".toRegex()).orEmpty()
// konanHome extension is set by downloadKonanCompiler task.
internal val Project.konanHome: String
get() {
assert(hasProperty(KotlinNativeProjectProperty.KONAN_HOME))
return project.file(getProperty(KotlinNativeProjectProperty.KONAN_HOME)).canonicalPath
}
get() = findProperty(KotlinNativeProjectProperty.KONAN_HOME_OVERRIDE)?.let {
file(it).absolutePath
} ?: NativeCompilerDownloader(project).compilerDirectory.absolutePath
internal interface KonanToolRunner: Named {
val mainClass: String
@@ -36,7 +36,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile
import org.jetbrains.kotlin.gradle.tasks.CInteropProcess
import org.jetbrains.kotlin.gradle.tasks.KonanCompilerDownloadTask
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.utils.isGradleVersionAtLeast
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
@@ -412,7 +411,6 @@ open class KotlinNativeTargetConfigurator(
onlyIf { testExecutableProperty.get().exists() }
inputs.file(testExecutableProperty)
dependsOn(testExecutableLinkTask)
dependsOnCompilerDownloading()
}
tasks.maybeCreate(LifecycleBasePlugin.CHECK_TASK_NAME).apply {
dependsOn(testTask)
@@ -507,7 +505,6 @@ open class KotlinNativeTargetConfigurator(
addCompilerPlugins()
dependsOn(compilation.compileKotlinTaskName)
dependsOnCompilerDownloading()
linkAll.dependsOn(this)
}
@@ -577,7 +574,6 @@ open class KotlinNativeTargetConfigurator(
registerOutputFiles(klibOutputDirectory(compilation))
addCompilerPlugins()
dependsOnCompilerDownloading()
compilation.output.tryAddClassesDir {
project.files(this.outputFile).builtBy(this)
}
@@ -609,7 +605,6 @@ open class KotlinNativeTargetConfigurator(
"of target '${konanTarget.name}'."
enabled = compilation.target.konanTarget.enabledOnCurrentHost
dependsOnCompilerDownloading()
val interopOutput = project.files(outputFileProvider).builtBy(this)
with(compilation) {
project.dependencies.add(compileDependencyConfigurationName, interopOutput)
@@ -655,9 +650,6 @@ open class KotlinNativeTargetConfigurator(
configureCInterops(target)
}
private fun Task.dependsOnCompilerDownloading() =
dependsOn(KonanCompilerDownloadTask.KONAN_DOWNLOAD_TASK_NAME)
object NativeArtifactFormat {
const val KLIB = "org.jetbrains.kotlin.klib"
}
@@ -290,7 +290,7 @@ class KotlinNativeCompilation(
internal val binaryTasks = mutableMapOf<Pair<NativeOutputKind, NativeBuildType>, KotlinNativeCompile>()
// Native-specific DSL.
val extraOpts = mutableListOf<String>()
var extraOpts = mutableListOf<String>()
fun extraOpts(vararg values: Any) = extraOpts(values.toList())
fun extraOpts(values: List<Any>) {
@@ -20,9 +20,8 @@ import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToKotlinTask
import org.jetbrains.kotlin.gradle.tasks.AndroidTasksProvider
import org.jetbrains.kotlin.gradle.tasks.KonanCompilerDownloadTask
import org.jetbrains.kotlin.gradle.tasks.KonanCompilerDownloadTask.Companion.KONAN_DOWNLOAD_TASK_NAME
import org.jetbrains.kotlin.gradle.tasks.KotlinTasksProvider
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -245,26 +244,27 @@ class KotlinNativeTargetPreset(
override fun getName(): String = name
private fun createCompilerDownloadingTask() = with(project) {
if (!hasProperty(KotlinNativeProjectProperty.KONAN_HOME)) {
setProperty(KotlinNativeProjectProperty.KONAN_HOME, KonanCompilerDownloadTask.compilerDirectory)
setProperty(KotlinNativeProjectProperty.DOWNLOAD_COMPILER, true)
private fun setupNativeCompiler() = with(project) {
if (!hasProperty(KotlinNativeProjectProperty.KONAN_HOME_OVERRIDE)) {
NativeCompilerDownloader(this).downloadIfNeeded()
logger.info("Kotlin/Native distribution: $konanHome")
} else {
logger.info("User-provided Kotlin/Native distribution: $konanHome")
}
tasks.maybeCreate(KONAN_DOWNLOAD_TASK_NAME, KonanCompilerDownloadTask::class.java)
}
private fun stdlib(target: KonanTarget): FileCollection = with(project) {
files("${konanHome}/klib/common/stdlib").builtBy(createCompilerDownloadingTask())
files("${konanHome}/klib/common/stdlib")
}
private fun platformLibs(target: KonanTarget): FileCollection = with(project) {
files(provider {
file("${project.konanHome}/klib/platform/${target.name}").listFiles { file -> file.isDirectory } ?: emptyArray()
}).builtBy(createCompilerDownloadingTask())
file("${konanHome}/klib/platform/${target.name}").listFiles { file -> file.isDirectory } ?: emptyArray()
})
}
override fun createTarget(name: String): KotlinNativeTarget {
createCompilerDownloadingTask()
setupNativeCompiler()
val result = KotlinNativeTarget(project, konanTarget).apply {
targetName = name
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.DefaultCInteropSettings
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.defaultSourceSetName
import org.jetbrains.kotlin.gradle.plugin.mpp.isMainCompilation
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.KonanVersionImpl
import org.jetbrains.kotlin.konan.MetaVersion
@@ -77,8 +78,6 @@ private fun File.providedByCompiler(project: Project): Boolean =
open class KotlinNativeCompile : AbstractCompile() {
init {
dependsOn(KonanCompilerDownloadTask.KONAN_DOWNLOAD_TASK_NAME)
@Suppress("LeakingThis")
setDestinationDir(project.provider {
val output = outputFile.get()
@@ -155,7 +154,7 @@ open class KotlinNativeCompile : AbstractCompile() {
// endregion.
val kotlinNativeVersion: String
@Input get() = KonanCompilerDownloadTask.compilerVersion.toString()
@Input get() = NativeCompilerDownloader(project).compilerVersion.toString()
// We manually register this property as output file or directory depending on output kind.
@Internal
@@ -333,100 +332,3 @@ open class CInteropProcess: DefaultTask() {
KonanInteropRunner(project).run(args)
}
}
open class KonanCompilerDownloadTask : DefaultTask() {
internal companion object {
val simpleOsName: String = HostManager.simpleOsName()
val compilerDirectory: File
get() = DependencyDirectories.localKonanDir.resolve("kotlin-native-$simpleOsName-$compilerVersion")
// TODO: Support project property for Kotlin/Native compiler version
val compilerVersion: KonanVersion = KonanVersionImpl(MetaVersion.RELEASE, 0, 9, 0)
internal const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
const val KONAN_DOWNLOAD_TASK_NAME = "checkNativeCompiler"
}
private val useZip = HostManager.hostIsMingw
private val archiveExtension
get() = if (useZip) {
"zip"
} else {
"tar.gz"
}
private fun archiveFileTree(archive: File): FileTree =
if (useZip) {
project.zipTree(archive)
} else {
project.tarTree(archive)
}
private fun setupRepo(url: String): ArtifactRepository {
return project.repositories.ivy { repo ->
repo.setUrl(url)
repo.layout("pattern") {
val layout = it as IvyPatternRepositoryLayout
layout.artifact("[artifact]-[revision].[ext]")
}
repo.metadataSources {
it.artifact()
}
}
}
private fun removeRepo(repo: ArtifactRepository) {
project.repositories.remove(repo)
}
private fun downloadAndExtract() {
val versionString = compilerVersion.toString()
val url = buildString {
append("$BASE_DOWNLOAD_URL/")
append(if (compilerVersion.meta == MetaVersion.DEV) "dev/" else "releases/")
append("$versionString/")
append(simpleOsName)
}
val repo = setupRepo(url)
val compilerDependency = project.dependencies.create(
mapOf(
"name" to "kotlin-native-$simpleOsName",
"version" to versionString,
"ext" to archiveExtension
)
)
val configuration = project.configurations.detachedConfiguration(compilerDependency)
val archive = configuration.files.single()
logger.info("Use Kotlin/Native compiler archive: ${archive.absolutePath}")
logger.lifecycle("Unpacking Kotlin/Native compiler (version $versionString)...")
project.copy {
it.from(archiveFileTree(archive))
it.into(DependencyDirectories.localKonanDir)
}
removeRepo(repo)
}
@TaskAction
fun checkCompiler() {
if (!project.hasProperty(KotlinNativeProjectProperty.DOWNLOAD_COMPILER)) {
val konanHome = project.getProperty(KotlinNativeProjectProperty.KONAN_HOME)
logger.info("Use a user-defined compiler path: $konanHome")
} else {
// TODO: Move Kotlin/Native Distribution class in the Big Kotlin repo and use it here.
if (KonanCompilerRunner(project).classpath.isEmpty) {
downloadAndExtract()
}
logger.info("Use Kotlin/Native distribution: $compilerDirectory")
}
}
}
@@ -0,0 +1,111 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. 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.utils
import org.gradle.api.Project
import org.gradle.api.artifacts.repositories.ArtifactRepository
import org.gradle.api.artifacts.repositories.IvyPatternRepositoryLayout
import org.gradle.api.file.FileTree
import org.gradle.api.logging.Logger
import org.jetbrains.kotlin.compilerRunner.KonanCompilerRunner
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.KonanVersionImpl
import org.jetbrains.kotlin.konan.MetaVersion
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.util.DependencyDirectories
import java.io.File
class NativeCompilerDownloader(val project: Project) {
internal companion object {
const val BASE_DOWNLOAD_URL = "https://download.jetbrains.com/kotlin/native/builds"
}
private val logger: Logger
get() = project.logger
private val simpleOsName: String
get() = HostManager.simpleOsName()
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)
} else {
project.tarTree(archive)
}
private fun setupRepo(url: String): ArtifactRepository {
return project.repositories.ivy { repo ->
repo.setUrl(url)
repo.layout("pattern") {
val layout = it as IvyPatternRepositoryLayout
layout.artifact("[artifact]-[revision].[ext]")
}
repo.metadataSources {
it.artifact()
}
}
}
private fun removeRepo(repo: ArtifactRepository) {
project.repositories.remove(repo)
}
private fun downloadAndExtract() {
val versionString = compilerVersion.toString()
val url = buildString {
append("$BASE_DOWNLOAD_URL/")
append(if (compilerVersion.meta == MetaVersion.DEV) "dev/" else "releases/")
append("$versionString/")
append(simpleOsName)
}
val repo = setupRepo(url)
val compilerDependency = project.dependencies.create(
mapOf(
"name" to "kotlin-native-$simpleOsName",
"version" to versionString,
"ext" to archiveExtension
)
)
val configuration = project.configurations.detachedConfiguration(compilerDependency)
val archive = configuration.files.single()
logger.info("Use Kotlin/Native compiler archive: ${archive.absolutePath}")
logger.lifecycle("Unpacking Kotlin/Native compiler (version $versionString)...")
project.copy {
it.from(archiveFileTree(archive))
it.into(DependencyDirectories.localKonanDir)
}
removeRepo(repo)
}
val compilerDirectory: File
get() = DependencyDirectories.localKonanDir.resolve("kotlin-native-$simpleOsName-$compilerVersion")
// TODO: Support project property for Kotlin/Native compiler version
val compilerVersion: KonanVersion = KonanVersionImpl(MetaVersion.RELEASE, 0, 9, 0)
fun downloadIfNeeded() {
if (KonanCompilerRunner(project).classpath.isEmpty) {
downloadAndExtract()
}
}
}