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
+2 -2
View File
@@ -72,7 +72,7 @@ model {
}
binaries.all {
cCompiler.args hostCompilerArgsForJni
cCompiler.args hostPlatform.clang.hostCompilerArgsForJni
cCompiler.args.addAll(cflags)
}
@@ -157,4 +157,4 @@ task updatePrebuilt {
into 'prebuilt/nativeInteropStubs/c'
}
}
}
}
+1 -1
View File
@@ -33,7 +33,7 @@ model {
def hostLibffiDir = rootProject.ext.get("${host}LibffiDir")
cCompiler.args hostCompilerArgsForJni
cCompiler.args hostPlatform.clang.hostCompilerArgsForJni
cCompiler.args "-I$hostLibffiDir/include"
linker.args "$hostLibffiDir/lib/libffi.a"
@@ -16,10 +16,13 @@
package org.jetbrains.kotlin.native.interop.tool
import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.properties.*
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.*
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.properties.loadProperties
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.PlatformManager
import org.jetbrains.kotlin.konan.target.TargetManager
import org.jetbrains.kotlin.konan.util.DependencyProcessor
import org.jetbrains.kotlin.konan.util.visibleName
class ToolConfig(userProvidedTargetName: String?, userProvidedKonanProperties: String?, runnerProvidedKonanHome: String) {
@@ -33,23 +36,21 @@ class ToolConfig(userProvidedTargetName: String?, userProvidedKonanProperties: S
private val dependencies = DependencyProcessor.defaultDependenciesRoot
private val targetProperties = KonanProperties(target, properties, dependencies.path)
private val platform = PlatformManager(properties, dependencies.path).platform(target)
val substitutions = mapOf<String, String> (
"target" to target.detailedName,
"arch" to target.architecture.visibleName)
fun downloadDependencies() = targetProperties.downloadDependencies()
fun downloadDependencies() = platform.downloadDependencies()
val llvmHome = targetProperties.absoluteLlvmHome
val defaultCompilerOpts =
platform.clang.targetLibclangArgs.toList()
val sysRoot get() = targetProperties.absoluteTargetSysRoot
val llvmHome = platform.absoluteLlvmHome
val sysRoot = platform.absoluteTargetSysRoot
val defaultCompilerOpts = ClangManager(properties, dependencies.path)
.targetLibclangArgs(targetProperties.target).toList()
val libclang = when (host) {
val libclang = when (host) {
KonanTarget.MINGW -> "$llvmHome/bin/libclang.dll"
else -> "$llvmHome/lib/${System.mapLibraryName("clang")}"
}
@@ -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()
}
@@ -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
+4 -4
View File
@@ -39,7 +39,7 @@ ext {
distDir = file('dist')
dependenciesDir = DependencyProcessor.defaultDependenciesRoot
clangManager = new ClangManager(konanProperties, dependenciesDir.absolutePath)
platformManager = new PlatformManager(konanProperties, dependenciesDir.absolutePath)
kotlinCompilerModule="org.jetbrains.kotlin:kotlin-compiler:${kotlinCompilerVersion}"
kotlinStdLibModule="org.jetbrains.kotlin:kotlin-stdlib:${kotlinStdLibVersion}"
kotlinReflectModule="org.jetbrains.kotlin:kotlin-reflect:${kotlinReflectVersion}"
@@ -71,7 +71,7 @@ void setupHostAndTarget() {
void setupClang(Project project) {
project.convention.plugins.clangManager = project.rootProject.ext.clangManager
project.convention.plugins.platformManager = project.rootProject.ext.platformManager
project.convention.plugins.execClang = new org.jetbrains.kotlin.ExecClang(project)
project.plugins.withType(NativeComponentPlugin) {
@@ -98,13 +98,13 @@ void setupClang(Project project) {
toolChains {
clang(Clang) {
hostClang.hostClangPath.each {
hostPlatform.clang.clangPaths.each {
path it
}
eachPlatform { // TODO: will not work when cross-compiling
[cCompiler, cppCompiler, linker].each {
it.withArguments { it.addAll(project.hostClangArgs) }
it.withArguments { it.addAll(project.hostPlatform.clang.clangArgs) }
}
}
@@ -33,7 +33,7 @@ class ExecClang {
}
private List<String> konanArgs(KonanTarget target) {
return project.rootProject.targetClangArgsForKonanSources(target)
return project.rootProject.platform(target).clang.clangArgsForKonanSources
}
private List<String> konanArgs(String target) {
@@ -95,7 +95,7 @@ class ExecClang {
throw new GradleException("unsupported clang executable: $executable")
}
environment["PATH"] = project.files(project.hostClang.hostClangPath).asPath +
environment["PATH"] = project.files(project.hostPlatform.clang.clangPaths).asPath +
File.pathSeparator + environment["PATH"]
args defaultArgs
}
@@ -238,7 +238,7 @@ class NamedNativeInteropConfig implements Named {
}
// TODO: the interop plugin should probably be reworked to execute clang from build scripts directly
environment['PATH'] = project.files(project.hostClang.hostClangPath).asPath +
environment['PATH'] = project.files(project.hostPlatform.clang.clangPaths).asPath +
File.pathSeparator + environment['PATH']
args compilerOpts.collectMany { ['-copt', it] }
+5 -5
View File
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.util.DependencyProcessor
import static org.jetbrains.kotlin.konan.target.KonanTarget.*
import static org.jetbrains.kotlin.konan.util.VisibleNamedKt.*
import org.jetbrains.kotlin.konan.properties.KonanProperties
import org.jetbrains.kotlin.konan.properties.KonanPropertiesLoader
import org.jetbrains.kotlin.konan.properties.*
buildscript {
@@ -210,14 +210,14 @@ class HelperNativeDep extends TgzNativeDep {
enum DependencyKind {
LLVM( "llvm", { it.llvmHome }, { "llvmDir" } ),
GCC_TOOLCHAIN( "gccToolchain", { it.gccToolchain }, { "gccToolchainDir" }),
GCC_TOOLCHAIN( "gccToolchain", { (it instanceof LinuxBasedConfigurables) ? it.gccToolchain : null }, { "gccToolchainDir" }),
SYSROOT( "sysroot", { it.targetSysRoot } ),
LIBFFI( "libffi", { it.libffiDir } ),
TARGET_TOOLCHAIN("targetToolchain", { it.targetToolchain } )
DependencyKind(String name,
@ClosureParams(value = FromString.class, options = "KonanProperties") Closure<String> dirGetter,
@ClosureParams(value = FromString.class, options = "KonanPropertiesLoader") Closure<String> dirGetter,
@ClosureParams(value = FromString.class, options = "KonanTarget") Closure<String> propertyNameGetter =
{target -> "${getVisibleName(target)}${name.capitalize()}Dir"}) {
this.name = name
@@ -229,7 +229,7 @@ enum DependencyKind {
private Closure<String> dirGetter // KonanProperties -> String
private Closure<String> propertyNameGetter // KonanTarget -> String
String getDirectory(KonanProperties properties) {
String getDirectory(KonanPropertiesLoader properties) {
return dirGetter(properties)
}
@@ -241,7 +241,7 @@ enum DependencyKind {
}
TargetManager.enabled.each { target ->
def konanProperties = new KonanProperties(target,
def konanProperties = new KonanPropertiesLoader(target,
rootProject.ext.konanProperties,
rootProject.ext.dependenciesDir.canonicalPath
)
@@ -135,7 +135,7 @@ val currentAbiVersion = 1
fun libraryInRepo(repository: File, name: String): File {
val resolver = KonanLibrarySearchPathResolver(
repositories = listOf(repository.absolutePath),
targetManager = null,
target = null,
distributionKlib = null,
localKonanDir = null,
skipCurrentDir = true
@@ -146,7 +146,7 @@ fun libraryInRepo(repository: File, name: String): File {
fun libraryInCurrentDir(name: String): File {
val resolver = KonanLibrarySearchPathResolver(
repositories = emptyList(),
targetManager = null,
target = null,
distributionKlib = null,
localKonanDir = null
)
@@ -156,7 +156,7 @@ fun libraryInCurrentDir(name: String): File {
fun libraryInRepoOrCurrentDir(repository: File, name: String): File {
val resolver = KonanLibrarySearchPathResolver(
repositories = listOf(repository.absolutePath),
targetManager = null,
target = null,
distributionKlib = null,
localKonanDir = null
)
@@ -14,8 +14,7 @@
* limitations under the License.
*/
package org.jetbrains.kotlin.backend.konan
package org.jetbrains.kotlin.konan.file
val String.isJavaScript
get() = this.endsWith(".js")
@@ -16,70 +16,70 @@
package org.jetbrains.kotlin.konan.target
import org.jetbrains.kotlin.konan.properties.KonanProperties
import org.jetbrains.kotlin.konan.file.File
class ClangTargetArgs(val target: KonanTarget, konanProperties: KonanProperties) {
class ClangArgs(private val configurables: Configurables) : Configurables by configurables {
val sysRoot = konanProperties.absoluteTargetSysRoot
val targetArg = konanProperties.targetArg
val targetArg = if (configurables is NonAppleConfigurables)
configurables.targetArg
else null
val specificClangArgs: List<String> get() {
val result = when (target) {
KonanTarget.LINUX ->
listOf("--sysroot=$sysRoot")
listOf("--sysroot=$absoluteTargetSysRoot")
KonanTarget.RASPBERRYPI ->
listOf("-target", targetArg!!,
"-mfpu=vfp", "-mfloat-abi=hard",
"--sysroot=$sysRoot",
"--sysroot=$absoluteTargetSysRoot",
// TODO: those two are hacks.
"-I$sysRoot/usr/include/c++/4.8.3",
"-I$sysRoot/usr/include/c++/4.8.3/arm-linux-gnueabihf")
"-I$absoluteTargetSysRoot/usr/include/c++/4.8.3",
"-I$absoluteTargetSysRoot/usr/include/c++/4.8.3/arm-linux-gnueabihf")
KonanTarget.LINUX_MIPS32 ->
listOf("-target", targetArg!!,
"--sysroot=$sysRoot",
"-I$sysRoot/usr/include/c++/4.9.4",
"-I$sysRoot/usr/include/c++/4.9.4/mips-unknown-linux-gnu")
"--sysroot=$absoluteTargetSysRoot",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4/mips-unknown-linux-gnu")
KonanTarget.LINUX_MIPSEL32 ->
listOf("-target", targetArg!!,
"--sysroot=$sysRoot",
"-I$sysRoot/usr/include/c++/4.9.4",
"-I$sysRoot/usr/include/c++/4.9.4/mipsel-unknown-linux-gnu")
"--sysroot=$absoluteTargetSysRoot",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.4/mipsel-unknown-linux-gnu")
KonanTarget.MINGW ->
listOf("-target", targetArg!!, "--sysroot=$sysRoot", "-Xclang", "-flto-visibility-public-std")
listOf("-target", targetArg!!, "--sysroot=$absoluteTargetSysRoot", "-Xclang", "-flto-visibility-public-std")
KonanTarget.MACBOOK ->
listOf("--sysroot=$sysRoot", "-mmacosx-version-min=10.11")
listOf("--sysroot=$absoluteTargetSysRoot", "-mmacosx-version-min=10.11")
KonanTarget.IPHONE ->
listOf("-stdlib=libc++", "-arch", "arm64", "-isysroot", sysRoot, "-miphoneos-version-min=8.0.0")
listOf("-stdlib=libc++", "-arch", "arm64", "-isysroot", absoluteTargetSysRoot, "-miphoneos-version-min=8.0.0")
KonanTarget.IPHONE_SIM ->
listOf("-stdlib=libc++", "-isysroot", sysRoot, "-miphoneos-version-min=8.0.0")
listOf("-stdlib=libc++", "-isysroot", absoluteTargetSysRoot, "-miphoneos-version-min=8.0.0")
KonanTarget.ANDROID_ARM32 ->
listOf("-target", targetArg!!,
"--sysroot=$sysRoot",
"--sysroot=$absoluteTargetSysRoot",
// HACKS!
"-I$sysRoot/usr/include/c++/4.9.x",
"-I$sysRoot/usr/include/c++/4.9.x/arm-linux-androideabi")
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x/arm-linux-androideabi")
KonanTarget.ANDROID_ARM64 ->
listOf("-target", targetArg!!,
"--sysroot=$sysRoot",
"--sysroot=$absoluteTargetSysRoot",
// HACKS!
"-I$sysRoot/usr/include/c++/4.9.x",
"-I$sysRoot/usr/include/c++/4.9.x/aarch64-linux-android")
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x",
"-I$absoluteTargetSysRoot/usr/include/c++/4.9.x/aarch64-linux-android")
KonanTarget.WASM32 ->
listOf("-target", targetArg!!, "-O1", "-fno-rtti", "-fno-exceptions",
"-D_LIBCPP_ABI_VERSION=2", "-D_LIBCPP_NO_EXCEPTIONS=1",
"-nostdinc", "-Xclang", "-nobuiltininc", "-Xclang", "-nostdsysteminc",
"-Xclang", "-isystem$sysRoot/include/libcxx", "-Xclang", "-isystem$sysRoot/lib/libcxxabi/include",
"-Xclang", "-isystem$sysRoot/include/compat", "-Xclang", "-isystem$sysRoot/include/libc")
"-Xclang", "-isystem$absoluteTargetSysRoot/include/libcxx", "-Xclang", "-isystem$absoluteTargetSysRoot/lib/libcxxabi/include",
"-Xclang", "-isystem$absoluteTargetSysRoot/include/compat", "-Xclang", "-isystem$absoluteTargetSysRoot/include/libc")
}
return result
}
@@ -119,35 +119,58 @@ class ClangTargetArgs(val target: KonanTarget, konanProperties: KonanProperties)
listOf("-DKONAN_WASM=1", "-DKONAN_NO_FFI=1", "-DKONAN_NO_THREADS=1", "-DKONAN_NO_EXCEPTIONS=1",
"-DKONAN_INTERNAL_DLMALLOC=1", "-DKONAN_INTERNAL_SNPRINTF=1", "-DKONAN_INTERNAL_NOW=1")
}
}
class ClangHostArgs(val hostProperties: KonanProperties) {
private val host = TargetManager.host
val targetToolchain get() = hostProperties.absoluteTargetToolchain
val gccToolchain get() = hostProperties.absoluteGccToolchain
val sysRoot get() = hostProperties.absoluteTargetSysRoot
val llvmDir get() = hostProperties.absoluteLlvmHome
val binDir = when(TargetManager.host) {
KonanTarget.LINUX -> "$targetToolchain/bin"
KonanTarget.MINGW -> "$sysRoot/bin"
KonanTarget.MACBOOK -> "$targetToolchain/usr/bin"
private val binDir = when(host) {
KonanTarget.LINUX -> "$absoluteTargetToolchain/bin"
KonanTarget.MINGW -> "$absoluteTargetToolchain/bin"
KonanTarget.MACBOOK -> "$absoluteTargetToolchain/usr/bin"
else -> throw TargetSupportException("Unexpected host platform")
}
private val extraHostClangArgs =
if (TargetManager.host == KonanTarget.LINUX) {
listOf("--gcc-toolchain=$gccToolchain")
if (configurables is LinuxBasedConfigurables) {
listOf("--gcc-toolchain=${configurables.absoluteGccToolchain}")
} else {
emptyList()
}
val commonClangArgs = listOf("-B$binDir") + extraHostClangArgs
val hostClangPath = listOf("$llvmDir/bin", binDir)
val clangPaths = listOf("$absoluteLlvmHome/bin", binDir)
private val jdkHome = File.jdkHome.absoluteFile.parent
val hostCompilerArgsForJni = listOf("", TargetManager.jniHostPlatformIncludeDir).map { "-I$jdkHome/include/$it" }
val hostCompilerArgsForJni = listOf("", TargetManager.jniHostPlatformIncludeDir).map { "-I$jdkHome/include/$it" }.toTypedArray()
val clangArgs =
(commonClangArgs + specificClangArgs).toTypedArray()
val clangArgsForKonanSources =
clangArgs + clangArgsSpecificForKonanSources
val targetLibclangArgs: List<String> get() {
// libclang works not exactly the same way as the clang binary and
// (in particular) uses different default header search path.
// See e.g. http://lists.llvm.org/pipermail/cfe-dev/2013-November/033680.html
// We workaround the problem with -isystem flag below.
val llvmVersion = llvmVersion
val llvmHome = absoluteLlvmHome
val isystemArgs = listOf("-isystem", "$llvmHome/lib/clang/$llvmVersion/include")
return isystemArgs + clangArgs.toList()
}
val targetClangCmd
= listOf("${absoluteLlvmHome}/bin/clang") + clangArgs
val targetClangXXCmd
= listOf("${absoluteLlvmHome}/bin/clang++") + clangArgs
fun clangC(vararg userArgs: String) = targetClangCmd + userArgs.asList()
fun clangCXX(vararg userArgs: String) = targetClangXXCmd + userArgs.asList()
}
@@ -1,74 +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 -> 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.konan.target
import org.jetbrains.kotlin.konan.properties.*
class ClangManager(val properties: Properties, val baseDir: String) {
private val host = TargetManager.host
private val enabledTargets = TargetManager.enabled
private val konanProperties = enabledTargets.map {
it to KonanProperties(it, properties, baseDir)
}.toMap()
private val targetClangArgs = enabledTargets.map {
it to ClangTargetArgs(it, konanProperties[it]!!)
}.toMap()
private val hostClang = ClangHostArgs(konanProperties[host]!!)
// These are converted to arrays to be convenient
// in groovy plugins.
val hostClangArgs = (hostClang.commonClangArgs + targetClangArgs[host]!!.specificClangArgs).toTypedArray()
fun targetClangArgs(target: KonanTarget)
= (hostClang.commonClangArgs + targetClangArgs[target]!!.specificClangArgs).toTypedArray()
fun targetClangArgsForKonanSources(target: KonanTarget) =
targetClangArgs(target) + targetClangArgs[target]!!.clangArgsSpecificForKonanSources
val hostCompilerArgsForJni = hostClang.hostCompilerArgsForJni.toTypedArray()
fun targetLibclangArgs(target: KonanTarget): List<String> {
// libclang works not exactly the same way as the clang binary and
// (in particular) uses different default header search path.
// See e.g. http://lists.llvm.org/pipermail/cfe-dev/2013-November/033680.html
// We workaround the problem with -isystem flag below.
val llvmVersion = properties.hostString("llvmVersion")!!
val llvmHome = konanProperties[target]!!.absoluteLlvmHome
val isystemArgs = listOf("-isystem", "$llvmHome/lib/clang/$llvmVersion/include")
return isystemArgs + targetClangArgs(target).toList()
}
fun targetClangCmd(target: KonanTarget)
= listOf("${hostClang.llvmDir}/bin/clang") + targetClangArgs(target)
fun targetClangXXCmd(target: KonanTarget)
= listOf("${hostClang.llvmDir}/bin/clang++") + targetClangArgs(target)
}
class TargetClang(private val clangManager: ClangManager, private val target: KonanTarget) {
constructor (properties: Properties, baseDir: String, target: KonanTarget)
: this (ClangManager(properties, baseDir), target)
fun clangC(vararg userArgs: String) = clangManager.targetClangCmd(target) + userArgs.asList()
fun clangCXX(vararg userArgs: String) = clangManager.targetClangXXCmd(target) + userArgs.asList()
}
@@ -0,0 +1,80 @@
/*
* 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 -> 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.konan.target
import org.jetbrains.kotlin.konan.properties.*
interface Configurables : TargetableExternalStorage {
val target: KonanTarget
val llvmHome get() = hostString("llvmHome")
val llvmVersion get() = hostString("llvmVersion")
// TODO: Delegate to a map?
val llvmLtoNooptFlags get() = targetList("llvmLtoNooptFlags")
val llvmLtoOptFlags get() = targetList("llvmLtoOptFlags")
val llvmLtoFlags get() = targetList("llvmLtoFlags")
val llvmLtoDynamicFlags get() = targetList("llvmLtoDynamicFlags")
val entrySelector get() = targetList("entrySelector")
val linkerOptimizationFlags get() = targetList("linkerOptimizationFlags")
val linkerKonanFlags get() = targetList("linkerKonanFlags")
val linkerNoDebugFlags get() = targetList("linkerNoDebugFlags")
val linkerDynamicFlags get() = targetList("linkerDynamicFlags")
val llvmDebugOptFlags get() = targetList("llvmDebugOptFlags")
val targetSysRoot get() = targetString("targetSysRoot")
val libffiDir get() = targetString("libffiDir")
// Notice: these ones are host-target.
val targetToolchain get() = hostTargetString("targetToolchain")
val absoluteTargetSysRoot get() = absolute(targetSysRoot)
val absoluteTargetToolchain get() = absolute(targetToolchain)
val absoluteLlvmHome get() = absolute(llvmHome)
val absoluteLibffiDir get() = absolute(libffiDir)
}
interface NonAppleConfigurables : Configurables {
val targetArg get() = targetString("quadruple")
}
interface AppleConfigurables : Configurables {
val arch get() = targetString("arch")!!
val osVersionMin get() = targetString("osVersionMin")!!
val osVersionMinFlagLd get() = targetString("osVersionMinFlagLd")!!
}
interface MingwConfigurables : NonAppleConfigurables
interface LinuxBasedConfigurables : NonAppleConfigurables {
val gccToolchain get() = hostString("gccToolchain")
val absoluteGccToolchain get() = absolute(gccToolchain)
val libGcc get() = targetString("libGcc")!!
val dynamicLinker get() = targetString("dynamicLinker")!!
val pluginOptimizationFlags get() = targetList("pluginOptimizationFlags")
val abiSpecificLibraries get() = targetList("abiSpecificLibraries")
}
interface LinuxConfigurables : LinuxBasedConfigurables
interface LinuxMIPSConfigurables : LinuxBasedConfigurables
interface RaspberryPiConfigurables : LinuxBasedConfigurables
interface AndroidConfigurables : NonAppleConfigurables
interface WasmConfigurables : NonAppleConfigurables {
val s2wasmFlags get() = targetList("s2wasmFlags")
}
@@ -0,0 +1,54 @@
/*
* 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 -> 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.konan.target
import org.jetbrains.kotlin.konan.properties.*
class LinuxConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: LinuxConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class LinuxMIPSConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: LinuxMIPSConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class AndroidConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: AndroidConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class AppleConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: AppleConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class MingwConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: MingwConfigurables, KonanPropertiesLoader(target, properties, baseDir)
class WasmConfigurablesImpl(target: KonanTarget, properties: Properties, baseDir: String?)
: WasmConfigurables, KonanPropertiesLoader(target, properties, baseDir)
fun loadConfigurables(target: KonanTarget, properties: Properties, baseDir: String?) = when (target) {
KonanTarget.LINUX, KonanTarget.RASPBERRYPI ->
LinuxConfigurablesImpl(target, properties, baseDir)
KonanTarget.LINUX_MIPS32, KonanTarget.LINUX_MIPSEL32 ->
LinuxMIPSConfigurablesImpl(target, properties, baseDir)
KonanTarget.MACBOOK, KonanTarget.IPHONE, KonanTarget.IPHONE_SIM ->
AppleConfigurablesImpl(target, properties, baseDir)
KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64 ->
AndroidConfigurablesImpl(target, properties, baseDir)
KonanTarget.MINGW ->
MingwConfigurablesImpl(target, properties, baseDir)
KonanTarget.WASM32 ->
WasmConfigurablesImpl(target, properties, baseDir)
}
@@ -16,73 +16,44 @@
package org.jetbrains.kotlin.konan.properties
import org.jetbrains.kotlin.konan.file.*
import org.jetbrains.kotlin.konan.target.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.konan.target.Configurables
import org.jetbrains.kotlin.konan.util.DependencyProcessor
class KonanProperties(val target: KonanTarget, val properties: Properties, val baseDir: String? = null) {
interface TargetableExternalStorage {
fun targetString(key: String): String?
fun targetList(key: String): List<String>
fun hostString(key: String): String?
fun hostList(key: String): List<String>
fun hostTargetString(key: String): String?
fun hostTargetList(key: String): List<String>
fun absolute(value: String?): String
fun downloadDependencies()
}
fun downloadDependencies() {
open class KonanPropertiesLoader(override val target: KonanTarget, val properties: Properties, val baseDir: String? = null) : Configurables {
val dependencies get() = hostTargetList("dependencies")
override fun downloadDependencies() {
dependencyProcessor!!.run()
}
fun targetString(key: String): String?
override fun targetString(key: String): String?
= properties.targetString(key, target)
fun targetList(key: String): List<String>
override fun targetList(key: String): List<String>
= properties.targetList(key, target)
fun hostString(key: String): String?
override fun hostString(key: String): String?
= properties.hostString(key)
fun hostList(key: String): List<String>
override fun hostList(key: String): List<String>
= properties.hostList(key)
fun hostTargetString(key: String): String?
override fun hostTargetString(key: String): String?
= properties.hostTargetString(key, target)
fun hostTargetList(key: String): List<String>
override fun hostTargetList(key: String): List<String>
= properties.hostTargetList(key, target)
val llvmHome get() = hostString("llvmHome")
// TODO: Delegate to a map?
val llvmLtoNooptFlags get() = targetList("llvmLtoNooptFlags")
val llvmLtoOptFlags get() = targetList("llvmLtoOptFlags")
val llvmLtoFlags get() = targetList("llvmLtoFlags")
val llvmLtoDynamicFlags get() = targetList("llvmLtoDynamicFlags")
val entrySelector get() = targetList("entrySelector")
val linkerOptimizationFlags get() = targetList("linkerOptimizationFlags")
val linkerKonanFlags get() = targetList("linkerKonanFlags")
val linkerNoDebugFlags get() = targetList("linkerNoDebugFlags")
val linkerDynamicFlags get() = targetList("linkerDynamicFlags")
val llvmDebugOptFlags get() = targetList("llvmDebugOptFlags")
val s2wasmFlags get() = targetList("s2wasmFlags")
val targetSysRoot get() = targetString("targetSysRoot")
val libffiDir get() = targetString("libffiDir")
val gccToolchain get() = targetString("gccToolchain")
val targetArg get() = targetString("quadruple")
// Notice: these ones are host-target.
val targetToolchain get() = hostTargetString("targetToolchain")
val dependencies get() = hostTargetList("dependencies")
private fun absolute(value: String?): String =
override fun absolute(value: String?): String =
dependencyProcessor!!.resolveRelative(value!!).absolutePath
val absoluteTargetSysRoot get() = absolute(targetSysRoot)
val absoluteTargetToolchain get() = absolute(targetToolchain)
val absoluteGccToolchain get() = absolute(gccToolchain)
val absoluteLlvmHome get() = absolute(llvmHome)
val absoluteLibffiDir get() = absolute(libffiDir)
val mingwWithLlvm: String?
get() {
if (target != KonanTarget.MINGW) {
error("Only mingw target can have '.mingwWithLlvm' property")
}
// TODO: make it a property in the konan.properties.
// Use (equal) llvmHome fow now.
return targetString("llvmHome")
}
val osVersionMin: String? get() = targetString("osVersionMin")
private val dependencyProcessor = baseDir?.let { DependencyProcessor(java.io.File(it), this) }
private val dependencyProcessor by lazy {
baseDir?.let { DependencyProcessor(java.io.File(it), this) }
}
}
@@ -0,0 +1,303 @@
/*
* 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.konan.target
import java.lang.ProcessBuilder
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
// Use "clang -v -save-temps" to write linkCommand() method
// for another implementation of this class.
abstract class LinkerFlags(val configurables: Configurables)
/* : Configurables by configurables */{
protected val llvmBin = "${configurables.absoluteLlvmHome}/bin"
protected val llvmLib = "${configurables.absoluteLlvmHome}/lib"
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")}"
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
open fun linkCommandSuffix(): List<String> = emptyList()
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
}
}
open class AndroidLinker(targetProperties: AndroidConfigurables)
: LinkerFlags(targetProperties), AndroidConfigurables by targetProperties {
private val prefix = "$absoluteTargetToolchain/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
}
}
}
open class MacOSBasedLinker(targetProperties: AppleConfigurables)
: LinkerFlags(targetProperties), AppleConfigurables by targetProperties {
private val linker = "$absoluteTargetToolchain/usr/bin/ld"
internal val dsymutil = "$absoluteLlvmHome/bin/llvm-dsymutil"
open val osVersionMinFlags: List<String> by lazy {
listOf(
osVersionMinFlagLd,
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", arch)
+ osVersionMinFlags
+ listOf("-syslibroot", absoluteTargetSysRoot, "-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)
}
open class LinuxBasedLinker(targetProperties: LinuxBasedConfigurables)
: LinkerFlags(targetProperties), LinuxBasedConfigurables by targetProperties {
override val libGcc: String = "$absoluteTargetSysRoot/${super.libGcc}"
private val linker = "$absoluteTargetToolchain/bin/ld.gold"
private val specificLibs
= abiSpecificLibraries.map { "-L${absoluteTargetSysRoot}/$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 = (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"
}
}
}
open class MingwLinker(targetProperties: MingwConfigurables)
: LinkerFlags(targetProperties), MingwConfigurables by targetProperties {
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 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
}
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 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
}
}
}
}
fun linker(configurables: Configurables): LinkerFlags =
when (configurables.target) {
KonanTarget.LINUX, KonanTarget.RASPBERRYPI ->
LinuxBasedLinker(configurables as LinuxConfigurables)
KonanTarget.LINUX_MIPS32, KonanTarget.LINUX_MIPSEL32 ->
LinuxBasedLinker(configurables as LinuxMIPSConfigurables)
KonanTarget.MACBOOK, KonanTarget.IPHONE, KonanTarget.IPHONE_SIM ->
MacOSBasedLinker(configurables as AppleConfigurables)
KonanTarget.ANDROID_ARM32, KonanTarget.ANDROID_ARM64 ->
AndroidLinker(configurables as AndroidConfigurables)
KonanTarget.MINGW ->
MingwLinker(configurables as MingwConfigurables)
KonanTarget.WASM32 ->
WasmLinker(configurables as WasmConfigurables)
}
@@ -0,0 +1,41 @@
/*
* Copyright 2010-2018 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.konan.target
import org.jetbrains.kotlin.konan.properties.*
class Platform(val configurables: Configurables)
: Configurables by configurables {
val clang by lazy {
ClangArgs(configurables)
}
val linker by lazy {
linker(configurables)
}
}
class PlatformManager(properties: Properties, baseDir: String) {
private val host = TargetManager.host
private val platforms = TargetManager.enabled.map {
it to Platform(loadConfigurables(it, properties, baseDir))
}.toMap()
fun platform(target: KonanTarget) = platforms[target]!!
val hostPlatform = platforms[host]!!
}
@@ -17,7 +17,7 @@
package org.jetbrains.kotlin.konan.util
import org.jetbrains.kotlin.konan.file.use
import org.jetbrains.kotlin.konan.properties.KonanProperties
import org.jetbrains.kotlin.konan.properties.KonanPropertiesLoader
import org.jetbrains.kotlin.konan.properties.Properties
import org.jetbrains.kotlin.konan.properties.propertyList
import java.io.File
@@ -69,11 +69,11 @@ private fun Properties.findCandidates(dependencies: List<String>): Map<String, L
}
private val KonanProperties.dependenciesUrl : String get() = properties.dependenciesUrl
private val KonanProperties.airplaneMode : Boolean get() = properties.airplaneMode
private val KonanProperties.downloadingAttempts : Int get() = properties.downloadingAttempts
private val KonanProperties.downloadingAttemptIntervalMs : Long get() = properties.downloadingAttemptIntervalMs
private val KonanProperties.homeDependencyCache : String get() = properties.homeDependencyCache
private val KonanPropertiesLoader.dependenciesUrl : String get() = properties.dependenciesUrl
private val KonanPropertiesLoader.airplaneMode : Boolean get() = properties.airplaneMode
private val KonanPropertiesLoader.downloadingAttempts : Int get() = properties.downloadingAttempts
private val KonanPropertiesLoader.downloadingAttemptIntervalMs : Long get() = properties.downloadingAttemptIntervalMs
private val KonanPropertiesLoader.homeDependencyCache : String get() = properties.homeDependencyCache
sealed class DependencySource {
data class Local(val path: File) : DependencySource()
@@ -114,7 +114,7 @@ class DependencyProcessor(dependenciesRoot: File,
private val archiveExtension get() = extractor.archiveExtension
constructor(dependenciesRoot: File,
properties: KonanProperties,
properties: KonanPropertiesLoader,
dependenciesUrl: String = properties.dependenciesUrl,
keepUnstable:Boolean = true) : this(
dependenciesRoot,
@@ -65,7 +65,7 @@ fun invokeInterop(flavor: String, args: Array<String>): Array<String> {
val manifest = File(buildDir, "manifest.properties")
val targetManager = TargetManager(target)
val resolver = defaultResolver(repos, targetManager)
val resolver = defaultResolver(repos, targetManager.target)
val allLibraries = resolver.resolveLibrariesRecursive(
libraries, targetManager.target, noStdLib = true, noDefaultLibs = noDefaultLibs
)