[Commonizer] Integrate commonizer to the Gradle plugin, p.2

Call commonizer CLI via Gradle tool runner.
This commit is contained in:
Dmitriy Dolovov
2020-02-01 18:14:17 +07:00
parent d7e82bf899
commit 7cf4395ccd
9 changed files with 62 additions and 45 deletions
@@ -6,18 +6,29 @@
package org.jetbrains.kotlin.compilerRunner
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.gradle.plugin.KLIB_COMMONIZER_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import java.io.File
// TODO: implement this runner
internal class KotlinNativeKlibCommonizerToolRunner(project: Project) : KotlinToolRunner(project) {
override val displayName get() = "Kotlin/Native KLIB commonizer"
override val mainClass: String get() = TODO("not implemented")
override val classpath: FileCollection get() = TODO("not implemented")
override val mainClass: String get() = "org.jetbrains.kotlin.descriptors.commonizer.cli.CommonizerCLI"
override fun getIsolatedClassLoader(): ClassLoader {
TODO("not implemented")
override val classpath by lazy {
try {
project.configurations.getByName(KLIB_COMMONIZER_CLASSPATH_CONFIGURATION_NAME).resolve() as Set<File>
} catch (e: Exception) {
project.logger.error(
"Could not resolve KLIB commonizer classpath. Check if Kotlin Gradle plugin repository is configured in $project."
)
throw e
}
}
override val mustRunViaExec get() = false
override val isolatedClassLoaderCacheKey get() = project.getKotlinPluginVersion()!!
override val defaultMaxHeapSize: String get() = "4G"
override val mustRunViaExec get() = true // because it's not enough the standard Gradle wrapper's heap size
}
@@ -6,9 +6,11 @@
package org.jetbrains.kotlin.compilerRunner
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.konan.target.HostManager
import java.io.File
import java.lang.reflect.InvocationTargetException
import java.net.URLClassLoader
import java.util.concurrent.ConcurrentHashMap
internal abstract class KotlinToolRunner(
val project: Project
@@ -25,9 +27,14 @@ internal abstract class KotlinToolRunner(
open val systemProperties: Map<String, String> = emptyMap()
open val systemPropertiesBlacklist: Set<String> = emptySet()
abstract val classpath: FileCollection
open fun checkClasspath(): Unit = check(!classpath.isEmpty) { "Classpath of the tool is empty: $displayName" }
abstract fun getIsolatedClassLoader(): ClassLoader
abstract val classpath: Set<File>
open fun checkClasspath(): Unit = check(classpath.isNotEmpty()) { "Classpath of the tool is empty: $displayName" }
abstract val isolatedClassLoaderCacheKey: Any
private fun getIsolatedClassLoader(): ClassLoader = isolatedClassLoadersMap.computeIfAbsent(isolatedClassLoaderCacheKey) {
val arrayOfURLs = classpath.map { File(it.absolutePath).toURI().toURL() }.toTypedArray()
URLClassLoader(arrayOfURLs, null)
}
open val defaultMaxHeapSize: String get() = "3G"
open val enableAssertions: Boolean get() = true
@@ -67,7 +74,7 @@ internal abstract class KotlinToolRunner(
private fun runViaExec(args: List<String>) {
project.javaexec { spec ->
spec.main = mainClass
spec.classpath = classpath
spec.classpath = project.files(classpath)
spec.jvmArgs(jvmArgs)
spec.systemProperties(
System.getProperties().asSequence()
@@ -87,9 +94,7 @@ internal abstract class KotlinToolRunner(
val oldProperties = setUpSystemProperties()
try {
val classLoader = getIsolatedClassLoader()
val mainClass = classLoader.loadClass(mainClass)
val mainClass = getIsolatedClassLoader().loadClass(mainClass)
val entryPoint = mainClass.methods.single { it.name == daemonEntryPoint }
entryPoint.invoke(null, transformArgs(args).toTypedArray())
@@ -129,5 +134,7 @@ internal abstract class KotlinToolRunner(
private fun Sequence<Pair<String, String>>.escapeQuotesForWindows() =
if (HostManager.hostIsMingw) map { (key, value) -> key.escapeQuotes() to value.escapeQuotes() } else this
private val isolatedClassLoadersMap = ConcurrentHashMap<Any, ClassLoader>()
}
}
@@ -6,7 +6,6 @@
package org.jetbrains.kotlin.compilerRunner
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.cli.common.messages.MessageRenderer
import org.jetbrains.kotlin.gradle.dsl.NativeCacheKind
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
@@ -15,10 +14,7 @@ import org.jetbrains.kotlin.konan.CompilerVersion
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.DependencyDirectories
import java.io.File
import java.net.URLClassLoader
import java.util.*
import java.util.concurrent.ConcurrentHashMap
private val Project.jvmArgs
get() = PropertiesProvider(this).nativeJvmArgs?.split("\\s+".toRegex()).orEmpty()
@@ -65,10 +61,12 @@ internal abstract class KotlinNativeToolRunner(
}
final override val systemPropertiesBlacklist = setOf("java.endorsed.dirs")
final override val classpath: FileCollection = project.fileTree("${project.konanHome}/konan/lib/").apply { include("*.jar") }
final override val classpath by lazy {
project.fileTree("${project.konanHome}/konan/lib/").apply { include("*.jar") }.toSet()
}
final override fun checkClasspath() =
check(!classpath.isEmpty) {
check(classpath.isNotEmpty()) {
"""
Classpath of the tool is empty: $toolName
Probably the '${PropertiesProvider.KOTLIN_NATIVE_HOME}' project property contains an incorrect path.
@@ -76,19 +74,11 @@ internal abstract class KotlinNativeToolRunner(
""".trimIndent()
}
final override fun getIsolatedClassLoader() =
isolatedClassLoadersMap.computeIfAbsent(project.konanHome) {
val arrayOfURLs = classpath.map { File(it.absolutePath).toURI().toURL() }.toTypedArray()
URLClassLoader(arrayOfURLs, null)
}
final override val isolatedClassLoaderCacheKey get() = project.konanHome
override fun transformArgs(args: List<String>) = listOf(toolName) + args
final override fun getCustomJvmArgs() = project.jvmArgs
companion object {
private val isolatedClassLoadersMap = ConcurrentHashMap<String, ClassLoader>()
}
}
/** Kotlin/Native C-interop tool runner */
@@ -48,6 +48,8 @@ import java.util.jar.Manifest
const val PLUGIN_CLASSPATH_CONFIGURATION_NAME = "kotlinCompilerPluginClasspath"
const val NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME = "kotlinNativeCompilerPluginClasspath"
internal const val COMPILER_CLASSPATH_CONFIGURATION_NAME = "kotlinCompilerClasspath"
internal const val KLIB_COMMONIZER_CLASSPATH_CONFIGURATION_NAME = "kotlinKlibCommonizerClasspath"
val KOTLIN_DSL_NAME = "kotlin"
val KOTLIN_JS_DSL_NAME = "kotlin2js"
val KOTLIN_OPTIONS_DSL_NAME = "kotlinOptions"
@@ -34,11 +34,10 @@ import org.jetbrains.kotlin.gradle.targets.js.KotlinJsPlugin
import org.jetbrains.kotlin.gradle.targets.js.npm.addNpmDependencyExtension
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_COMPILER_EMBEDDABLE
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_MODULE_GROUP
import org.jetbrains.kotlin.gradle.tasks.KOTLIN_KLIB_COMMONIZER_EMBEDDABLE
import org.jetbrains.kotlin.gradle.testing.internal.KotlinTestsRegistry
import org.jetbrains.kotlin.gradle.utils.checkGradleCompatibility
import org.jetbrains.kotlin.gradle.utils.loadPropertyFromResources
import org.jetbrains.kotlin.statistics.metrics.BooleanMetrics
import org.jetbrains.kotlin.statistics.metrics.NumericalMetrics
import org.jetbrains.kotlin.statistics.metrics.StringMetrics
import javax.inject.Inject
import kotlin.reflect.KClass
@@ -67,6 +66,9 @@ abstract class KotlinBasePluginWrapper(
project.configurations.maybeCreate(NATIVE_COMPILER_PLUGIN_CLASSPATH_CONFIGURATION_NAME).apply {
isTransitive = false
}
project.configurations.maybeCreate(KLIB_COMMONIZER_CLASSPATH_CONFIGURATION_NAME).defaultDependencies {
it.add(project.dependencies.create("$KOTLIN_MODULE_GROUP:$KOTLIN_KLIB_COMMONIZER_EMBEDDABLE:$kotlinPluginVersion"))
}
// TODO: consider only set if if daemon or parallel compilation are enabled, though this way it should be safe too
System.setProperty(org.jetbrains.kotlin.cli.common.KOTLIN_COMPILER_ENVIRONMENT_KEEPALIVE_PROPERTY, "true")
@@ -134,7 +134,7 @@ class NativeCompilerDownloader(
}
fun downloadIfNeeded() {
if (KotlinNativeCompilerRunner(project).classpath.isEmpty) {
if (KotlinNativeCompilerRunner(project).classpath.isEmpty()) {
downloadAndExtract()
}
}
@@ -5,6 +5,8 @@
package org.jetbrains.kotlin.gradle.targets.native.internal
import org.gradle.api.Project
import org.jetbrains.kotlin.compilerRunner.KotlinNativeKlibCommonizerToolRunner
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
@@ -16,12 +18,13 @@ import java.nio.file.StandardCopyOption
import java.util.*
internal fun runCommonizerInBulk(
project: Project,
distributionDir: File,
baseDestinationDir: File,
targetGroups: List<Set<KonanTarget>>,
kotlinVersion: String
): List<File> {
val commandLineParameters = mutableListOf<String>()
val commandLineArguments = mutableListOf<String>()
val postActions = mutableListOf<() -> Unit>()
val result = targetGroups.map { targets ->
@@ -54,13 +57,13 @@ internal fun runCommonizerInBulk(
directory = parentDir
)
commandLineParameters += "native-dist-commonize"
commandLineParameters += "-distribution-path"
commandLineParameters += distributionDir.toString()
commandLineParameters += "-output-path"
commandLineParameters += destinationTmpDir.toString()
commandLineParameters += "-targets"
commandLineParameters += orderedTargets.joinToString(separator = ",")
commandLineArguments += "native-dist-commonize"
commandLineArguments += "-distribution-path"
commandLineArguments += distributionDir.toString()
commandLineArguments += "-output-path"
commandLineArguments += destinationTmpDir.toString()
commandLineArguments += "-targets"
commandLineArguments += orderedTargets.joinToString(separator = ",")
postActions.add { renameDirectory(destinationTmpDir, destinationDir) }
}
@@ -69,17 +72,17 @@ internal fun runCommonizerInBulk(
}
}
callCommonizerCLI(commandLineParameters)
callCommonizerCLI(project, commandLineArguments)
postActions.forEach { it() }
return result
}
private fun callCommonizerCLI(commandLineParameters: List<String>) {
if (commandLineParameters.isEmpty()) return
private fun callCommonizerCLI(project: Project, commandLineArguments: List<String>) {
if (commandLineArguments.isEmpty()) return
// TODO: implement
KotlinNativeKlibCommonizerToolRunner(project).run(commandLineArguments)
}
private fun renameDirectory(source: File, destination: File) {
@@ -88,6 +88,7 @@ private class NativePlatformDependencyResolver(val project: Project, val kotlinV
val commonizedLibsDirs: Map<CommonizedCommon, File> =
runCommonizerInBulk(
project = project,
distributionDir = distributionDir,
baseDestinationDir = distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR).resolve(KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR),
targetGroups = targetGroups.map { it.second },
@@ -48,6 +48,7 @@ private val KOTLIN_SCRIPT_RUNTIME = "kotlin-script-runtime"
private val KOTLIN_SCRIPT_COMMON = "kotlin-scripting-common"
private val KOTLIN_SCRIPT_JVM = "kotlin-scripting-jvm"
private val KOTLIN_REFLECT = "kotlin-reflect"
internal const val KOTLIN_KLIB_COMMONIZER_EMBEDDABLE = "kotlin-klib-commonizer-embeddable"
internal fun findKotlinJvmCompilerClasspath(project: Project): List<File> =
findKotlinModuleJar(project, K2JVM_COMPILER_CLASS, KOTLIN_COMPILER_EMBEDDABLE).let {