[stage][link] commmand reprisentation
This commit is contained in:
committed by
Vasily Levchenko
parent
dd42c63bd2
commit
9d211e74c5
+133
-117
@@ -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{""}
|
||||||
|
|||||||
Reference in New Issue
Block a user