Splitted KonanProperties into Configurables hierarchy.

Untangled Platfrom classes from the LinkStage and Distribution.
Simplified clang management a little.
This commit is contained in:
Alexander Gorshenev
2018-01-19 17:11:48 +03:00
committed by alexander-gorshenev
parent c5276cf6da
commit d4b47ac709
25 changed files with 653 additions and 558 deletions
@@ -20,7 +20,7 @@ import org.jetbrains.kotlin.konan.exec.*
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.file.*
fun produceCAdapterBitcode(clang: TargetClang, cppFileName: String, bitcodeFileName: String) {
fun produceCAdapterBitcode(clang: ClangArgs, cppFileName: String, bitcodeFileName: String) {
val clangCommand = clang.clangCXX("-std=c++11", cppFileName, "-emit-llvm", "-c", "-o", bitcodeFileName)
Command(clangCommand).execute()
}
@@ -16,21 +16,15 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.properties.*
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.visibleName
import org.jetbrains.kotlin.konan.util.DependencyProcessor
class Distribution(val targetManager: TargetManager,
val propertyFileOverride: String? = null,
val runtimeFileOverride: String? = null) {
val target = targetManager.target
val targetName = targetManager.targetName
val host = TargetManager.host
val hostSuffix = TargetManager.hostSuffix
val hostTargetSuffix = targetManager.hostTargetSuffix
val targetSuffix = targetManager.targetSuffix
class Distribution(val target: KonanTarget,
propertyFileOverride: String? = null,
runtimeFileOverride: String? = null) {
val localKonanDir = "${File.userHome}/.konan"
@@ -46,22 +40,10 @@ class Distribution(val targetManager: TargetManager,
val klib = "$konanHome/klib"
val stdlib = "$klib/common/stdlib"
val targetName = target.visibleName
val defaultNatives = "$konanHome/konan/targets/${targetName}/native"
val runtime = runtimeFileOverride ?: "$stdlib/targets/${targetName}/native/runtime.bc"
val dependenciesDir = DependencyProcessor.defaultDependenciesRoot.absolutePath
val targetProperties = KonanProperties(target, properties, dependenciesDir)
val llvmHome = targetProperties.absoluteLlvmHome
val llvmBin = "$llvmHome/bin"
val llvmLib = "$llvmHome/lib"
val llvmLto = "$llvmBin/llvm-lto"
private val libLTODir = when (TargetManager.host) {
KonanTarget.MACBOOK, KonanTarget.LINUX -> llvmLib
KonanTarget.MINGW -> llvmBin
else -> error("Don't know libLTO location for this platform.")
}
val libLTO = "$libLTODir/${System.mapLibraryName("LTO")}"
}
@@ -52,19 +52,17 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
val indirectBranchesAreAllowed = target != KonanTarget.WASM32
private fun Distribution.prepareDependencies(checkDependencies: Boolean) {
if (checkDependencies) {
targetProperties.downloadDependencies()
internal val distribution = Distribution(target,
configuration.get(KonanConfigKeys.PROPERTY_FILE),
configuration.get(KonanConfigKeys.RUNTIME_FILE))
internal val platform = PlatformManager(distribution.properties, distribution.dependenciesDir).platform(target).apply {
if (configuration.getBoolean(KonanConfigKeys.CHECK_DEPENDENCIES)) {
downloadDependencies()
}
}
internal val distribution = Distribution(targetManager,
configuration.get(KonanConfigKeys.PROPERTY_FILE),
configuration.get(KonanConfigKeys.RUNTIME_FILE)).apply {
prepareDependencies(configuration.getBoolean(KonanConfigKeys.CHECK_DEPENDENCIES))
}
internal val clang = TargetClang(distribution.properties, distribution.dependenciesDir, target)
internal val clang = platform.clang
internal val produce get() = configuration.get(KonanConfigKeys.PRODUCE)!!
private val prefix = produce.prefix(target)
@@ -16,310 +16,21 @@
package org.jetbrains.kotlin.backend.konan
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.*
typealias BitcodeFile = String
typealias ObjectFile = String
typealias ExecutableFile = String
// Use "clang -v -save-temps" to write linkCommand() method
// for another implementation of this class.
internal abstract class PlatformFlags(val properties: KonanProperties) {
val llvmLtoNooptFlags = properties.llvmLtoNooptFlags
val llvmLtoOptFlags = properties.llvmLtoOptFlags
val llvmLtoFlags = properties.llvmLtoFlags
val llvmLtoDynamicFlags = properties.llvmLtoDynamicFlags
val entrySelector = properties.entrySelector
val linkerOptimizationFlags = properties.linkerOptimizationFlags
val linkerKonanFlags = properties.linkerKonanFlags
val linkerNoDebugFlags = properties.linkerNoDebugFlags
val linkerDynamicFlags = properties.linkerDynamicFlags
val llvmDebugOptFlags = properties.llvmDebugOptFlags
val s2wasmFlags = properties.s2wasmFlags
val targetToolchain = properties.absoluteTargetToolchain
val targetSysRoot = properties.absoluteTargetSysRoot
val targetLibffi = properties.libffiDir ?.let { listOf("${properties.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
open fun linkCommandSuffix(): List<String> = emptyList()
protected fun propertyTargetString(name: String)
= properties.targetString(name)!!
protected fun propertyTargetList(name: String)
= properties.targetList(name)
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
return libraries
}
}
internal open class AndroidPlatform(distribution: Distribution)
: PlatformFlags(distribution.targetProperties) {
private val prefix = "$targetToolchain/bin/"
private val clang = "$prefix/clang"
override val useCompilerDriverAsLinker: Boolean get() = true
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
}
}
}
internal open class MacOSBasedPlatform(distribution: Distribution)
: PlatformFlags(distribution.targetProperties) {
private val linker = "$targetToolchain/usr/bin/ld"
internal val dsymutil = "${distribution.llvmBin}/llvm-dsymutil"
internal val libLTO = distribution.libLTO
open val osVersionMin by lazy {
listOf(
propertyTargetString("osVersionMinFlagLd"),
properties.osVersionMin!! + ".0")
}
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", propertyTargetString("arch"))
+ osVersionMin
+ listOf("-syslibroot", targetSysRoot, "-o", executable)
+ objectFiles
if (optimize) + linkerOptimizationFlags
if (!debug) + linkerNoDebugFlags
if (dynamic) + linkerDynamicFlags
+ linkerKonanFlags
+ "-lSystem"
}
}
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 {
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, outputDsymBundle: String): List<String> =
listOf(dsymutil, executable, "-o", outputDsymBundle)
open fun dsymutilDryRunVerboseCommand(executable: ExecutableFile): List<String> =
listOf(dsymutil, "-dump-debug-map" ,executable)
}
internal open class LinuxBasedPlatform(val distribution: Distribution)
: PlatformFlags(distribution.targetProperties) {
private val llvmLib = distribution.llvmLib
private val libGcc = "$targetSysRoot/${propertyTargetString("libGcc")}"
private val linker = "$targetToolchain/bin/ld.gold"
private val pluginOptimizationFlags = propertyTargetList("pluginOptimizationFlags")
private val specificLibs
= propertyTargetList("abiSpecificLibraries").map { "-L${targetSysRoot}/$it" }
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 = (distribution.target == KonanTarget.LINUX_MIPS32 ||
distribution.target == KonanTarget.LINUX_MIPSEL32)
// TODO: Can we extract more to the konan.properties?
return Command(linker).apply {
+ "--sysroot=${targetSysRoot}"
+ "-export-dynamic"
+ "-z"
+ "relro"
+ "--build-id"
+ "--eh-frame-hdr"
// + "-m"
// + "elf_x86_64",
+ "-dynamic-linker"
+ propertyTargetString("dynamicLinker")
+ "-o"
+ executable
if (!dynamic) + "$targetSysRoot/usr/lib64/crt1.o"
+ "$targetSysRoot/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$targetSysRoot/../lib", "-L$targetSysRoot/lib", "-L$targetSysRoot/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"
+ "$targetSysRoot/usr/lib64/crtn.o"
}
}
}
internal open class MingwPlatform(distribution: Distribution)
: PlatformFlags(distribution.targetProperties) {
private val linker = "$targetToolchain/bin/clang++"
override val useCompilerDriverAsLinker: Boolean get() = true
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 linkCommandSuffix() = linkerKonanFlags
}
internal open class WasmPlatform(distribution: Distribution)
: PlatformFlags(distribution.targetProperties) {
private val clang = "clang"
override val useCompilerDriverAsLinker: Boolean get() = false
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 execute() {
val src = File(objectFiles.single())
val dst = File(executable)
src.recursiveCopyTo(dst)
javaScriptLink(args, executable)
}
private fun javaScriptLink(jsFiles: List<String>, executable: String): String {
val linkedJavaScript = File("$executable.js")
val linkerHeader = "var konan = { libraries: [] };\n"
val linkerFooter = """|if (isBrowser()) {
| konan.moduleEntry([]);
|} else {
| konan.moduleEntry(arguments);
|}""".trimMargin()
linkedJavaScript.writeBytes(linkerHeader.toByteArray());
jsFiles.forEach {
linkedJavaScript.appendBytes(File(it).readBytes())
}
linkedJavaScript.appendBytes(linkerFooter.toByteArray());
return linkedJavaScript.name
}
}
}
}
internal class LinkStage(val context: Context) {
val config = context.config.configuration
val target = context.config.targetManager.target
private val distribution = context.config.distribution
private val platform = when (target) {
KonanTarget.LINUX, KonanTarget.RASPBERRYPI,
KonanTarget.LINUX_MIPS32, KonanTarget.LINUX_MIPSEL32 ->
LinuxBasedPlatform(distribution)
KonanTarget.MACBOOK, KonanTarget.IPHONE, KonanTarget.IPHONE_SIM ->
MacOSBasedPlatform(distribution)
KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64 ->
AndroidPlatform(distribution)
KonanTarget.MINGW ->
MingwPlatform(distribution)
KonanTarget.WASM32 ->
WasmPlatform(distribution)
}
private val config = context.config.configuration
private val target = context.config.targetManager.target
private val platform = context.config.platform
private val linker = platform.linker
private val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false
private val debug = config.get(KonanConfigKeys.DEBUG) ?: false
@@ -341,7 +52,7 @@ internal class LinkStage(val context: Context) {
private fun llvmLto(files: List<BitcodeFile>): ObjectFile {
val combined = temporary("combined", ".o")
val tool = distribution.llvmLto
val tool = "${platform.absoluteLlvmHome}/bin/llvm-lto"
val command = mutableListOf(tool, "-o", combined)
command.addNonEmpty(platform.llvmLtoFlags)
when {
@@ -363,12 +74,12 @@ internal class LinkStage(val context: Context) {
}
private fun targetTool(tool: String, vararg arg: String) {
val absoluteToolName = "${platform.targetToolchain}/bin/$tool"
val absoluteToolName = "${platform.absoluteTargetToolchain}/bin/$tool"
runTool(absoluteToolName, *arg)
}
private fun hostLlvmTool(tool: String, args: List<String>) {
val absoluteToolName = "${distribution.llvmBin}/$tool"
val absoluteToolName = "${platform.absoluteLlvmHome}/bin/$tool"
val command = listOf(absoluteToolName) + args
runTool(command)
}
@@ -380,7 +91,7 @@ internal class LinkStage(val context: Context) {
val combinedS = temporary("combined", ".s")
targetTool("llc", combinedBc, "-o", combinedS)
val s2wasmFlags = platform.s2wasmFlags.toTypedArray()
val s2wasmFlags = (platform.configurables as WasmConfigurables).s2wasmFlags.toTypedArray()
val combinedWast = temporary( "combined", ".wast")
targetTool("s2wasm", combinedS, "-o", combinedWast, *s2wasmFlags)
@@ -392,7 +103,7 @@ internal class LinkStage(val context: Context) {
}
private fun asLinkerArgs(args: List<String>): List<String> {
if (platform.useCompilerDriverAsLinker) {
if (linker.useCompilerDriverAsLinker) {
return args
}
@@ -440,21 +151,21 @@ internal class LinkStage(val context: Context) {
}
try {
platform.linkCommand(objectFiles, executable, optimize, debug, dynamic).apply {
+ platform.targetLibffi
linker.linkCommand(objectFiles, executable, optimize, debug, dynamic).apply {
+ linker.targetLibffi
+ asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS))
+ entryPointSelector
+ frameworkLinkerArgs
+ platform.linkCommandSuffix()
+ platform.linkStaticLibraries(includedBinaries)
+ linker.linkCommandSuffix()
+ linker.linkStaticLibraries(includedBinaries)
+ libraryProvidedLinkerFlags
logger = context::log
}.execute()
if (debug && platform is MacOSBasedPlatform) {
if (debug && linker is MacOSBasedLinker) {
val outputDsymBundle = context.config.outputFile + ".dSYM" // `outputFile` is either binary or bundle.
platform.dsymUtilCommand(executable, outputDsymBundle)
linker.dsymUtilCommand(executable, outputDsymBundle)
.logWith(context::log)
.execute()
}
@@ -1,27 +0,0 @@
/*
* 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.backend.konan
val String.isJavaScript
get() = this.endsWith(".js")
val String.isUnixStaticLib
get() = this.endsWith(".a")
val String.isWindowsStaticLib
get() = this.endsWith(".lib")
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.backend.konan.util.suffixIfNot
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.TargetManager
import org.jetbrains.kotlin.konan.util.visibleName
interface SearchPathResolver {
val searchRoots: List<File>
@@ -30,13 +31,13 @@ interface SearchPathResolver {
fun defaultLinks(nostdlib: Boolean, noDefaultLibs: Boolean): List<File>
}
fun defaultResolver(repositories: List<String>, targetManager: TargetManager): SearchPathResolver =
defaultResolver(repositories, Distribution(targetManager))
fun defaultResolver(repositories: List<String>, target: KonanTarget): SearchPathResolver =
defaultResolver(repositories, Distribution(target))
fun defaultResolver(repositories: List<String>, distribution: Distribution): SearchPathResolver =
KonanLibrarySearchPathResolver(
repositories,
distribution.targetManager,
distribution.target,
distribution.klib,
distribution.localKonanDir
)
@@ -133,7 +134,7 @@ fun SearchPathResolver.resolveLibrariesRecursive(libraryNames: List<String>,
class KonanLibrarySearchPathResolver(
repositories: List<String>,
val targetManager: TargetManager?,
val target: KonanTarget?,
val distributionKlib: String?,
val localKonanDir: String?,
val skipCurrentDir: Boolean = false
@@ -146,7 +147,7 @@ class KonanLibrarySearchPathResolver(
get() = distributionKlib?.File()?.child("common")
val distPlatformHead: File?
get() = targetManager?.let { distributionKlib?.File()?.child("platform")?.child(targetManager.targetName) }
get() = target?.let { distributionKlib?.File()?.child("platform")?.child(target.visibleName) }
val currentDirHead: File?
get() = if (!skipCurrentDir) File.userDir else null
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.AppleConfigurables
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.isSubpackageOf
@@ -102,7 +103,8 @@ internal class ObjCExport(val context: Context) {
KonanTarget.MACBOOK -> "MacOSX"
else -> error(target)
}
val minimumOsVersion = context.config.distribution.targetProperties.osVersionMin!!
val properties = context.config.platform.configurables as AppleConfigurables
val minimumOsVersion = properties.osVersionMin!!
val contents = StringBuilder()
contents.append("""
+3
View File
@@ -193,9 +193,11 @@ targetToolchain.linux-linux_mips32 = target-gcc-toolchain-2-linux-mips/x86_64-un
dependencies.linux-linux_mips32 = \
clang-llvm-5.0.0-linux-x86-64 \
target-gcc-toolchain-2-linux-mips \
target-gcc-toolchain-3-linux-x86-64 \
target-sysroot-2-mips \
libffi-3.2.1-2-linux-x86-64 \
libffi-3.2.1-2-linux-mips
quadruple.linux_mips32 = mips-unknown-linux-gnu
entrySelector.linux_mips32 = --defsym main=Konan_main
linkerOptimizationFlags.linux_mips32 = --gc-sections
@@ -220,6 +222,7 @@ targetToolchain.linux-linux_mipsel32 = target-gcc-toolchain-2-linux-mips/x86_64-
dependencies.linux-linux_mipsel32 = \
clang-llvm-5.0.0-linux-x86-64 \
target-gcc-toolchain-2-linux-mips \
target-gcc-toolchain-3-linux-x86-64 \
target-sysroot-2-mipsel \
libffi-3.2.1-2-linux-x86-64 \
libffi-3.2.1-2-linux-mipsel