Revert "[K/N][build] Refactored K/N tool runner"

This reverts commit fa587a61fd.
This commit is contained in:
Igor Chevdar
2021-11-26 14:04:06 +05:00
parent 07adab561c
commit fed76a87af
5 changed files with 138 additions and 93 deletions
@@ -16,125 +16,172 @@
package org.jetbrains.kotlin.gradle.plugin.konan
import org.gradle.api.Named
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.api.Action
import org.gradle.api.GradleException
import org.gradle.api.plugins.JavaPluginExtension
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider
import org.gradle.jvm.toolchain.JavaLanguageVersion
import org.gradle.jvm.toolchain.JavaLauncher
import org.gradle.jvm.toolchain.JavaToolchainService
import org.gradle.jvm.toolchain.JavaToolchainSpec
import org.gradle.process.ExecSpec
import org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin.ProjectProperty.KONAN_HOME
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.util.DependencyProcessor
import java.nio.file.Files
import org.jetbrains.kotlin.*
import org.jetbrains.kotlin.konan.properties.resolvablePropertyString
import org.jetbrains.kotlin.konan.util.DependencyDirectories
import java.io.File
import java.util.Properties
import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner
import java.io.ByteArrayOutputStream
internal interface KonanToolRunner : Named {
val mainClass: String
val classpath: FileCollection
val jvmArgs: List<String>
val environment: Map<String, Any>
internal interface KonanToolRunner {
fun run(args: List<String>)
fun run(vararg args: String) = run(args.toList())
}
internal fun KonanToolRunner.run(vararg args: String) = run(args.toList())
internal abstract class KonanCliRunner(
protected val toolName: String,
project: Project,
val additionalJvmArgs: List<String> = emptyList(),
val konanHome: String = project.konanHome
) : KotlinToolRunner(project), KonanToolRunner {
final override val displayName get() = toolName
val toolName: String,
val fullName: String,
val project: Project,
private val additionalJvmArgs: List<String>,
private val konanHome: String
) : KonanToolRunner {
override val mainClass = "org.jetbrains.kotlin.cli.utilities.MainKt"
final override val mainClass get() = "org.jetbrains.kotlin.cli.utilities.MainKt"
final override val daemonEntryPoint get() = "daemonMain"
override fun getName() = toolName
// We need to unset some environment variables which are set by XCode and may potentially affect the tool executed.
final override val execEnvironmentBlacklist: Set<String> by lazy {
HashSet<String>().also { collector ->
KonanPlugin::class.java.getResourceAsStream("/env_blacklist")?.let { stream ->
stream.reader().use { r -> r.forEachLine { collector.add(it) } }
}
}
protected val blacklistEnvironment: List<String> by lazy {
KonanPlugin::class.java.getResourceAsStream("/env_blacklist")?.let { stream ->
stream.reader().use { it.readLines() }
} ?: emptyList<String>()
}
final override val execSystemProperties by lazy { mapOf("konan.home" to konanHome) }
protected val blacklistProperties: Set<String> =
setOf(
"java.endorsed.dirs", // Fix for KT-25887
"user.dir" // Don't propagate the working dir of the current Gradle process
)
final override val classpath by lazy { project.fileTree("$konanHome/konan/lib/").apply { include("*.jar") }.files }
override val classpath: FileCollection =
project.fileTree("$konanHome/konan/lib/")
.apply { include("*.jar") }
final override fun checkClasspath() =
check(classpath.isNotEmpty()) {
"""
Classpath of the tool is empty: $toolName
Probably the '${KONAN_HOME.propertyName}' project property contains an incorrect path.
Please change it to the compiler root directory and rerun the build.
""".trimIndent()
override val jvmArgs = HostManager.defaultJvmArgs.toMutableList().apply {
if (additionalJvmArgs.none { it.startsWith("-Xmx") } &&
project.jvmArgs.none { it.startsWith("-Xmx") }) {
add("-Xmx3G")
}
addAll(additionalJvmArgs)
addAll(project.jvmArgs)
}
override val environment = mutableMapOf("LIBCLANG_DISABLE_CRASH_RECOVERY" to "1")
private fun String.escapeQuotes() = replace("\"", "\\\"")
private fun Sequence<Pair<String, String>>.escapeQuotesForWindows() =
if (HostManager.hostIsMingw) {
map { (key, value) -> key.escapeQuotes() to value.escapeQuotes() }
} else {
this
}
data class IsolatedClassLoaderCacheKey(val classpath: Set<java.io.File>)
open protected fun transformArgs(args: List<String>): List<String> = args
// TODO: can't we use this for other implementations too?
final override val isolatedClassLoaderCacheKey get() = IsolatedClassLoaderCacheKey(classpath)
override fun run(args: List<String>) {
project.logger.info("Run tool: $toolName with args: ${args.joinToString(separator = " ")}")
if (classpath.isEmpty) {
throw IllegalStateException("Classpath of the tool is empty: $toolName\n" +
"Probably the '${KONAN_HOME.propertyName}' project property contains an incorrect path.\n" +
"Please change it to the compiler root directory and rerun the build.")
}
override fun transformArgs(args: List<String>) = listOf(toolName) + args
@Suppress("UNCHECKED_CAST")
val launcher = project.getProperty(KonanPlugin.ProjectProperty.KONAN_JVM_LAUNCHER) as? Provider<JavaLauncher>
?: throw IllegalStateException("Missing property: ${KonanPlugin.ProjectProperty.KONAN_JVM_LAUNCHER}")
final override fun getCustomJvmArgs() = additionalJvmArgs
val out = ByteArrayOutputStream()
val err = ByteArrayOutputStream()
val execResult = project.exec(object : Action<ExecSpec> {
override fun execute(exec: ExecSpec) {
exec.executable = launcher.get().executablePath.toString()
val properties = System.getProperties().asSequence()
.map { (k, v) -> k.toString() to v.toString() }
.filter { (k, _) -> k !in this@KonanCliRunner.blacklistProperties }
.filter { (k, _) -> !k.startsWith("sun") && !k.startsWith("java") }
.escapeQuotesForWindows()
.toMap()
.toMutableMap()
properties.put("konan.home", project.kotlinNativeDist.absolutePath)
exec.args(mutableListOf<String>().apply {
addAll(jvmArgs)
addAll(properties.entries.map { "-D${it.key}=${it.value}" })
add("-cp")
add(classpath.joinToString(separator = System.getProperty("path.separator")))
add(mainClass)
addAll(listOf(toolName) + transformArgs(args))
})
blacklistEnvironment.forEach { environment.remove(it) }
exec.environment(environment)
exec.errorOutput = err
exec.standardOutput = out
exec.isIgnoreExitValue = true
}
})
check(execResult.exitValue == 0) {
"""
stdout:$out
stderr:$err
""".trimIndent()
}
}
}
/** Kotlin/Native compiler runner */
internal class KonanCliCompilerRunner(
internal class KonanInteropRunner(
project: Project,
additionalJvmArgs: List<String> = emptyList(),
konanHome: String = project.konanHome
) : KonanCliRunner("cinterop", "Kotlin/Native cinterop tool", project, additionalJvmArgs, konanHome) {
init {
if (HostManager.host == KonanTarget.MINGW_X64) {
//TODO: Oh-ho-ho fix it in more convinient way.
environment.put("PATH", DependencyProcessor.defaultDependenciesRoot.absolutePath +
"\\llvm-11.1.0-windows-x64" +
"\\bin;${environment.get("PATH")}")
}
}
}
internal class KonanCompilerRunner(
project: Project,
additionalJvmArgs: List<String> = emptyList(),
val useArgFile: Boolean = true,
konanHome: String = project.konanHome
) : KonanCliRunner("konanc", project, additionalJvmArgs, konanHome) {
override val mustRunViaExec get() = false
) : KonanCliRunner("konanc", "Kotlin/Native compiler", project, additionalJvmArgs, konanHome) {
override fun transformArgs(args: List<String>): List<String> {
if (!useArgFile) return super.transformArgs(args)
val argFile = Files.createTempFile(/* prefix = */ "konancArgs", /* suffix = */ ".lst").toFile().apply { deleteOnExit() }
argFile.printWriter().use { w ->
for (arg in args) {
val escapedArg = arg
.replace("\\", "\\\\")
.replace("\"", "\\\"")
w.println("\"$escapedArg\"")
}
if (!useArgFile) {
return args
}
return listOf(toolName, "@${argFile.absolutePath}")
}
}
/** Kotlin/Native C-interop tool runner */
internal class KonanCliInteropRunner(
project: Project,
additionalJvmArgs: List<String> = emptyList(),
konanHome: String = project.konanHome
) : KonanCliRunner("cinterop", project, additionalJvmArgs, konanHome) {
override val mustRunViaExec get() = false
override val execEnvironment by lazy {
val result = mutableMapOf<String, String>()
result.putAll(super.execEnvironment)
result["LIBCLANG_DISABLE_CRASH_RECOVERY"] = "1"
llvmExecutablesPath?.let {
result["PATH"] = "$it;${System.getenv("PATH")}"
val argFile = Files.createTempFile("konancArgs", ".lst").toAbsolutePath().apply {
toFile().deleteOnExit()
}
result
}
Files.write(argFile, args)
private val llvmExecutablesPath: String? by lazy {
if (HostManager.host == KonanTarget.MINGW_X64) {
// TODO: Read it from Platform properties when it is accessible.
val konanProperties = Properties().apply {
project.file("$konanHome/konan/konan.properties").inputStream().use(::load)
}
konanProperties.resolvablePropertyString("llvmHome.mingw_x64")?.let { toolchainDir ->
DependencyDirectories.defaultDependenciesRoot
.resolve("$toolchainDir/bin")
.absolutePath
}
} else
null
return listOf("@${argFile}")
}
}
@@ -142,6 +189,4 @@ internal class KonanKlibRunner(
project: Project,
additionalJvmArgs: List<String> = emptyList(),
konanHome: String = project.konanHome
) : KonanCliRunner("klib", project, additionalJvmArgs, konanHome) {
override val mustRunViaExec get() = false
}
) : KonanCliRunner("klib", "Klib management tool", project, additionalJvmArgs, konanHome)
@@ -4,7 +4,7 @@ import org.gradle.api.DefaultTask
import org.gradle.api.file.Directory
import org.gradle.api.provider.Property
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.plugin.konan.KonanCliCompilerRunner
import org.jetbrains.kotlin.gradle.plugin.konan.KonanCompilerRunner
import org.jetbrains.kotlin.gradle.plugin.konan.konanHome
import org.jetbrains.kotlin.konan.library.defaultResolver
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -79,6 +79,6 @@ open class KonanCacheTask: DefaultTask() {
"-Xadd-cache=${originalKlib?.absolutePath}",
"-Xcache-directory=${cacheDirectory.absolutePath}"
) + additionalCacheFlags + cachedLibraries.map { "-Xcached-library=${it.key},${it.value}" }
KonanCliCompilerRunner(project, konanHome = konanHome).run(args)
KonanCompilerRunner(project, konanHome = konanHome).run(args)
}
}
@@ -36,7 +36,7 @@ import java.io.File
abstract class KonanCompileTask: KonanBuildingTask(), KonanCompileSpec {
@get:Internal
override val toolRunner = KonanCliCompilerRunner(project, project.konanExtension.jvmArgs)
override val toolRunner = KonanCompilerRunner(project, project.konanExtension.jvmArgs)
abstract val produce: CompilerOutputKind
@Internal get
@@ -70,7 +70,7 @@ open class KonanCompilerDownloadTask : DefaultTask() {
// Download dependencies if a user said so.
if (downloadDependencies) {
val runner = KonanCliCompilerRunner(project, project.konanExtension.jvmArgs)
val runner = KonanCompilerRunner(project, project.konanExtension.jvmArgs)
project.konanTargets.forEach {
runner.run("-Xcheck_dependencies", "-target", it.visibleName)
}
@@ -37,7 +37,7 @@ import javax.inject.Inject
open class KonanInteropTask @Inject constructor(@Internal val workerExecutor: WorkerExecutor) : KonanBuildingTask(), KonanInteropSpec {
@get:Internal
override val toolRunner: KonanToolRunner = KonanCliInteropRunner(project, project.konanExtension.jvmArgs)
override val toolRunner: KonanToolRunner = KonanInteropRunner(project, project.konanExtension.jvmArgs)
override fun init(config: KonanBuildingConfig<*>, destinationDir: File, artifactName: String, target: KonanTarget) {
super.init(config, destinationDir, artifactName, target)