Further refactored external utility execution.
This commit is contained in:
committed by
alexander-gorshenev
parent
4daaf9c99f
commit
e64c2f5990
+1
-1
@@ -22,5 +22,5 @@ import org.jetbrains.kotlin.konan.file.*
|
||||
|
||||
fun produceCAdapterBitcode(clang: TargetClang, cppFileName: String, bitcodeFileName: String) {
|
||||
val clangCommand = clang.clangCXX("-std=c++11", cppFileName, "-emit-llvm", "-c", "-o", bitcodeFileName)
|
||||
runTool(clangCommand)
|
||||
Command(clangCommand).execute()
|
||||
}
|
||||
|
||||
+1
-9
@@ -16,15 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
/**
|
||||
* This is a common ancestor of all Kotlin/Native exceptions.
|
||||
*/
|
||||
open class KonanException(message: String = "", cause: Throwable? = null) : Exception(message, cause)
|
||||
|
||||
/**
|
||||
* An error occured during external tool invocation. Such as non-zero exit code.
|
||||
*/
|
||||
class KonanExternalToolFailure(message: String = "", cause: Throwable? = null) : KonanException(message, cause)
|
||||
import org.jetbrains.kotlin.konan.KonanException
|
||||
|
||||
/**
|
||||
* Represents a compilation error caused by mistakes in an input file, e.g. undefined reference.
|
||||
|
||||
+57
-76
@@ -16,9 +16,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.konan
|
||||
|
||||
import org.jetbrains.kotlin.konan.exec.runTool
|
||||
import java.lang.ProcessBuilder
|
||||
import java.lang.ProcessBuilder.Redirect
|
||||
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
|
||||
import org.jetbrains.kotlin.konan.exec.Command
|
||||
import org.jetbrains.kotlin.konan.file.*
|
||||
import org.jetbrains.kotlin.konan.properties.*
|
||||
import org.jetbrains.kotlin.konan.target.*
|
||||
@@ -68,26 +69,6 @@ internal abstract class PlatformFlags(val properties: KonanProperties) {
|
||||
|
||||
}
|
||||
|
||||
internal open class Command(tool:String) {
|
||||
private val opts = mutableListOf(tool)
|
||||
val libs = mutableListOf<String>()
|
||||
operator fun String.unaryPlus():Command {
|
||||
opts += this
|
||||
return this@Command
|
||||
}
|
||||
|
||||
operator fun List<String>.unaryPlus():Command {
|
||||
opts.addAll(this)
|
||||
return this@Command
|
||||
}
|
||||
|
||||
open fun execute() = runTool(*opts.toTypedArray())
|
||||
|
||||
fun externalLibraries(deps: List<String>) {
|
||||
libs.addAll(deps)
|
||||
}
|
||||
}
|
||||
|
||||
internal open class AndroidPlatform(distribution: Distribution)
|
||||
: PlatformFlags(distribution.targetProperties) {
|
||||
|
||||
@@ -133,13 +114,7 @@ internal open class MacOSBasedPlatform(distribution: Distribution)
|
||||
= binaries.filter { it.isUnixStaticLib }
|
||||
|
||||
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
|
||||
return object : Command(linker){
|
||||
override fun execute() {
|
||||
super.execute()
|
||||
if (debug)
|
||||
runTool(*dsymutilCommand(executable).toTypedArray())
|
||||
}
|
||||
}.apply {
|
||||
return object : Command(linker) {} .apply {
|
||||
+ "-demangle"
|
||||
+ listOf("-object_path_lto", "temporary.o", "-lto_library", libLTO)
|
||||
+ listOf("-dynamic", "-arch", propertyTargetString("arch"))
|
||||
@@ -154,6 +129,42 @@ internal open class MacOSBasedPlatform(distribution: Distribution)
|
||||
}
|
||||
}
|
||||
|
||||
fun dsymUtilCommand(executable: ExecutableFile) = object : Command(dsymutilCommand(executable)) {
|
||||
override fun runProcess(): Int =
|
||||
executeCommandWithFilter(command)
|
||||
}
|
||||
|
||||
// TODO: consider introducing a better filtering directly in Command.
|
||||
private fun executeCommandWithFilter(command: List<String>): Int {
|
||||
val builder = ProcessBuilder(command)
|
||||
|
||||
// Inherit main process output streams.
|
||||
val isDsymUtil = (command[0] == dsymutil)
|
||||
|
||||
builder.redirectOutput(Redirect.INHERIT)
|
||||
builder.redirectInput(Redirect.INHERIT)
|
||||
if (!isDsymUtil)
|
||||
builder.redirectError(Redirect.INHERIT)
|
||||
|
||||
val process = builder.start()
|
||||
if (isDsymUtil) {
|
||||
/**
|
||||
* llvm-lto has option -alias that lets tool to know which symbol we use instead of _main,
|
||||
* llvm-dsym doesn't have such a option, so we ignore annoying warning manually.
|
||||
*/
|
||||
val errorStream = process.errorStream
|
||||
val outputStream = bufferedReader(errorStream)
|
||||
while (true) {
|
||||
val line = outputStream.readLine() ?: break
|
||||
if (!line.contains("warning: could not find object file symbol for symbol _main"))
|
||||
System.err.println(line)
|
||||
}
|
||||
outputStream.close()
|
||||
}
|
||||
val exitCode = process.waitFor()
|
||||
return exitCode
|
||||
}
|
||||
|
||||
open fun dsymutilCommand(executable: ExecutableFile): List<String> = listOf(dsymutil, executable)
|
||||
|
||||
open fun dsymutilDryRunVerboseCommand(executable: ExecutableFile): List<String> =
|
||||
@@ -253,7 +264,7 @@ internal open class WasmPlatform(distribution: Distribution)
|
||||
override val useCompilerDriverAsLinker: Boolean get() = false
|
||||
|
||||
override fun filterStaticLibraries(binaries: List<String>)
|
||||
= emptyList<String>()
|
||||
= binaries.filter{it.isJavaScript}
|
||||
|
||||
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
|
||||
return object: Command("") {
|
||||
@@ -261,7 +272,7 @@ internal open class WasmPlatform(distribution: Distribution)
|
||||
val src = File(objectFiles.single())
|
||||
val dst = File(executable)
|
||||
src.recursiveCopyTo(dst)
|
||||
javaScriptLink(libs.filter{it.isJavaScript}, executable)
|
||||
javaScriptLink(args, executable)
|
||||
}
|
||||
|
||||
private fun javaScriptLink(jsFiles: List<String>, executable: String): String {
|
||||
@@ -312,6 +323,12 @@ internal class LinkStage(val context: Context) {
|
||||
addAll(elements.filter { !it.isEmpty() })
|
||||
}
|
||||
|
||||
private fun runTool(command: List<String>) = runTool(*command.toTypedArray())
|
||||
private fun runTool(vararg command: String) =
|
||||
Command(*command)
|
||||
.logWith(context::log)
|
||||
.execute()
|
||||
|
||||
private fun llvmLto(files: List<BitcodeFile>): ObjectFile {
|
||||
val combined = temporary("combined", ".o")
|
||||
|
||||
@@ -325,7 +342,7 @@ internal class LinkStage(val context: Context) {
|
||||
}
|
||||
command.addNonEmpty(platform.llvmLtoDynamicFlags)
|
||||
command.addNonEmpty(files)
|
||||
runTool(*command.toTypedArray())
|
||||
runTool(command)
|
||||
|
||||
return combined
|
||||
}
|
||||
@@ -344,7 +361,7 @@ internal class LinkStage(val context: Context) {
|
||||
private fun hostLlvmTool(tool: String, args: List<String>) {
|
||||
val absoluteToolName = "${distribution.llvmBin}/$tool"
|
||||
val command = listOf(absoluteToolName) + args
|
||||
runTool(*command.toTypedArray())
|
||||
runTool(command)
|
||||
}
|
||||
|
||||
private fun bitcodeToWasm(bitcodeFiles: List<BitcodeFile>): String {
|
||||
@@ -422,58 +439,22 @@ internal class LinkStage(val context: Context) {
|
||||
+ platform.linkCommandSuffix()
|
||||
+ platform.linkStaticLibraries(includedBinaries)
|
||||
+ libraryProvidedLinkerFlags
|
||||
externalLibraries(includedBinaries)
|
||||
logger = context::log
|
||||
}.execute()
|
||||
|
||||
if (debug && platform is MacOSBasedPlatform) {
|
||||
platform.dsymUtilCommand(executable)
|
||||
.logWith(context::log)
|
||||
.execute()
|
||||
}
|
||||
} catch (e: KonanExternalToolFailure) {
|
||||
context.reportCompilationError("linker invocation reported errors")
|
||||
context.reportCompilationError("${e.toolName} invocation reported errors")
|
||||
return null
|
||||
}
|
||||
return executable
|
||||
}
|
||||
|
||||
private fun executeCommand(vararg command: String): Int {
|
||||
|
||||
context.log{""}
|
||||
context.log{command.asList<String>().joinToString(" ")}
|
||||
|
||||
val builder = ProcessBuilder(command.asList())
|
||||
|
||||
// Inherit main process output streams.
|
||||
val isDsymUtil = platform is MacOSBasedPlatform && command[0] == platform.dsymutil
|
||||
|
||||
builder.redirectOutput(Redirect.INHERIT)
|
||||
builder.redirectInput(Redirect.INHERIT)
|
||||
if (!isDsymUtil)
|
||||
builder.redirectError(Redirect.INHERIT)
|
||||
|
||||
|
||||
val process = builder.start()
|
||||
if (isDsymUtil) {
|
||||
/**
|
||||
* llvm-lto has option -alias that lets tool to know which symbol we use instead of _main,
|
||||
* llvm-dsym doesn't have such a option, so we ignore annoying warning manually.
|
||||
*/
|
||||
val errorStream = process.errorStream
|
||||
val outputStream = bufferedReader(errorStream)
|
||||
while (true) {
|
||||
val line = outputStream.readLine() ?: break
|
||||
if (!line.contains("warning: could not find object file symbol for symbol _main"))
|
||||
System.err.println(line)
|
||||
}
|
||||
outputStream.close()
|
||||
}
|
||||
val exitCode = process.waitFor()
|
||||
return exitCode
|
||||
}
|
||||
|
||||
private fun runTool(vararg command: String) {
|
||||
val code = executeCommand(*command)
|
||||
if (code != 0) throw KonanExternalToolFailure("The ${command[0]} command returned non-zero exit code: $code.")
|
||||
}
|
||||
|
||||
fun linkStage() {
|
||||
context.log{"# Compiler root: ${distribution.konanHome}"}
|
||||
|
||||
val bitcodeFiles = listOf(emitted) +
|
||||
libraries.map{it -> it.bitcodePaths}.flatten()
|
||||
|
||||
|
||||
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.konan
|
||||
|
||||
/**
|
||||
* This is a common ancestor of all Kotlin/Native exceptions.
|
||||
*/
|
||||
open class KonanException(message: String = "", cause: Throwable? = null) : Exception(message, cause)
|
||||
|
||||
/**
|
||||
* An error occured during external tool invocation. Such as non-zero exit code.
|
||||
*/
|
||||
class KonanExternalToolFailure(message: String, val toolName: String, cause: Throwable? = null) : KonanException(message, cause)
|
||||
|
||||
@@ -18,29 +18,51 @@ package org.jetbrains.kotlin.konan.exec
|
||||
|
||||
import java.lang.ProcessBuilder
|
||||
import java.lang.ProcessBuilder.Redirect
|
||||
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
|
||||
|
||||
fun executeCommand(command: List<String>) =
|
||||
executeCommand(*command.toTypedArray())
|
||||
|
||||
fun executeCommand(vararg command: String): Int {
|
||||
// TODO: need a verbose logger here.
|
||||
open class Command(initialCommand: List<String>) {
|
||||
|
||||
val builder = ProcessBuilder(command.asList())
|
||||
constructor(tool: String) : this(listOf(tool))
|
||||
constructor(vararg command: String) : this(command.toList<String>())
|
||||
protected val command = initialCommand.toMutableList()
|
||||
|
||||
builder.redirectOutput(Redirect.INHERIT)
|
||||
builder.redirectInput(Redirect.INHERIT)
|
||||
builder.redirectError(Redirect.INHERIT)
|
||||
val args: List<String>
|
||||
get() = command.drop(1)
|
||||
|
||||
val process = builder.start()
|
||||
val exitCode = process.waitFor()
|
||||
return exitCode
|
||||
operator fun String.unaryPlus(): Command {
|
||||
command += this
|
||||
return this@Command
|
||||
}
|
||||
|
||||
operator fun List<String>.unaryPlus(): Command {
|
||||
command.addAll(this)
|
||||
return this@Command
|
||||
}
|
||||
|
||||
var logger: ((() -> String)->Unit)? = null
|
||||
|
||||
fun logWith(newLogger: ((() -> String)->Unit)): Command {
|
||||
logger = newLogger
|
||||
return this
|
||||
}
|
||||
|
||||
open fun runProcess(): Int {
|
||||
val builder = ProcessBuilder(command)
|
||||
|
||||
builder.redirectOutput(Redirect.INHERIT)
|
||||
builder.redirectInput(Redirect.INHERIT)
|
||||
builder.redirectError(Redirect.INHERIT)
|
||||
|
||||
val process = builder.start()
|
||||
val exitCode = process.waitFor()
|
||||
return exitCode
|
||||
}
|
||||
|
||||
open fun execute() {
|
||||
if (logger != null) logger!! { command.toList<String>().joinToString(" ") }
|
||||
|
||||
val code = runProcess()
|
||||
if (code != 0) throw KonanExternalToolFailure("The ${command[0]} command returned non-zero exit code: $code.", command[0])
|
||||
}
|
||||
}
|
||||
|
||||
fun runTool(command: List<String>) =
|
||||
runTool(*command.toTypedArray())
|
||||
|
||||
fun runTool(vararg command: String) {
|
||||
val code = executeCommand(*command)
|
||||
if (code != 0) error("The ${command[0]} command returned non-zero exit code: $code.")
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user