[stage][link] commmand reprisentation

This commit is contained in:
Vasily Levchenko
2017-12-13 13:40:30 +03:00
committed by Vasily Levchenko
parent dd42c63bd2
commit 9d211e74c5
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.backend.konan package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.konan.exec.runTool
import java.lang.ProcessBuilder import java.lang.ProcessBuilder
import java.lang.ProcessBuilder.Redirect import java.lang.ProcessBuilder.Redirect
import org.jetbrains.kotlin.konan.file.* import org.jetbrains.kotlin.konan.file.*
@@ -50,7 +51,7 @@ internal abstract class PlatformFlags(val properties: KonanProperties) {
open val useCompilerDriverAsLinker: Boolean get() = false // TODO: refactor. open val useCompilerDriverAsLinker: Boolean get() = false // TODO: refactor.
abstract fun linkCommand(objectFiles: List<ObjectFile>, abstract fun linkCommand(objectFiles: List<ObjectFile>,
executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): List<String> executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command
open fun linkCommandSuffix(): List<String> = emptyList() open fun linkCommandSuffix(): List<String> = emptyList()
@@ -69,6 +70,25 @@ 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) internal open class AndroidPlatform(distribution: Distribution)
: PlatformFlags(distribution.targetProperties) { : PlatformFlags(distribution.targetProperties) {
@@ -81,19 +101,19 @@ internal open class AndroidPlatform(distribution: Distribution)
override fun filterStaticLibraries(binaries: List<String>) override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isUnixStaticLib } = binaries.filter { it.isUnixStaticLib }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): List<String> { override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
// liblog.so must be linked in, as we use its functionality in runtime. // liblog.so must be linked in, as we use its functionality in runtime.
return mutableListOf(clang).apply{ return Command(clang).apply {
add("-o") + "-o"
add(executable) + executable
add("-fPIC") + "-fPIC"
add("-shared") + "-shared"
add("-llog") + "-llog"
addAll(objectFiles) + objectFiles
if (optimize) addAll(linkerOptimizationFlags) if (optimize) + linkerOptimizationFlags
if (!debug) addAll(linkerNoDebugFlags) if (!debug) + linkerNoDebugFlags
if (dynamic) addAll(linkerDynamicFlags) if (dynamic) + linkerDynamicFlags
addAll(linkerKonanFlags) + linkerKonanFlags
} }
} }
} }
@@ -115,19 +135,24 @@ internal open class MacOSBasedPlatform(distribution: Distribution)
override fun filterStaticLibraries(binaries: List<String>) override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isUnixStaticLib } = binaries.filter { it.isUnixStaticLib }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): List<String> { override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
return mutableListOf(linker).apply { return object : Command(linker){
add("-demangle") override fun execute() {
addAll(listOf("-object_path_lto", "temporary.o", "-lto_library", libLTO)) super.execute()
addAll(listOf("-dynamic", "-arch", propertyTargetString("arch"))) runTool(*dsymutilCommand(executable).toTypedArray())
addAll(osVersionMin) }
addAll(listOf("-syslibroot", targetSysRoot, "-o", executable)) }.apply {
addAll(objectFiles) + "-demangle"
if (optimize) addAll(linkerOptimizationFlags) + listOf("-object_path_lto", "temporary.o", "-lto_library", libLTO)
if (!debug) addAll(linkerNoDebugFlags) + listOf("-dynamic", "-arch", propertyTargetString("arch"))
if (dynamic) addAll(linkerDynamicFlags) + osVersionMin
addAll(linkerKonanFlags) + listOf("-syslibroot", targetSysRoot, "-o", executable)
add("-lSystem") + objectFiles
if (optimize) + linkerOptimizationFlags
if (!debug) + linkerNoDebugFlags
if (dynamic) + linkerDynamicFlags
+ linkerKonanFlags
+ "-lSystem"
} }
} }
@@ -136,6 +161,7 @@ internal open class MacOSBasedPlatform(distribution: Distribution)
open fun dsymutilDryRunVerboseCommand(executable: ExecutableFile): List<String> = open fun dsymutilDryRunVerboseCommand(executable: ExecutableFile): List<String> =
listOf(dsymutil, "-dump-debug-map" ,executable) listOf(dsymutil, "-dump-debug-map" ,executable)
} }
internal open class LinuxBasedPlatform(val distribution: Distribution) internal open class LinuxBasedPlatform(val distribution: Distribution)
: PlatformFlags(distribution.targetProperties) { : PlatformFlags(distribution.targetProperties) {
@@ -149,47 +175,52 @@ internal open class LinuxBasedPlatform(val distribution: Distribution)
override fun filterStaticLibraries(binaries: List<String>) override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isUnixStaticLib } = binaries.filter { it.isUnixStaticLib }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): List<String> { override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
val isMips = (distribution.target == KonanTarget.LINUX_MIPS32 || val isMips = (distribution.target == KonanTarget.LINUX_MIPS32 ||
distribution.target == KonanTarget.LINUX_MIPSEL32) distribution.target == KonanTarget.LINUX_MIPSEL32)
// TODO: Can we extract more to the konan.properties? // TODO: Can we extract more to the konan.properties?
return listConstructor( return Command(linker).apply {
linker, + "--sysroot=${targetSysRoot}"
"--sysroot=${targetSysRoot}", + "-export-dynamic"
"-export-dynamic", "-z", "relro", + "-z"
"--build-id", "--eh-frame-hdr", // "-m", "elf_x86_64", + "relro"
"-dynamic-linker", propertyTargetString("dynamicLinker"), + "--build-id"
"-o", executable, + "--eh-frame-hdr"
If (!dynamic, // + "-m"
"${targetSysRoot}/usr/lib64/crt1.o"), // + "elf_x86_64",
"${targetSysRoot}/usr/lib64/crti.o", + "-dynamic-linker"
+ propertyTargetString("dynamicLinker")
+ "-o"
+ executable
if (!dynamic) + "$targetSysRoot/usr/lib64/crt1.o"
+ "$targetSysRoot/usr/lib64/crti.o"
if (dynamic) if (dynamic)
"${libGcc}/crtbeginS.o" + "$libGcc/crtbeginS.o"
else else
"${libGcc}/crtbegin.o", + "$libGcc/crtbegin.o"
"-L${llvmLib}", "-L${libGcc}", + "-L$llvmLib"
If (!isMips, // MIPS doesn't support hash-style=gnu + "-L$libGcc"
"--hash-style=gnu"), if (!isMips) + "--hash-style=gnu" // MIPS doesn't support hash-style=gnu
specificLibs, + specificLibs
"-L${targetSysRoot}/../lib", "-L${targetSysRoot}/lib", "-L${targetSysRoot}/usr/lib", + listOf("-L$targetSysRoot/../lib", "-L$targetSysRoot/lib", "-L$targetSysRoot/usr/lib")
If (optimize, if (optimize) {
"-plugin", "$llvmLib/LLVMgold.so", + "-plugin"
pluginOptimizationFlags, +"$llvmLib/LLVMgold.so"
linkerOptimizationFlags), + pluginOptimizationFlags
If (!debug, }
linkerNoDebugFlags), if (optimize) + linkerOptimizationFlags
If (dynamic, if (!debug) + linkerNoDebugFlags
linkerDynamicFlags), if (dynamic) + linkerDynamicFlags
objectFiles, + objectFiles
linkerKonanFlags, + linkerKonanFlags
"-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", + listOf("-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed",
"-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed", "-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed")
if (dynamic) if (dynamic)
"${libGcc}/crtendS.o" + "$libGcc/crtendS.o"
else else
"${libGcc}/crtend.o", + "$libGcc/crtend.o"
"${targetSysRoot}/usr/lib64/crtn.o" + "$targetSysRoot/usr/lib64/crtn.o"
) }
} }
} }
@@ -203,18 +234,14 @@ internal open class MingwPlatform(distribution: Distribution)
override fun filterStaticLibraries(binaries: List<String>) override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isWindowsStaticLib || it.isUnixStaticLib } = binaries.filter { it.isWindowsStaticLib || it.isUnixStaticLib }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): List<String> { override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
return listConstructor( return Command(linker).apply {
linker, + listOf("-o", executable)
"-o", executable, + objectFiles
objectFiles, if (optimize) + linkerOptimizationFlags
If (optimize, if (!debug) + linkerNoDebugFlags
linkerOptimizationFlags), if (dynamic) + linkerDynamicFlags
If (!debug, }
linkerNoDebugFlags),
If (dynamic,
linkerDynamicFlags)
)
} }
override fun linkCommandSuffix() = linkerKonanFlags override fun linkCommandSuffix() = linkerKonanFlags
@@ -230,13 +257,30 @@ internal open class WasmPlatform(distribution: Distribution)
override fun filterStaticLibraries(binaries: List<String>) override fun filterStaticLibraries(binaries: List<String>)
= emptyList<String>() = emptyList<String>()
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): List<String> { override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
// No link stage for WASM yet, just give '.wasm' as output. return object: Command("") {
val src = File(objectFiles.single()) override fun execute() {
val dst = File(executable) val src = File(objectFiles.single())
src.recursiveCopyTo(dst) val dst = File(executable)
src.recursiveCopyTo(dst)
javaScriptLink(libs.filter{it.isJavaScript}, executable)
}
return listOf() private fun javaScriptLink(jsFiles: List<String>, executable: String): String {
val linkedJavaScript = File("$executable.js")
val jsLibsExceptLauncher = jsFiles.filter { it != "launcher.js" }.map { it.removeSuffix(".js") }
val linkerStub = "var konan = { libraries: [] };\n"
linkedJavaScript.writeBytes(linkerStub.toByteArray());
jsFiles.forEach {
linkedJavaScript.appendBytes(File(it).readBytes())
}
return linkedJavaScript.name
}
}
} }
} }
@@ -373,52 +417,24 @@ internal class LinkStage(val context: Context) {
executable = dylibPath.absolutePath executable = dylibPath.absolutePath
} }
// Hack that removes using OS command line environment for copying files.
val toolExecution = platform.linkCommand(objectFiles, executable, optimize, debug, dynamic)
if (toolExecution.isEmpty() && platform is WasmPlatform) {
JavaScriptLinker(includedBinaries.filter{it.isJavaScript}, executable)
return executable
}
assert(toolExecution.isNotEmpty())
val linkCommand = toolExecution +
platform.targetLibffi +
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
entryPointSelector +
frameworkLinkerArgs +
platform.linkCommandSuffix() +
platform.linkStaticLibraries(includedBinaries) +
libraryProvidedLinkerFlags
try { try {
runTool(*linkCommand.toTypedArray()) platform.linkCommand(objectFiles, executable, optimize, debug, dynamic).apply {
+ platform.targetLibffi
+ asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS))
+ entryPointSelector
+ frameworkLinkerArgs
+ platform.linkCommandSuffix()
+ platform.linkStaticLibraries(includedBinaries)
+ libraryProvidedLinkerFlags
externalLibraries(includedBinaries)
}.execute()
} catch (e: KonanExternalToolFailure) { } catch (e: KonanExternalToolFailure) {
context.reportCompilationError("linker invocation reported errors") context.reportCompilationError("linker invocation reported errors")
return null return null
} }
if (platform is MacOSBasedPlatform && context.shouldContainDebugInfo()) {
if (context.phase?.verbose ?: false)
runTool(*platform.dsymutilDryRunVerboseCommand(executable).toTypedArray())
runTool(*platform.dsymutilCommand(executable).toTypedArray())
}
return executable return executable
} }
private fun JavaScriptLinker(jsFiles: List<String>, executable: String): String {
val linkedJavaScript = File("$executable.js")
val jsLibsExceptLauncher = jsFiles.filter { it != "launcher.js" }.map { it.removeSuffix(".js") }
val linkerStub = "var konan = { libraries: [] };\n"
linkedJavaScript.writeBytes(linkerStub.toByteArray());
jsFiles.forEach {
linkedJavaScript.appendBytes(File(it).readBytes())
}
return linkedJavaScript.name
}
private fun executeCommand(vararg command: String): Int { private fun executeCommand(vararg command: String): Int {
context.log{""} context.log{""}