Support static library production. (#1515)

This commit is contained in:
Nikolay Igotti
2018-04-20 12:25:59 +01:00
committed by GitHub
parent 6abf95d86d
commit 569bb71bca
10 changed files with 296 additions and 202 deletions
@@ -796,7 +796,7 @@ internal class CAdapterGenerator(
output("#endif /* KONAN_${prefix.toUpperCase()}_H */")
outputStreamWriter.close()
println("Produced dynamic library API in ${prefix}_api.h")
println("Produced library API in ${prefix}_api.h")
outputStreamWriter = context.config.tempFiles
.cAdapterCpp
@@ -22,7 +22,8 @@ import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
val CompilerOutputKind.isNativeBinary: Boolean get() = when (this) {
CompilerOutputKind.PROGRAM, CompilerOutputKind.DYNAMIC, CompilerOutputKind.FRAMEWORK -> true
CompilerOutputKind.PROGRAM, CompilerOutputKind.DYNAMIC,
CompilerOutputKind.STATIC, CompilerOutputKind.FRAMEWORK -> true
CompilerOutputKind.LIBRARY, CompilerOutputKind.BITCODE -> false
}
@@ -34,6 +35,7 @@ internal fun produceOutput(context: Context) {
val produce = config.get(KonanConfigKeys.PRODUCE)
when (produce) {
CompilerOutputKind.STATIC,
CompilerOutputKind.DYNAMIC,
CompilerOutputKind.FRAMEWORK,
CompilerOutputKind.PROGRAM -> {
@@ -41,7 +43,7 @@ internal fun produceOutput(context: Context) {
context.bitcodeFileName = output
val generatedBitcodeFiles =
if (produce == CompilerOutputKind.DYNAMIC) {
if (produce == CompilerOutputKind.DYNAMIC || produce == CompilerOutputKind.STATIC) {
produceCAdapterBitcode(
context.config.clang,
tempFiles.cAdapterCppName,
@@ -394,8 +394,9 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
lateinit var debugInfo: DebugInfo
val isDynamicLibrary: Boolean by lazy {
config.configuration.get(KonanConfigKeys.PRODUCE) == CompilerOutputKind.DYNAMIC
val isNativeLibrary: Boolean by lazy {
val kind = config.configuration.get(KonanConfigKeys.PRODUCE)
kind == CompilerOutputKind.DYNAMIC || kind == CompilerOutputKind.STATIC
}
}
@@ -35,8 +35,12 @@ internal class LinkStage(val context: Context) {
private val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false
private val debug = config.get(KonanConfigKeys.DEBUG) ?: false
private val dynamic = context.config.produce == CompilerOutputKind.DYNAMIC ||
context.config.produce == CompilerOutputKind.FRAMEWORK
private val linkerOutput = when (context.config.produce) {
CompilerOutputKind.DYNAMIC, CompilerOutputKind.FRAMEWORK -> LinkerOutputKind.DYNAMIC_LIBRARY
CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY
CompilerOutputKind.PROGRAM -> LinkerOutputKind.EXECUTABLE
else -> TODO("${context.config.produce} should not reach native linker stage")
}
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
private val emitted = context.bitcodeFileName
private val libraries = context.llvm.librariesToLink
@@ -45,10 +49,10 @@ internal class LinkStage(val context: Context) {
}
private fun runTool(command: List<String>) = runTool(*command.toTypedArray())
private fun runTool(vararg command: String) =
Command(*command)
.logWith(context::log)
.execute()
private fun runTool(vararg command: String) =
Command(*command)
.logWith(context::log)
.execute()
private fun llvmLto(files: List<BitcodeFile>): ObjectFile {
val combined = temporary("combined", ".o")
@@ -58,8 +62,8 @@ internal class LinkStage(val context: Context) {
command.addNonEmpty(platform.llvmLtoFlags)
when {
optimize -> command.addNonEmpty(platform.llvmLtoOptFlags)
debug -> command.addNonEmpty(platform.llvmDebugOptFlags)
else -> command.addNonEmpty(platform.llvmLtoNooptFlags)
debug -> command.addNonEmpty(platform.llvmDebugOptFlags)
else -> command.addNonEmpty(platform.llvmLtoNooptFlags)
}
command.addNonEmpty(platform.llvmLtoDynamicFlags)
command.addNonEmpty(files)
@@ -89,27 +93,27 @@ internal class LinkStage(val context: Context) {
hostLlvmTool("llvm-link", *bitcodeFiles.toTypedArray(), "-o", combinedBc)
val optFlags = (configurables.optFlags + when {
optimize -> configurables.optOptFlags
debug -> configurables.optDebugFlags
else -> configurables.optNooptFlags
optimize -> configurables.optOptFlags
debug -> configurables.optDebugFlags
else -> configurables.optNooptFlags
}).toTypedArray()
val optimizedBc = temporary("optimized", ".bc")
hostLlvmTool("opt", combinedBc, "-o", optimizedBc, *optFlags)
val llcFlags = (configurables.llcFlags + when {
optimize -> configurables.llcOptFlags
debug -> configurables.llcDebugFlags
else -> configurables.llcNooptFlags
optimize -> configurables.llcOptFlags
debug -> configurables.llcDebugFlags
else -> configurables.llcNooptFlags
}).toTypedArray()
val combinedS = temporary("combined", ".s")
targetTool("llc", optimizedBc, "-o", combinedS, *llcFlags)
val s2wasmFlags = configurables.s2wasmFlags.toTypedArray()
val combinedWast = temporary( "combined", ".wast")
val combinedWast = temporary("combined", ".wast")
targetTool("s2wasm", combinedS, "-o", combinedWast, *s2wasmFlags)
val combinedWasm = temporary( "combined", ".wasm")
val combinedSmap = temporary( "combined", ".smap")
val combinedWasm = temporary("combined", ".wasm")
val combinedSmap = temporary("combined", ".smap")
targetTool("wasm-as", combinedWast, "-o", combinedWasm, "-g", "-s", combinedSmap)
return combinedWasm
@@ -153,9 +157,11 @@ internal class LinkStage(val context: Context) {
// So we stick to "-alias _main _konan_main" on Mac.
// And just do the same on Linux.
private val entryPointSelector: List<String>
get() = if (nomain || dynamic) emptyList() else platform.entrySelector
get() = if (nomain || linkerOutput != LinkerOutputKind.EXECUTABLE) emptyList() else platform.entrySelector
private fun link(objectFiles: List<ObjectFile>, includedBinaries: List<String>, libraryProvidedLinkerFlags: List<String>): ExecutableFile? {
private fun link(objectFiles: List<ObjectFile>,
includedBinaries: List<String>,
libraryProvidedLinkerFlags: List<String>): ExecutableFile? {
val frameworkLinkerArgs: List<String>
val executable: String
@@ -177,23 +183,16 @@ internal class LinkStage(val context: Context) {
}
try {
linker.linkCommand(objectFiles, executable, optimize, debug, dynamic).apply {
+ linker.targetLibffi
+ asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS))
+ entryPointSelector
+ frameworkLinkerArgs
+ linker.linkCommandSuffix()
+ linker.linkStaticLibraries(includedBinaries)
+ libraryProvidedLinkerFlags
logger = context::log
}.execute()
if (debug && linker is MacOSBasedLinker) {
val outputDsymBundle = context.config.outputFile + ".dSYM" // `outputFile` is either binary or bundle.
linker.dsymUtilCommand(executable, outputDsymBundle)
.logWith(context::log)
.execute()
File(executable).delete()
linker.linkCommands(objectFiles = objectFiles, executable = executable,
libraries = linker.targetLibffi + linker.linkStaticLibraries(includedBinaries),
linkerArgs = entryPointSelector +
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
libraryProvidedLinkerFlags + frameworkLinkerArgs,
optimize = optimize, debug = debug, kind = linkerOutput,
outputDsymBundle = context.config.outputFile + ".dSYM").forEach {
it.logWith(context::log)
it.execute()
}
} catch (e: KonanExternalToolFailure) {
context.reportCompilationError("${e.toolName} invocation reported errors")
@@ -204,27 +203,27 @@ internal class LinkStage(val context: Context) {
fun linkStage() {
val bitcodeFiles = listOf(emitted) +
libraries.map{it -> it.bitcodePaths}.flatten()
libraries.map { it -> it.bitcodePaths }.flatten()
val includedBinaries =
libraries.map{it -> it.includedPaths}.flatten()
val includedBinaries =
libraries.map { it -> it.includedPaths }.flatten()
val libraryProvidedLinkerFlags =
libraries.map{it -> it.linkerOpts}.flatten()
val libraryProvidedLinkerFlags =
libraries.map { it -> it.linkerOpts }.flatten()
val objectFiles: MutableList<String> = mutableListOf()
val phaser = PhaseManager(context)
phaser.phase(KonanPhase.OBJECT_FILES) {
objectFiles.add(
when (platform.configurables) {
is WasmConfigurables
-> bitcodeToWasm(bitcodeFiles)
is ZephyrConfigurables
-> llvmLinkAndLlc(bitcodeFiles)
else
objectFiles.add(
when (platform.configurables) {
is WasmConfigurables
-> bitcodeToWasm(bitcodeFiles)
is ZephyrConfigurables
-> llvmLinkAndLlc(bitcodeFiles)
else
-> llvmLto(bitcodeFiles)
}
}
)
}
phaser.phase(KonanPhase.LINKER) {
@@ -348,7 +348,7 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
appendStaticInitializers()
appendEntryPointSelector(context.ir.symbols.entryPoint?.owner)
if (context.isDynamicLibrary) {
if (context.isNativeLibrary) {
appendCAdapters()
}
@@ -19,14 +19,15 @@ package org.jetbrains.kotlin.konan.target
import org.jetbrains.kotlin.konan.target.KonanTarget.*
import org.jetbrains.kotlin.konan.util.Named
enum class Family(val exeSuffix:String, val dynamicPrefix: String, val dynamicSuffix: String) {
OSX ("kexe", "lib", "dylib"),
IOS ("kexe", "lib", "dylib"),
LINUX ("kexe", "lib", "so" ),
MINGW ("exe" , "" , "dll" ),
ANDROID ("so" , "lib", "so" ),
WASM ("wasm", "" , "wasm" ),
ZEPHYR ("o" , "lib", "a" )
enum class Family(val exeSuffix:String, val dynamicPrefix: String, val dynamicSuffix: String,
val staticPrefix: String, val staticSuffix: String) {
OSX ("kexe", "lib", "dylib", "lib", "a"),
IOS ("kexe", "lib", "dylib", "lib", "a"),
LINUX ("kexe", "lib", "so" , "lib", "a"),
MINGW ("exe" , "" , "dll" , "lib", "a"),
ANDROID ("so" , "lib", "so" , "lib", "a"),
WASM ("wasm", "" , "wasm" , "", "wasm"),
ZEPHYR ("o" , "lib", "a" , "lib", "a")
}
enum class Architecture(val bitness: Int) {
@@ -68,6 +69,10 @@ enum class CompilerOutputKind {
override fun suffix(target: KonanTarget?) = ".${target!!.family.dynamicSuffix}"
override fun prefix(target: KonanTarget?) = "${target!!.family.dynamicPrefix}"
},
STATIC {
override fun suffix(target: KonanTarget?) = ".${target!!.family.staticSuffix}"
override fun prefix(target: KonanTarget?) = "${target!!.family.staticPrefix}"
},
FRAMEWORK {
override fun suffix(target: KonanTarget?): String = ".framework"
},
@@ -21,14 +21,19 @@ import java.lang.ProcessBuilder.Redirect
import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.*
typealias BitcodeFile = String
typealias ObjectFile = String
typealias ExecutableFile = String
enum class LinkerOutputKind {
DYNAMIC_LIBRARY,
STATIC_LIBRARY,
EXECUTABLE
}
// Use "clang -v -save-temps" to write linkCommand() method
// for another implementation of this class.
abstract class LinkerFlags(val configurables: Configurables)
/* : Configurables by configurables */{
/* : Configurables by configurables */ {
protected val llvmBin = "${configurables.absoluteLlvmHome}/bin"
protected val llvmLib = "${configurables.absoluteLlvmHome}/lib"
@@ -41,55 +46,80 @@ abstract class LinkerFlags(val configurables: Configurables)
val libLTO = "$libLTODir/${System.mapLibraryName("LTO")}"
val targetLibffi = configurables.libffiDir ?.let { listOf("${configurables.absoluteLibffiDir}/lib/libffi.a") } ?: emptyList()
val targetLibffi = configurables.libffiDir?.let { listOf("${configurables.absoluteLibffiDir}/lib/libffi.a") }
?: emptyList()
open val useCompilerDriverAsLinker: Boolean get() = false // TODO: refactor.
abstract fun linkCommand(objectFiles: List<ObjectFile>,
executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command
abstract fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command>
open fun linkCommandSuffix(): List<String> = emptyList()
abstract fun filterStaticLibraries(binaries: List<String>): List<String>
abstract fun filterStaticLibraries(binaries: List<String>): List<String>
open fun linkStaticLibraries(binaries: List<String>): List<String> {
val libraries = filterStaticLibraries(binaries)
// Let's just pass them as absolute paths
// Let's just pass them as absolute paths.
return libraries
}
protected fun postLinkGnuArCommand(ar: String, executable: ExecutableFile) =
Command("/bin/sh", "-c").apply {
+"/bin/echo -e 'create $executable\\naddlib $executable\\nsave\\nend' | $ar -M"
}
}
open class AndroidLinker(targetProperties: AndroidConfigurables)
: LinkerFlags(targetProperties), AndroidConfigurables by targetProperties {
: LinkerFlags(targetProperties), AndroidConfigurables by targetProperties {
private val prefix = "$absoluteTargetToolchain/bin/"
private val clang = "$prefix/clang"
private val ar = "$prefix/ar"
override val useCompilerDriverAsLinker: Boolean get() = true
override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isUnixStaticLib }
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isUnixStaticLib }
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.
return Command(clang).apply {
+ "-o"
+ executable
+ "-fPIC"
+ "-shared"
+ "-llog"
+ objectFiles
if (optimize) + linkerOptimizationFlags
if (!debug) + linkerNoDebugFlags
if (dynamic) + linkerDynamicFlags
+ linkerKonanFlags
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY) {
// Here we take somewhat unexpected approach - we create the thin
// library, and then repack it during post-link phase.
// This way we ensure .a inputs are properly processed.
return listOf(
Command(ar, "cqT", executable).apply {
+objectFiles
+libraries
},
postLinkGnuArCommand(ar, executable))
}
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
// liblog.so must be linked in, as we use its functionality in runtime.
return listOf(Command(clang).apply {
+"-o"
+executable
+"-fPIC"
+"-shared"
+"-llog"
+objectFiles
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
+linkerKonanFlags
+libraries
+linkerArgs
})
}
}
open class MacOSBasedLinker(targetProperties: AppleConfigurables)
: LinkerFlags(targetProperties), AppleConfigurables by targetProperties {
private val libtool = "$absoluteTargetToolchain/usr/bin/libtool"
private val linker = "$absoluteTargetToolchain/usr/bin/ld"
internal val dsymutil = "$absoluteLlvmHome/bin/llvm-dsymutil"
@@ -99,30 +129,42 @@ open class MacOSBasedLinker(targetProperties: AppleConfigurables)
osVersionMin + ".0")
}
override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isUnixStaticLib }
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isUnixStaticLib }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
return object : Command(linker) {} .apply {
+ "-demangle"
+ listOf("-object_path_lto", "temporary.o", "-lto_library", libLTO)
+ listOf("-dynamic", "-arch", arch)
+ osVersionMinFlags
+ listOf("-syslibroot", absoluteTargetSysRoot, "-o", executable)
+ objectFiles
if (optimize) + linkerOptimizationFlags
if (!debug) + linkerNoDebugFlags
if (dynamic) + linkerDynamicFlags
+ linkerKonanFlags
+ "-lSystem"
}
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean, kind: LinkerOutputKind,
outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY)
return listOf(Command(libtool).apply {
+"-static"
+listOf("-o", executable)
+objectFiles
+libraries
})
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
return listOf(Command(linker).apply {
+"-demangle"
+listOf("-object_path_lto", "temporary.o", "-lto_library", libLTO)
+listOf("-dynamic", "-arch", arch)
+osVersionMinFlags
+listOf("-syslibroot", absoluteTargetSysRoot, "-o", executable)
+objectFiles
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
+linkerKonanFlags
+"-lSystem"
+libraries
+linkerArgs
}) + if (debug) listOf(dsymUtilCommand(executable, outputDsymBundle)) else emptyList()
}
fun dsymUtilCommand(executable: ExecutableFile, outputDsymBundle: String) =
object : Command(dsymutilCommand(executable, outputDsymBundle)) {
override fun runProcess(): Int =
executeCommandWithFilter(command)
}
fun dsymUtilCommand(executable: ExecutableFile, outputDsymBundle: String) =
object : Command(dsymutilCommand(executable, outputDsymBundle)) {
override fun runProcess(): Int =
executeCommandWithFilter(command)
}
// TODO: consider introducing a better filtering directly in Command.
private fun executeCommandWithFilter(command: List<String>): Int {
@@ -155,106 +197,136 @@ open class MacOSBasedLinker(targetProperties: AppleConfigurables)
return exitCode
}
open fun dsymutilCommand(executable: ExecutableFile, outputDsymBundle: String): List<String> =
listOf(dsymutil, executable, "-o", outputDsymBundle)
open fun dsymutilCommand(executable: ExecutableFile, outputDsymBundle: String): List<String> =
listOf(dsymutil, executable, "-o", outputDsymBundle)
open fun dsymutilDryRunVerboseCommand(executable: ExecutableFile): List<String> =
listOf(dsymutil, "-dump-debug-map" ,executable)
listOf(dsymutil, "-dump-debug-map", executable)
}
open class LinuxBasedLinker(targetProperties: LinuxBasedConfigurables)
: LinkerFlags(targetProperties), LinuxBasedConfigurables by targetProperties {
private val ar = "$absoluteTargetToolchain/bin/ar"
override val libGcc: String = "$absoluteTargetSysRoot/${super.libGcc}"
private val linker = "$absoluteTargetToolchain/bin/ld.gold"
private val specificLibs
= abiSpecificLibraries.map { "-L${absoluteTargetSysRoot}/$it" }
private val specificLibs = abiSpecificLibraries.map { "-L${absoluteTargetSysRoot}/$it" }
override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isUnixStaticLib }
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isUnixStaticLib }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
val isMips = (configurables is LinuxMIPSConfigurables)
// TODO: Can we extract more to the konan.configurables?
return Command(linker).apply {
+ "--sysroot=${absoluteTargetSysRoot}"
+ "-export-dynamic"
+ "-z"
+ "relro"
+ "--build-id"
+ "--eh-frame-hdr"
+ "-dynamic-linker"
+ dynamicLinker
+ "-o"
+ executable
if (!dynamic) + "$absoluteTargetSysRoot/usr/lib64/crt1.o"
+ "$absoluteTargetSysRoot/usr/lib64/crti.o"
if (dynamic)
+ "$libGcc/crtbeginS.o"
else
+ "$libGcc/crtbegin.o"
+ "-L$llvmLib"
+ "-L$libGcc"
if (!isMips) + "--hash-style=gnu" // MIPS doesn't support hash-style=gnu
+ specificLibs
+ listOf("-L$absoluteTargetSysRoot/../lib", "-L$absoluteTargetSysRoot/lib", "-L$absoluteTargetSysRoot/usr/lib")
if (optimize) {
+ "-plugin"
+"$llvmLib/LLVMgold.so"
+ pluginOptimizationFlags
}
if (optimize) + linkerOptimizationFlags
if (!debug) + linkerNoDebugFlags
if (dynamic) + linkerDynamicFlags
+ objectFiles
+ linkerKonanFlags
+ listOf("-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed",
"-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed")
if (dynamic)
+ "$libGcc/crtendS.o"
else
+ "$libGcc/crtend.o"
+ "$absoluteTargetSysRoot/usr/lib64/crtn.o"
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY) {
// Here we take somewhat unexpected approach - we create the thin
// library, and then repack it during post-link phase.
// This way we ensure .a inputs are properly processed.
return listOf(Command(ar, "cqT", executable).apply {
+objectFiles
+libraries
},
postLinkGnuArCommand(ar, executable))
}
val isMips = (configurables is LinuxMIPSConfigurables)
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
// TODO: Can we extract more to the konan.configurables?
return listOf(Command(linker).apply {
+"--sysroot=${absoluteTargetSysRoot}"
+"-export-dynamic"
+"-z"
+"relro"
+"--build-id"
+"--eh-frame-hdr"
+"-dynamic-linker"
+dynamicLinker
+"-o"
+executable
if (!dynamic) +"$absoluteTargetSysRoot/usr/lib64/crt1.o"
+"$absoluteTargetSysRoot/usr/lib64/crti.o"
+if (dynamic) "$libGcc/crtbeginS.o" else "$libGcc/crtbegin.o"
+"-L$llvmLib"
+"-L$libGcc"
if (!isMips) +"--hash-style=gnu" // MIPS doesn't support hash-style=gnu
+specificLibs
+listOf("-L$absoluteTargetSysRoot/../lib", "-L$absoluteTargetSysRoot/lib", "-L$absoluteTargetSysRoot/usr/lib")
if (optimize) {
+"-plugin"
+"$llvmLib/LLVMgold.so"
+pluginOptimizationFlags
}
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
+objectFiles
+linkerKonanFlags
+listOf("-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed",
"-lc", "-lgcc", "--as-needed", "-lgcc_s", "--no-as-needed")
+if (dynamic) "$libGcc/crtendS.o" else "$libGcc/crtend.o"
+"$absoluteTargetSysRoot/usr/lib64/crtn.o"
+libraries
+linkerArgs
})
}
}
open class MingwLinker(targetProperties: MingwConfigurables)
: LinkerFlags(targetProperties), MingwConfigurables by targetProperties {
private val ar = "$absoluteTargetToolchain\\bin\\ar"
private val linker = "$absoluteTargetToolchain/bin/clang++"
override val useCompilerDriverAsLinker: Boolean get() = true
override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter { it.isWindowsStaticLib || it.isUnixStaticLib }
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isWindowsStaticLib || it.isUnixStaticLib }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
return Command(linker).apply {
+ listOf("-o", executable)
+ objectFiles
if (optimize) + linkerOptimizationFlags
if (!debug) + linkerNoDebugFlags
if (dynamic) + linkerDynamicFlags
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind == LinkerOutputKind.STATIC_LIBRARY) {
// Here we take somewhat unexpected approach - we create the thin
// library, and then repack it during post-link phase.
// This way we ensure .a inputs are properly processed.
val temp = executable.replace('/', '\\') + "__"
return listOf(
Command(ar, "-rucT", temp).apply {
+objectFiles
+libraries
},
Command("cmd", "/c").apply {
+"(echo create $executable & echo addlib ${temp} & echo save & echo end) | $ar -M"
},
Command("cmd", "/c", "del", "/q", temp))
}
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
return listOf(Command(linker).apply {
+listOf("-o", executable)
+objectFiles
if (optimize) +linkerOptimizationFlags
if (!debug) +linkerNoDebugFlags
if (dynamic) +linkerDynamicFlags
+libraries
+linkerArgs
+linkerKonanFlags
})
}
override fun linkCommandSuffix() = linkerKonanFlags
}
open class WasmLinker(targetProperties: WasmConfigurables)
: LinkerFlags(targetProperties), WasmConfigurables by targetProperties {
private val clang = "clang"
override val useCompilerDriverAsLinker: Boolean get() = false
override fun filterStaticLibraries(binaries: List<String>)
= binaries.filter{it.isJavaScript}
override fun filterStaticLibraries(binaries: List<String>) = binaries.filter { it.isJavaScript }
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
return object: Command("") {
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind != LinkerOutputKind.EXECUTABLE) throw Error("Unsupported linker output kind")
// TODO(horsh): make it proper list.
return listOf(object : Command() {
override fun execute() {
val src = File(objectFiles.single())
val dst = File(executable)
@@ -281,7 +353,7 @@ open class WasmLinker(targetProperties: WasmConfigurables)
linkedJavaScript.appendBytes(linkerFooter.toByteArray());
return linkedJavaScript.name
}
}
})
}
}
@@ -292,33 +364,38 @@ open class ZephyrLinker(targetProperties: ZephyrConfigurables)
override val useCompilerDriverAsLinker: Boolean get() = false
override fun filterStaticLibraries(binaries: List<String>)
= emptyList<String>()
override fun filterStaticLibraries(binaries: List<String>) = emptyList<String>()
override fun linkCommand(objectFiles: List<ObjectFile>, executable: ExecutableFile, optimize: Boolean, debug: Boolean, dynamic: Boolean): Command {
return Command(linker).apply {
+ listOf("-r", "--gc-sections", "--entry", "main")
+ listOf("-o", executable)
+ objectFiles
}
override fun linkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean,
kind: LinkerOutputKind, outputDsymBundle: String): List<Command> {
if (kind != LinkerOutputKind.EXECUTABLE) throw Error("Unsupported linker output kind: $kind")
return listOf(Command(linker).apply {
+listOf("-r", "--gc-sections", "--entry", "main")
+listOf("-o", executable)
+objectFiles
+libraries
+linkerArgs
})
}
}
fun linker(configurables: Configurables): LinkerFlags =
when (configurables.target) {
KonanTarget.LINUX_X64, KonanTarget.LINUX_ARM32_HFP ->
LinuxBasedLinker(configurables as LinuxConfigurables)
KonanTarget.LINUX_MIPS32, KonanTarget.LINUX_MIPSEL32 ->
LinuxBasedLinker(configurables as LinuxMIPSConfigurables)
KonanTarget.MACOS_X64, KonanTarget.IOS_ARM64, KonanTarget.IOS_X64 ->
MacOSBasedLinker(configurables as AppleConfigurables)
KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64 ->
AndroidLinker(configurables as AndroidConfigurables)
KonanTarget.MINGW_X64 ->
MingwLinker(configurables as MingwConfigurables)
KonanTarget.WASM32 ->
WasmLinker(configurables as WasmConfigurables)
is KonanTarget.ZEPHYR ->
ZephyrLinker(configurables as ZephyrConfigurables)
}
fun linker(configurables: Configurables): LinkerFlags =
when (configurables.target) {
KonanTarget.LINUX_X64, KonanTarget.LINUX_ARM32_HFP ->
LinuxBasedLinker(configurables as LinuxConfigurables)
KonanTarget.LINUX_MIPS32, KonanTarget.LINUX_MIPSEL32 ->
LinuxBasedLinker(configurables as LinuxMIPSConfigurables)
KonanTarget.MACOS_X64, KonanTarget.IOS_ARM64, KonanTarget.IOS_X64 ->
MacOSBasedLinker(configurables as AppleConfigurables)
KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64 ->
AndroidLinker(configurables as AndroidConfigurables)
KonanTarget.MINGW_X64 ->
MingwLinker(configurables as MingwConfigurables)
KonanTarget.WASM32 ->
WasmLinker(configurables as WasmConfigurables)
is KonanTarget.ZEPHYR ->
ZephyrLinker(configurables as ZephyrConfigurables)
}
@@ -110,6 +110,10 @@ class EnvVariableSpecification extends BaseKonanSpecification {
prefix = target.family.dynamicPrefix
suffix = target.family.dynamicSuffix
break
case ArtifactType.STATIC:
prefix = target.family.staticPrefix
suffix = target.family.staticSuffix
break
case ArtifactType.FRAMEWORK:
suffix = "framework"
}
@@ -194,6 +198,7 @@ class EnvVariableSpecification extends BaseKonanSpecification {
files.contains(artifactFileName("program", ArtifactType.PROGRAM))
files.contains(artifactFileName("library", ArtifactType.LIBRARY))
files.contains(artifactFileName("dynamic", ArtifactType.DYNAMIC))
files.contains(artifactFileName("static", ArtifactType.STATIC))
if (HostManager.hostIsMac) {
files.contains(artifactFileName("framework", ArtifactType.FRAMEWORK))
}
@@ -29,6 +29,7 @@ enum ArtifactType {
BITCODE("bitcode"),
INTEROP("interop"),
DYNAMIC("dynamic"),
STATIC("static"),
FRAMEWORK("framework")
String type
@@ -32,6 +32,10 @@ open class PropertiesAsEnvVariables {
prefix = target.family.dynamicPrefix
suffix = target.family.dynamicSuffix
}
ArtifactType.STATIC -> {
prefix = target.family.staticPrefix
suffix = target.family.staticSuffix
}
}
return "$prefix${baseName}.$suffix"