Support static library production. (#1515)
This commit is contained in:
+1
-1
@@ -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
|
||||
|
||||
+4
-2
@@ -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,
|
||||
|
||||
+3
-2
@@ -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
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+48
-49
@@ -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) {
|
||||
|
||||
+1
-1
@@ -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)
|
||||
}
|
||||
|
||||
|
||||
+5
@@ -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))
|
||||
}
|
||||
|
||||
+1
@@ -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"
|
||||
|
||||
Reference in New Issue
Block a user