Use clang instead if llvm-lto for darwin-based targets (#2974)

* Use LLVM C API for optimizations
* Use Clang for bitcode compilation
* Test bitcode embedding
This commit is contained in:
Sergey Bogolepov
2019-05-15 13:00:43 +07:00
committed by GitHub
parent 89c2fb21c4
commit 5306d7b427
23 changed files with 620 additions and 367 deletions
@@ -171,7 +171,6 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
put(VERBOSE_PHASES,
arguments.verbosePhases.toNonNullList())
put(LIST_PHASES, arguments.listPhases)
put(TIME_PHASES, arguments.timePhases)
put(COMPATIBLE_COMPILER_VERSIONS,
arguments.compatibleCompilerVersions.toNonNullList())
@@ -153,9 +153,6 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xtemporary-files-dir", deprecatedName = "--temporary_files_dir", valueDescription = "<path>", description = "Save temporary files to the given directory")
var temporaryFilesDir: String? = null
@Argument(value = "-Xtime", deprecatedName = "--time", description = "Report execution time for compiler phases")
var timePhases: Boolean = false
@Argument(value = "-Xverify-bitcode", deprecatedName = "--verify_bitcode", description = "Verify llvm bitcode after each method")
var verifyBitCode: Boolean = false
@@ -0,0 +1,179 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan
import llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.target.*
typealias BitcodeFile = String
typealias ObjectFile = String
typealias ExecutableFile = String
private fun mangleSymbol(target: KonanTarget,symbol: String) =
if (target.family == Family.IOS || target.family == Family.OSX) {
"_$symbol"
} else {
symbol
}
internal class BitcodeCompiler(val context: Context) {
private val target = context.config.target
private val platform = context.config.platform
private val optimize = context.shouldOptimize()
private val debug = context.config.debug
private fun MutableList<String>.addNonEmpty(elements: List<String>) {
addAll(elements.filter { !it.isEmpty() })
}
private val exportedSymbols = context.coverage.addExportedSymbols()
private fun runTool(vararg command: String) =
Command(*command)
.logWith(context::log)
.execute()
private fun temporary(name: String, suffix: String): String =
context.config.tempFiles.create(name, suffix).absolutePath
private fun targetTool(tool: String, vararg arg: String) {
val absoluteToolName = if (platform.configurables is AppleConfigurables) {
"${platform.absoluteTargetToolchain}/usr/bin/$tool"
} else {
"${platform.absoluteTargetToolchain}/bin/$tool"
}
runTool(absoluteToolName, *arg)
}
private fun hostLlvmTool(tool: String, vararg arg: String) {
val absoluteToolName = "${platform.absoluteLlvmHome}/bin/$tool"
runTool(absoluteToolName, *arg)
}
private fun llvmLto(configurables: LlvmLtoFlags, file: BitcodeFile): ObjectFile {
val combined = temporary("combined", ".o")
val arguments = mutableListOf<String>().apply {
addNonEmpty(configurables.llvmLtoFlags)
addNonEmpty(llvmProfilingFlags())
when {
optimize -> addNonEmpty(configurables.llvmLtoOptFlags)
debug -> addNonEmpty(platform.llvmDebugOptFlags)
else -> addNonEmpty(configurables.llvmLtoNooptFlags)
}
addNonEmpty(configurables.llvmLtoDynamicFlags)
add(file)
// Prevent symbols from being deleted by DCE.
addNonEmpty(exportedSymbols.map { "-exported-symbol=${mangleSymbol(target, it)}"} )
}
hostLlvmTool("llvm-lto", "-o", combined, *arguments.toTypedArray())
return combined
}
private fun opt(optFlags: OptFlags, bitcodeFile: BitcodeFile): BitcodeFile {
val flags = (optFlags.optFlags + when {
optimize -> optFlags.optOptFlags
debug -> optFlags.optDebugFlags
else -> optFlags.optNooptFlags
} + llvmProfilingFlags()).toTypedArray()
val optimizedBc = temporary("opt_output", ".bc")
hostLlvmTool("opt", bitcodeFile, "-o", optimizedBc, *flags)
if (shouldRunLateBitcodePasses(context)) {
val module = parseBitcodeFile(optimizedBc)
runLateBitcodePasses(context, module)
LLVMWriteBitcodeToFile(module, optimizedBc)
}
return optimizedBc
}
private fun llc(llcFlags: LlcFlags, bitcodeFile: BitcodeFile): ObjectFile {
val flags = (llcFlags.llcFlags + when {
optimize -> llcFlags.llcOptFlags
debug -> llcFlags.llcDebugFlags
else -> llcFlags.llcNooptFlags
} + llvmProfilingFlags()).toTypedArray()
val combinedO = temporary("llc_output", ".o")
hostLlvmTool("llc", bitcodeFile, "-o", combinedO, *flags, "-filetype=obj")
return combinedO
}
private fun bitcodeToWasm(configurables: WasmConfigurables, file: BitcodeFile): String {
val optimizedBc = opt(configurables, file)
val compiled = llc(configurables, optimizedBc)
// TODO: should be moved to linker.
val linkedWasm = temporary("linked", ".wasm")
hostLlvmTool("wasm-ld", compiled, "-o", linkedWasm, *configurables.lldFlags.toTypedArray())
return linkedWasm
}
private fun optAndLlc(configurables: ZephyrConfigurables, file: BitcodeFile): String {
val optimizedBc = temporary("optimized", ".bc")
val optFlags = llvmProfilingFlags() + listOf("-O3", "-internalize", "-globaldce")
hostLlvmTool("opt", file, "-o=$optimizedBc", *optFlags.toTypedArray())
val combinedO = temporary("combined", ".o")
val llcFlags = llvmProfilingFlags() + listOf("-function-sections", "-data-sections")
hostLlvmTool("llc", optimizedBc, "-filetype=obj", "-o", combinedO, *llcFlags.toTypedArray())
return combinedO
}
private fun clang(configurables: AppleConfigurables, file: BitcodeFile): ObjectFile {
val objectFile = temporary("result", ".o")
val profilingFlags = llvmProfilingFlags().map { listOf("-mllvm", it) }.flatten()
val flags = mutableListOf<String>().apply {
addNonEmpty(configurables.clangFlags)
addNonEmpty(listOf("-triple", context.llvm.targetTriple))
addNonEmpty(when {
optimize -> configurables.clangOptFlags
debug -> configurables.clangDebugFlags
else -> configurables.clangNooptFlags
})
addNonEmpty(BitcodeEmbedding.getClangOptions(context.config))
if (determineLinkerOutput(context) == LinkerOutputKind.DYNAMIC_LIBRARY) {
addNonEmpty(configurables.clangDynamicFlags)
}
addNonEmpty(profilingFlags)
}
targetTool("clang++", *flags.toTypedArray(), file, "-o", objectFile)
return objectFile
}
// llvm-lto, opt and llc share same profiling flags, so we can
// reuse this function.
private fun llvmProfilingFlags(): List<String> {
val flags = mutableListOf<String>()
if (context.shouldProfilePhases()) {
flags += "-time-passes"
}
if (context.inVerbosePhase) {
flags += "-debug-pass=Structure"
}
return flags
}
fun makeObjectFiles(bitcodeFile: BitcodeFile): List<ObjectFile> =
listOf(when (val configurables = platform.configurables) {
is AppleConfigurables ->
clang(configurables, bitcodeFile)
is WasmConfigurables ->
bitcodeToWasm(configurables, bitcodeFile)
is ZephyrConfigurables ->
optAndLlc(configurables, bitcodeFile)
is LlvmLtoFlags ->
llvmLto(configurables, bitcodeFile)
else ->
error("Unsupported configurables kind: ${configurables::class.simpleName}!")
})
}
@@ -16,6 +16,12 @@ object BitcodeEmbedding {
Mode.FULL -> listOf("-bitcode_bundle")
}
internal fun getClangOptions(config: KonanConfig): List<String> = when (config.bitcodeEmbeddingMode) {
BitcodeEmbedding.Mode.NONE -> listOf("-fembed-bitcode=off")
BitcodeEmbedding.Mode.MARKER -> listOf("-fembed-bitcode=marker")
BitcodeEmbedding.Mode.FULL -> listOf("-fembed-bitcode=all")
}
private val KonanConfig.bitcodeEmbeddingMode get() = configuration.get(KonanConfigKeys.BITCODE_EMBEDDING_MODE)!!.also {
require(it == Mode.NONE || this.produce == CompilerOutputKind.FRAMEWORK) {
"${it.name.toLowerCase()} bitcode embedding mode is not supported when producing ${this.produce.name.toLowerCase()}"
@@ -4,16 +4,19 @@
*/
package org.jetbrains.kotlin.backend.konan
import llvm.*
import llvm.LLVMLinkModules2
import llvm.LLVMModuleRef
import llvm.LLVMWriteBitcodeToFile
import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
import org.jetbrains.kotlin.backend.konan.llvm.embedLlvmLinkOptions
import org.jetbrains.kotlin.backend.konan.llvm.parseBitcodeFile
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.isBitcode
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Family
val CompilerOutputKind.isNativeBinary: Boolean get() = when (this) {
CompilerOutputKind.PROGRAM, CompilerOutputKind.DYNAMIC,
@@ -28,20 +31,30 @@ internal fun produceCStubs(context: Context) {
}
}
private fun shouldRunBitcodePasses(context: Context): Boolean =
context.coverage.enabled
private fun linkAllDependecies(context: Context, generatedBitcodeFiles: List<String>) {
val nativeLibraries = context.config.nativeLibraries + context.config.defaultNativeLibraries
val bitcodeLibraries = context.llvm.bitcodeToLink.map { it.bitcodePaths }.flatten().filter { it.isBitcode }
val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles
val bitcodeFiles = (nativeLibraries + generatedBitcodeFiles + additionalBitcodeFilesToLink + bitcodeLibraries).toSet()
internal fun runBitcodePasses(context: Context) {
if (!shouldRunBitcodePasses(context)) {
return
}
val llvmModule = context.llvmModule!!
val passManager = LLVMCreatePassManager()!!
val targetLibraryInfo = LLVMGetTargetLibraryInfo(llvmModule)
LLVMAddTargetLibraryInfo(targetLibraryInfo, passManager)
context.coverage.addLlvmPasses(passManager)
LLVMRunPassManager(passManager, llvmModule)
LLVMDisposePassManager(passManager)
bitcodeFiles.forEach {
parseAndLinkBitcodeFile(llvmModule, it)
}
}
private fun shouldOptimizeWithLlvmApi(context: Context) =
(context.config.target.family == Family.IOS || context.config.target.family == Family.OSX)
private fun shoudRunClosedWorldCleanUp(context: Context) =
// GlobalDCE will kill coverage-related globals.
!context.coverage.enabled
private fun runLlvmPipeline(context: Context) = when {
shouldOptimizeWithLlvmApi(context) -> runLlvmOptimizationPipeline(context)
shoudRunClosedWorldCleanUp(context) -> runClosedWorldCleanup(context)
else -> {}
}
internal fun produceOutput(context: Context) {
@@ -57,7 +70,6 @@ internal fun produceOutput(context: Context) {
CompilerOutputKind.PROGRAM -> {
val output = tempFiles.nativeBinaryFileName
context.bitcodeFileName = output
val generatedBitcodeFiles =
if (produce == CompilerOutputKind.DYNAMIC || produce == CompilerOutputKind.STATIC) {
produceCAdapterBitcode(
@@ -66,20 +78,11 @@ internal fun produceOutput(context: Context) {
tempFiles.cAdapterBitcodeName)
listOf(tempFiles.cAdapterBitcodeName)
} else emptyList()
val nativeLibraries =
context.config.nativeLibraries +
context.config.defaultNativeLibraries +
generatedBitcodeFiles
for (library in nativeLibraries) {
parseAndLinkBitcodeFile(context.llvmModule!!, library)
}
if (produce == CompilerOutputKind.FRAMEWORK && context.config.produceStaticFramework) {
embedAppleLinkerOptionsToBitcode(context.llvm, context.config)
}
linkAllDependecies(context, generatedBitcodeFiles)
runLlvmPipeline(context)
LLVMWriteBitcodeToFile(context.llvmModule!!, output)
}
CompilerOutputKind.LIBRARY -> {
@@ -94,7 +97,6 @@ internal fun produceOutput(context: Context) {
val nopack = config.getBoolean(KonanConfigKeys.NOPACK)
val manifestProperties = context.config.manifestProperties
val library = buildLibrary(
context.config.nativeLibraries,
context.config.includeBinaries,
@@ -109,7 +111,6 @@ internal fun produceOutput(context: Context) {
manifestProperties,
context.dataFlowGraph)
context.library = library
context.bitcodeFileName = library.mainBitcodeFileName
}
CompilerOutputKind.BITCODE -> {
@@ -147,4 +148,4 @@ private fun embedAppleLinkerOptionsToBitcode(llvm: Llvm, config: KonanConfig) {
llvm.nativeDependenciesToLink.flatMap { findEmbeddableOptions(it.linkerOpts) }
embedLlvmLinkOptions(llvm.llvmModule, optionsToEmbed)
}
}
@@ -13,7 +13,6 @@ import org.jetbrains.kotlin.backend.common.descriptors.WrappedTypeParameterDescr
import org.jetbrains.kotlin.backend.common.validateIrModule
import org.jetbrains.kotlin.backend.konan.descriptors.*
import org.jetbrains.kotlin.backend.konan.ir.KonanIr
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryWriter
import org.jetbrains.kotlin.backend.konan.library.LinkData
import org.jetbrains.kotlin.backend.konan.llvm.*
import org.jetbrains.kotlin.backend.konan.lower.DECLARATION_ORIGIN_BRIDGE_METHOD
@@ -40,7 +39,6 @@ import org.jetbrains.kotlin.builtins.konan.KonanBuiltIns
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.descriptorUtil.module
@@ -54,6 +52,7 @@ import org.jetbrains.kotlin.backend.common.serialization.KotlinMangler
import org.jetbrains.kotlin.backend.konan.objcexport.ObjCExport
import org.jetbrains.kotlin.backend.konan.llvm.coverage.CoverageManager
import org.jetbrains.kotlin.ir.symbols.impl.IrTypeParameterSymbolImpl
import org.jetbrains.kotlin.name.FqName
/**
* Offset for synthetic elements created by lowerings and not attributable to other places in the source code.
@@ -322,7 +321,6 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
val llvmImports: LlvmImports = Llvm.ImportsImpl(this)
lateinit var llvmDeclarations: LlvmDeclarations
lateinit var bitcodeFileName: String
lateinit var library: KonanLibraryWriter
val cStubsManager = CStubsManager(config.target)
@@ -441,7 +439,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
fun shouldPrintLocations() = config.configuration.getBoolean(KonanConfigKeys.PRINT_LOCATIONS)
fun shouldProfilePhases() = config.configuration.getBoolean(KonanConfigKeys.TIME_PHASES)
fun shouldProfilePhases() = config.phaseConfig.needProfiling
fun shouldContainDebugInfo() = config.debug
@@ -469,7 +467,7 @@ internal class Context(config: KonanConfig) : KonanBackendContext(config) {
internal val stdlibModule
get() = this.builtIns.any.module
lateinit var linkStage: LinkStage
lateinit var compilerOutput: List<ObjectFile>
}
private fun MemberScope.getContributedClassifier(name: String) =
@@ -96,8 +96,6 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("target we compile for")
val TEMPORARY_FILES_DIR: CompilerConfigurationKey<String?>
= CompilerConfigurationKey.create("directory for temporary files")
val TIME_PHASES: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("time backend phases")
val VERIFY_BITCODE: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("verify bitcode")
val VERIFY_DESCRIPTORS: CompilerConfigurationKey<Boolean>
@@ -1,250 +0,0 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the LICENSE file.
*/
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
import org.jetbrains.kotlin.konan.exec.Command
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.file.isBitcode
import org.jetbrains.kotlin.konan.target.*
typealias BitcodeFile = String
typealias ObjectFile = String
typealias ExecutableFile = String
private fun determineLinkerOutput(context: Context): LinkerOutputKind =
when (context.config.produce) {
CompilerOutputKind.FRAMEWORK -> {
val staticFramework = context.config.produceStaticFramework
if (staticFramework) LinkerOutputKind.STATIC_LIBRARY else LinkerOutputKind.DYNAMIC_LIBRARY
}
CompilerOutputKind.DYNAMIC -> LinkerOutputKind.DYNAMIC_LIBRARY
CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY
CompilerOutputKind.PROGRAM -> LinkerOutputKind.EXECUTABLE
else -> TODO("${context.config.produce} should not reach native linker stage")
}
internal class LinkStage(val context: Context) {
private val config = context.config.configuration
private val target = context.config.target
private val platform = context.config.platform
private val linker = platform.linker
private val optimize = context.shouldOptimize()
private val debug = context.config.debug
private val linkerOutput = determineLinkerOutput(context)
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
private val emitted = context.bitcodeFileName
private val bitcodeLibraries = context.llvm.bitcodeToLink
private val nativeDependencies = context.llvm.nativeDependenciesToLink
private val additionalBitcodeFilesToLink = context.llvm.additionalProducedBitcodeFiles
private fun MutableList<String>.addNonEmpty(elements: List<String>) {
addAll(elements.filter { !it.isEmpty() })
}
private val exportedSymbols = context.coverage.addExportedSymbols()
private fun mangleSymbol(symbol: String) =
if (target.family == Family.IOS || target.family == Family.OSX) {
"_$symbol"
} else {
symbol
}
private fun runTool(command: List<String>) = runTool(*command.toTypedArray())
private fun runTool(vararg command: String) =
Command(*command)
.logWith(context::log)
.execute()
private fun llvmLto(files: List<BitcodeFile>): ObjectFile {
val combined = temporary("combined", ".o")
val tool = "${platform.absoluteLlvmHome}/bin/llvm-lto"
val command = mutableListOf(tool, "-o", combined)
command.addNonEmpty(platform.llvmLtoFlags)
command.addNonEmpty(llvmProfilingFlags())
when {
optimize -> command.addNonEmpty(platform.llvmLtoOptFlags)
debug -> command.addNonEmpty(platform.llvmDebugOptFlags)
else -> command.addNonEmpty(platform.llvmLtoNooptFlags)
}
command.addNonEmpty(platform.llvmLtoDynamicFlags)
command.addNonEmpty(files)
// Prevent symbols from being deleted by DCE.
command.addNonEmpty(exportedSymbols.map { "-exported-symbol=${mangleSymbol(it)}"} )
runTool(command)
return combined
}
private fun temporary(name: String, suffix: String): String =
context.config.tempFiles.create(name, suffix).absolutePath
private fun targetTool(tool: String, vararg arg: String) {
val absoluteToolName = "${platform.absoluteTargetToolchain}/bin/$tool"
runTool(absoluteToolName, *arg)
}
private fun hostLlvmTool(tool: String, vararg arg: String) {
val absoluteToolName = "${platform.absoluteLlvmHome}/bin/$tool"
runTool(absoluteToolName, *arg)
}
private fun bitcodeToWasm(bitcodeFiles: List<BitcodeFile>): String {
val configurables = platform.configurables as WasmConfigurables
val combinedBc = temporary("combined", ".bc")
// TODO: use -only-needed for the stdlib
hostLlvmTool("llvm-link", *bitcodeFiles.toTypedArray(), "-o", combinedBc)
val optFlags = (configurables.optFlags + when {
optimize -> configurables.optOptFlags
debug -> configurables.optDebugFlags
else -> configurables.optNooptFlags
} + llvmProfilingFlags()).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
} + llvmProfilingFlags()).toTypedArray()
val combinedO = temporary("combined", ".o")
hostLlvmTool("llc", optimizedBc, "-o", combinedO, *llcFlags, "-filetype=obj")
val linkedWasm = temporary("linked", ".wasm")
hostLlvmTool("wasm-ld", combinedO, "-o", linkedWasm, *configurables.lldFlags.toTypedArray())
return linkedWasm
}
private fun llvmLinkAndLlc(bitcodeFiles: List<BitcodeFile>): String {
val combinedBc = temporary("combined", ".bc")
hostLlvmTool("llvm-link", "-o", combinedBc, *bitcodeFiles.toTypedArray())
val optimizedBc = temporary("optimized", ".bc")
val optFlags = llvmProfilingFlags() + listOf("-O3", "-internalize", "-globaldce")
hostLlvmTool("opt", combinedBc, "-o=$optimizedBc", *optFlags.toTypedArray())
val combinedO = temporary("combined", ".o")
val llcFlags = llvmProfilingFlags() + listOf("-function-sections", "-data-sections")
hostLlvmTool("llc", optimizedBc, "-filetype=obj", "-o", combinedO, *llcFlags.toTypedArray())
return combinedO
}
// llvm-lto, opt and llc share same profiling flags, so we can
// reuse this function.
private fun llvmProfilingFlags(): List<String> {
val flags = mutableListOf<String>()
if (context.shouldProfilePhases()) {
flags += "-time-passes"
}
if (context.inVerbosePhase) {
flags += "-debug-pass=Structure"
}
return flags
}
private fun asLinkerArgs(args: List<String>): List<String> {
if (linker.useCompilerDriverAsLinker) {
return args
}
val result = mutableListOf<String>()
for (arg in args) {
// If user passes compiler arguments to us - transform them to linker ones.
if (arg.startsWith("-Wl,")) {
result.addAll(arg.substring(4).split(','))
} else {
result.add(arg)
}
}
return result
}
// Ideally we'd want to have
// #pragma weak main = Konan_main
// in the launcher.cpp.
// Unfortunately, anything related to weak linking on MacOS
// only seems to be working with dynamic libraries.
// 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 || linkerOutput != LinkerOutputKind.EXECUTABLE) emptyList() else platform.entrySelector
private fun link(objectFiles: List<ObjectFile>,
includedBinaries: List<String>,
libraryProvidedLinkerFlags: List<String>): ExecutableFile? {
val frameworkLinkerArgs: List<String>
val executable: String
if (context.config.produce != CompilerOutputKind.FRAMEWORK) {
frameworkLinkerArgs = emptyList()
executable = context.config.outputFile
} else {
val framework = File(context.config.outputFile)
val dylibName = framework.name.removeSuffix(".framework")
val dylibRelativePath = when (target.family) {
Family.IOS -> dylibName
Family.OSX -> "Versions/A/$dylibName"
else -> error(target)
}
frameworkLinkerArgs = listOf("-install_name", "@rpath/${framework.name}/$dylibRelativePath")
val dylibPath = framework.child(dylibRelativePath)
dylibPath.parentFile.mkdirs()
executable = dylibPath.absolutePath
}
try {
File(executable).delete()
linker.linkCommands(objectFiles = objectFiles, executable = executable,
libraries = linker.linkStaticLibraries(includedBinaries) + context.config.defaultSystemLibraries,
linkerArgs = entryPointSelector +
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
BitcodeEmbedding.getLinkerOptions(context.config) +
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")
}
return executable
}
val objectFiles = mutableListOf<String>()
fun makeObjectFiles() {
val bitcodeFiles = listOf(emitted) + additionalBitcodeFilesToLink +
bitcodeLibraries.map { it.bitcodePaths }.flatten().filter { it.isBitcode }
objectFiles.add(when (platform.configurables) {
is WasmConfigurables
-> bitcodeToWasm(bitcodeFiles)
is ZephyrConfigurables
-> llvmLinkAndLlc(bitcodeFiles)
else
-> llvmLto(bitcodeFiles)
})
}
fun linkStage() {
val includedBinaries =
nativeDependencies.map { it.includedPaths }.flatten()
val libraryProvidedLinkerFlags =
nativeDependencies.map { it.linkerOpts }.flatten()
link(objectFiles, includedBinaries, libraryProvidedLinkerFlags)
}
}
@@ -0,0 +1,109 @@
package org.jetbrains.kotlin.backend.konan
import org.jetbrains.kotlin.konan.KonanExternalToolFailure
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Family
import org.jetbrains.kotlin.konan.target.LinkerOutputKind
internal fun determineLinkerOutput(context: Context): LinkerOutputKind =
when (context.config.produce) {
CompilerOutputKind.FRAMEWORK -> {
val staticFramework = context.config.produceStaticFramework
if (staticFramework) LinkerOutputKind.STATIC_LIBRARY else LinkerOutputKind.DYNAMIC_LIBRARY
}
CompilerOutputKind.DYNAMIC -> LinkerOutputKind.DYNAMIC_LIBRARY
CompilerOutputKind.STATIC -> LinkerOutputKind.STATIC_LIBRARY
CompilerOutputKind.PROGRAM -> LinkerOutputKind.EXECUTABLE
else -> TODO("${context.config.produce} should not reach native linker stage")
}
// TODO: We have a Linker.kt file in the shared module.
internal class Linker(val context: Context) {
private val platform = context.config.platform
private val config = context.config.configuration
private val linkerOutput = determineLinkerOutput(context)
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
private val linker = platform.linker
private val target = context.config.target
private val optimize = context.shouldOptimize()
private val debug = context.config.debug
// Ideally we'd want to have
// #pragma weak main = Konan_main
// in the launcher.cpp.
// Unfortunately, anything related to weak linking on MacOS
// only seems to be working with dynamic libraries.
// 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 || linkerOutput != LinkerOutputKind.EXECUTABLE) emptyList() else platform.entrySelector
fun link(objectFiles: List<ObjectFile>) {
val nativeDependencies = context.llvm.nativeDependenciesToLink
val includedBinaries = nativeDependencies.map { it.includedPaths }.flatten()
val libraryProvidedLinkerFlags = nativeDependencies.map { it.linkerOpts }.flatten()
runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags)
}
private fun asLinkerArgs(args: List<String>): List<String> {
if (linker.useCompilerDriverAsLinker) {
return args
}
val result = mutableListOf<String>()
for (arg in args) {
// If user passes compiler arguments to us - transform them to linker ones.
if (arg.startsWith("-Wl,")) {
result.addAll(arg.substring(4).split(','))
} else {
result.add(arg)
}
}
return result
}
private fun runLinker(objectFiles: List<ObjectFile>,
includedBinaries: List<String>,
libraryProvidedLinkerFlags: List<String>): ExecutableFile? {
val frameworkLinkerArgs: List<String>
val executable: String
if (context.config.produce != CompilerOutputKind.FRAMEWORK) {
frameworkLinkerArgs = emptyList()
executable = context.config.outputFile
} else {
val framework = File(context.config.outputFile)
val dylibName = framework.name.removeSuffix(".framework")
val dylibRelativePath = when (target.family) {
Family.IOS -> dylibName
Family.OSX -> "Versions/A/$dylibName"
else -> error(target)
}
frameworkLinkerArgs = listOf("-install_name", "@rpath/${framework.name}/$dylibRelativePath")
val dylibPath = framework.child(dylibRelativePath)
dylibPath.parentFile.mkdirs()
executable = dylibPath.absolutePath
}
try {
File(executable).delete()
linker.linkCommands(objectFiles = objectFiles, executable = executable,
libraries = linker.linkStaticLibraries(includedBinaries) + context.config.defaultSystemLibraries,
linkerArgs = entryPointSelector +
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
BitcodeEmbedding.getLinkerOptions(context.config) +
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")
}
return executable
}
}
@@ -0,0 +1,146 @@
package org.jetbrains.kotlin.backend.konan
import kotlinx.cinterop.alloc
import kotlinx.cinterop.memScoped
import kotlinx.cinterop.ptr
import kotlinx.cinterop.value
import llvm.*
import org.jetbrains.kotlin.konan.target.KonanTarget
private fun initializeLlvmGlobalPassRegistry() {
val passRegistry = LLVMGetGlobalPassRegistry()
LLVMInitializeCore(passRegistry)
LLVMInitializeTransformUtils(passRegistry)
LLVMInitializeScalarOpts(passRegistry)
LLVMInitializeVectorization(passRegistry)
LLVMInitializeInstCombine(passRegistry)
LLVMInitializeIPO(passRegistry)
LLVMInitializeInstrumentation(passRegistry)
LLVMInitializeAnalysis(passRegistry)
LLVMInitializeIPA(passRegistry)
LLVMInitializeCodeGen(passRegistry)
LLVMInitializeTarget(passRegistry)
}
internal fun shouldRunLateBitcodePasses(context: Context): Boolean {
return context.coverage.enabled
}
internal fun runLateBitcodePasses(context: Context, llvmModule: LLVMModuleRef) {
val passManager = LLVMCreatePassManager()!!
val targetLibraryInfo = LLVMGetTargetLibraryInfo(llvmModule)
LLVMAddTargetLibraryInfo(targetLibraryInfo, passManager)
context.coverage.addLateLlvmPasses(passManager)
LLVMRunPassManager(passManager, llvmModule)
LLVMDisposePassManager(passManager)
}
private class LlvmPipelineConfiguration(context: Context) {
private val target = context.config.target
val targetTriple: String = context.llvm.targetTriple
val cpuArchitecture: String = when (target) {
KonanTarget.IOS_ARM32 -> "armv7"
KonanTarget.IOS_ARM64 -> "arm64"
KonanTarget.MACOS_X64 -> "core2"
else -> error("There is no support for ${target.name} target yet.")
}
val cpuFeatures: String = ""
val customInlineThreshold: Int? = when {
context.shouldOptimize() -> 100
context.shouldContainDebugInfo() -> null
else -> null
}
val optimizationLevel: Int = when {
context.shouldOptimize() -> 3
context.shouldContainDebugInfo() -> 0
else -> 1
}
val sizeLevel: Int = when {
context.shouldOptimize() -> 0
context.shouldContainDebugInfo() -> 0
else -> 0
}
val codegenOptimizationLevel: LLVMCodeGenOptLevel = when {
context.shouldOptimize() -> LLVMCodeGenOptLevel.LLVMCodeGenLevelAggressive
context.shouldContainDebugInfo() -> LLVMCodeGenOptLevel.LLVMCodeGenLevelNone
else -> LLVMCodeGenOptLevel.LLVMCodeGenLevelDefault
}
val relocMode: LLVMRelocMode = LLVMRelocMode.LLVMRelocDefault
val codeModel: LLVMCodeModel = LLVMCodeModel.LLVMCodeModelDefault
}
// Since we are in a "closed world" internalization and global dce
// can be safely used to reduce size of a bitcode.
internal fun runClosedWorldCleanup(context: Context) {
initializeLlvmGlobalPassRegistry()
val llvmModule = context.llvmModule!!
val modulePasses = LLVMCreatePassManager()
LLVMAddInternalizePass(modulePasses, 0)
LLVMAddGlobalDCEPass(modulePasses)
LLVMRunPassManager(modulePasses, llvmModule)
LLVMDisposePassManager(modulePasses)
}
internal fun runLlvmOptimizationPipeline(context: Context) {
val llvmModule = context.llvmModule!!
val config = LlvmPipelineConfiguration(context)
memScoped {
LLVMKotlinInitializeTargets()
initializeLlvmGlobalPassRegistry()
val passBuilder = LLVMPassManagerBuilderCreate()
val modulePasses = LLVMCreatePassManager()
LLVMPassManagerBuilderSetOptLevel(passBuilder, config.optimizationLevel)
LLVMPassManagerBuilderSetSizeLevel(passBuilder, config.sizeLevel)
// TODO: use LLVMGetTargetFromName instead.
val target = alloc<LLVMTargetRefVar>()
val foundLlvmTarget = LLVMGetTargetFromTriple(config.targetTriple, target.ptr, null) == 0
check(foundLlvmTarget) { "Cannot get target from triple ${config.targetTriple}." }
val targetMachine = LLVMCreateTargetMachine(
target.value,
config.targetTriple,
config.cpuArchitecture,
config.cpuFeatures,
config.codegenOptimizationLevel,
config.relocMode,
config.codeModel)
val targetLibraryInfo = LLVMGetTargetLibraryInfo(llvmModule)
LLVMAddTargetLibraryInfo(targetLibraryInfo, modulePasses)
// TargetTransformInfo pass.
LLVMAddAnalysisPasses(targetMachine, modulePasses)
// Since we are in a "closed world" internalization and global dce
// can be safely used to reduce size of a bitcode.
LLVMAddInternalizePass(modulePasses, 0)
LLVMAddGlobalDCEPass(modulePasses)
config.customInlineThreshold?.let { threshold ->
LLVMPassManagerBuilderUseInlinerWithThreshold(passBuilder, threshold)
}
// Pipeline that is similar to `llvm-lto`.
// TODO: Add ObjC optimization passes.
LLVMPassManagerBuilderPopulateLTOPassManager(passBuilder, modulePasses, Internalize = 0, RunInliner = 1)
LLVMPassManagerBuilderDispose(passBuilder)
LLVMRunPassManager(modulePasses, llvmModule)
LLVMDisposeTargetMachine(targetMachine)
LLVMDisposePassManager(modulePasses)
}
if (shouldRunLateBitcodePasses(context)) {
runLateBitcodePasses(context, llvmModule)
}
}
@@ -1,9 +1,9 @@
package org.jetbrains.kotlin.backend.konan
import llvm.LLVMWriteBitcodeToFile
import org.jetbrains.kotlin.backend.common.LoggingContext
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.phaser.*
import org.jetbrains.kotlin.backend.common.serialization.DeserializationStrategy
import org.jetbrains.kotlin.backend.konan.descriptors.isForwardDeclarationModule
import org.jetbrains.kotlin.backend.konan.descriptors.konanLibrary
import org.jetbrains.kotlin.backend.konan.ir.KonanSymbols
@@ -15,10 +15,15 @@ import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.languageVersionSettings
import org.jetbrains.kotlin.backend.common.serialization.DescriptorTable
import org.jetbrains.kotlin.backend.konan.library.impl.buildLibrary
import org.jetbrains.kotlin.ir.declarations.IrFile
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.util.SymbolTable
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
import org.jetbrains.kotlin.konan.CURRENT
import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.library.KonanLibraryVersioning
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.psi2ir.Psi2IrConfiguration
import org.jetbrains.kotlin.psi2ir.Psi2IrTranslator
@@ -185,20 +190,14 @@ internal val serializerPhase = konanUnitPhase(
description = "Serialize descriptor tree and inline IR bodies"
)
internal val setUpLinkStagePhase = konanUnitPhase(
op = { linkStage = LinkStage(this) },
name = "SetUpLinkStage",
description = "Set up link stage"
)
internal val objectFilesPhase = konanUnitPhase(
op = { linkStage.makeObjectFiles() },
op = { compilerOutput = BitcodeCompiler(this).makeObjectFiles(bitcodeFileName) },
name = "ObjectFiles",
description = "Bitcode to object file"
)
internal val linkerPhase = konanUnitPhase(
op = { linkStage.linkStage() },
op = { Linker(this).link(compilerOutput) },
name = "Linker",
description = "Linker"
)
@@ -206,8 +205,7 @@ internal val linkerPhase = konanUnitPhase(
internal val linkPhase = namedUnitPhase(
name = "Link",
description = "Link stage",
lower = setUpLinkStagePhase then
objectFilesPhase then
lower = objectFilesPhase then
linkerPhase
)
@@ -304,7 +302,6 @@ internal val bitcodePhase = namedIrModulePhase(
escapeAnalysisPhase then
codegenPhase then
finalizeDebugInfoPhase then
bitcodePassesPhase then
cStubsPhase
)
@@ -330,9 +327,9 @@ val toplevelPhase: CompilerPhase<*, Unit, Unit> = namedUnitPhase(
dependenciesLowerPhase then // Then lower all libraries in topological order.
// With that we guarantee that inline functions are unlowered while being inlined.
bitcodePhase then
produceOutputPhase then
verifyBitcodePhase then
printBitcodePhase then
produceOutputPhase then
unitSink()
) then
linkPhase
@@ -124,16 +124,6 @@ internal val cStubsPhase = makeKonanModuleOpPhase(
op = { context, _ -> produceCStubs(context) }
)
/**
* Runs specific passes over context.llvmModule. The main compilation pipeline
* is performed by [linkPhase].
*/
internal val bitcodePassesPhase = makeKonanModuleOpPhase(
name = "BitcodePasses",
description = "Run custom LLVM passes over bitcode",
op = { context, _ -> runBitcodePasses(context) }
)
internal val produceOutputPhase = makeKonanModuleOpPhase(
name = "ProduceOutput",
description = "Produce output",
@@ -409,9 +409,11 @@ internal class Llvm(val context: Context, val llvmModule: LLVMModuleRef) {
val runtimeFile = context.config.distribution.runtime(target)
val runtime = Runtime(runtimeFile) // TODO: dispose
val targetTriple = runtime.target
init {
LLVMSetDataLayout(llvmModule, runtime.dataLayout)
LLVMSetTarget(llvmModule, runtime.target)
LLVMSetTarget(llvmModule, targetTriple)
}
private fun importRtFunction(name: String) = importFunction(name, runtime.llvmModule)
@@ -318,7 +318,6 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
codegen.objCDataGenerator?.finishModule()
BitcodeEmbedding.processModule(context.llvm)
context.coverage.writeRegionInfo()
appendDebugSelector()
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
@@ -4,12 +4,9 @@
*/
package org.jetbrains.kotlin.backend.konan.llvm.coverage
import llvm.LLVMAddInstrProfPass
import llvm.LLVMPassManagerRef
import llvm.LLVMValueRef
import llvm.*
import org.jetbrains.kotlin.backend.konan.*
import org.jetbrains.kotlin.backend.konan.Context
import org.jetbrains.kotlin.backend.konan.KonanConfigKeys
import org.jetbrains.kotlin.backend.konan.isNativeBinary
import org.jetbrains.kotlin.backend.konan.reportCompilationError
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
import org.jetbrains.kotlin.ir.declarations.IrFile
@@ -106,10 +103,11 @@ internal class CoverageManager(val context: Context) {
}
/**
* Add InstrProfilingLegacyPass to the list of llvm passes
* Add passes that should be executed after main LLVM optimization pipeline.
*/
fun addLlvmPasses(passManager: LLVMPassManagerRef) {
fun addLateLlvmPasses(passManager: LLVMPassManagerRef) {
if (enabled) {
// It's a late pass since DCE can kill __llvm_profile_filename global.
LLVMAddInstrProfPass(passManager, outputFileName)
}
}
+15 -13
View File
@@ -1,7 +1,9 @@
headers = llvm-c/Core.h llvm-c/Target.h llvm-c/Analysis.h llvm-c/BitWriter.h \
llvm-c/BitReader.h llvm-c/Linker.h DebugInfoC.h CoverageMappingC.h
llvm-c/BitReader.h llvm-c/Transforms/PassManagerBuilder.h llvm-c/Transforms/IPO.h \
llvm-c/TargetMachine.h llvm-c/Target.h llvm-c/Linker.h llvm-c/Initialization.h \
DebugInfoC.h CoverageMappingC.h
headerFilter = llvm-c/* DebugInfoC.h CoverageMappingC.h
headerFilter = llvm-c/* llvm-c/**/* DebugInfoC.h CoverageMappingC.h
compilerOpts = -std=c99 \
-Wall -W -Wno-unused-parameter -Wwrite-strings -Wmissing-field-initializers \
@@ -16,25 +18,25 @@ linkerOpts = -fvisibility-inlines-hidden \
-pedantic -Wno-long-long -Wcovered-switch-default -Wnon-virtual-dtor -Wdelete-non-virtual-dtor \
-std=c++11 \
-DNDEBUG -D__STDC_CONSTANT_MACROS -D__STDC_FORMAT_MACROS -D__STDC_LIMIT_MACROS \
-ldebugInfo -lcoverageMapping -lLLVMCoverage -lLLVMTarget -lLLVMInstrumentation \
-lLLVMMC -lLLVMLinker -lLLVMTransformUtils -lLLVMBitWriter \
-lLLVMBitReader -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMMCParser -lLLVMMC \
-lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle
# ./llvm-config --libs analysis bitreader bitwriter core linker target coverage
-ldebugInfo -lcoverageMapping
# ./llvm-config --libs analysis bitreader bitwriter core linker target coverage analysis ipo instrumentation lto objcarcopts arm aarch64 webassembly x86 mips
linkerOpts.osx = -fPIC \
-Wl,-search_paths_first -Wl,-headerpad_max_install_names \
-lpthread -lz -lm -lcurses -Wl,-U,_futimens -Wl,-U,_LLVMDumpType
-lpthread -lz -lm -lcurses -Wl,-U,_futimens -Wl,-U,_LLVMDumpType \
-lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMIRReader -lLLVMAsmParser -lLLVMMipsDisassembler -lLLVMMipsCodeGen -lLLVMMipsAsmParser -lLLVMMipsDesc -lLLVMMipsInfo -lLLVMMipsAsmPrinter -lLLVMX86Disassembler -lLLVMX86AsmParser -lLLVMX86CodeGen -lLLVMX86Desc -lLLVMX86Info -lLLVMX86AsmPrinter -lLLVMX86Utils -lLLVMWebAssemblyDisassembler -lLLVMWebAssemblyCodeGen -lLLVMWebAssemblyDesc -lLLVMWebAssemblyInfo -lLLVMWebAssemblyAsmPrinter -lLLVMAArch64Disassembler -lLLVMAArch64CodeGen -lLLVMAArch64AsmParser -lLLVMAArch64Desc -lLLVMAArch64Info -lLLVMAArch64AsmPrinter -lLLVMAArch64Utils -lLLVMARMDisassembler -lLLVMARMCodeGen -lLLVMGlobalISel -lLLVMSelectionDAG -lLLVMAsmPrinter -lLLVMDebugInfoCodeView -lLLVMDebugInfoMSF -lLLVMCodeGen -lLLVMScalarOpts -lLLVMInstCombine -lLLVMARMAsmParser -lLLVMARMDesc -lLLVMMCDisassembler -lLLVMARMInfo -lLLVMARMAsmPrinter -lLLVMARMUtils -lLLVMCoverage -lLLVMTarget -lLLVMLinker -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMMCParser -lLLVMMC -lLLVMBitReader -lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle
linkerOpts.linux= -fPIC \
# ./llvm-config --libs analysis bitreader bitwriter core linker target coverage analysis ipo instrumentation lto
linkerOpts.linux= -lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts -lLLVMCodeGen -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMScalarOpts -lLLVMIRReader -lLLVMAsmParser -lLLVMInstCombine -lLLVMCoverage -lLLVMTarget -lLLVMLinker -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMMCParser -lLLVMMC -lLLVMBitReader -lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle \
-fPIC \
-Wl,-z,noexecstack \
-lrt -ldl -lpthread -lz -lm
linkerOpts.mingw = -lole32 -luuid -static-libgcc -static-libstdc++ \
# ./llvm-config --libs analysis bitreader bitwriter core linker target coverage analysis ipo instrumentation lto
linkerOpts.mingw = -lLLVMLTO -lLLVMPasses -lLLVMObjCARCOpts -lLLVMCodeGen -lLLVMipo -lLLVMInstrumentation -lLLVMVectorize -lLLVMScalarOpts -lLLVMIRReader -lLLVMAsmParser -lLLVMInstCombine -lLLVMCoverage -lLLVMTarget -lLLVMLinker -lLLVMTransformUtils -lLLVMBitWriter -lLLVMAnalysis -lLLVMProfileData -lLLVMObject -lLLVMMCParser -lLLVMMC -lLLVMBitReader -lLLVMCore -lLLVMBinaryFormat -lLLVMSupport -lLLVMDemangle \
-lole32 -luuid -static-libgcc -static-libstdc++ \
-Wl,-Bstatic -lz \
-Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic
-Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic \
# It looks like mingw port compiled without LLVM_ENABLE_DUMP
#Note: ld on mingw process -Wl,-U,_LLVMDumpType use different from other platform
@@ -3,11 +3,8 @@ package org.jetbrains.kotlin
import groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.DefaultTask
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.tasks.Input
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.SourceSetContainer
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.konan.target.*
@@ -55,9 +52,11 @@ open class FrameworkTest : DefaultTask() {
@TaskAction
fun run() {
val frameworkPath = "$testOutput/$frameworkName/${project.testTarget().name}"
codesign(project, Paths.get(frameworkPath, "$frameworkName.framework").toString())
val frameworkParentDirPath = "$testOutput/$frameworkName/${project.testTarget().name}"
val frameworkPath = "$frameworkParentDirPath/$frameworkName.framework"
val frameworkBinaryPath = "$frameworkPath/$frameworkName"
validateBitcodeEmbedding(frameworkBinaryPath)
codesign(project, frameworkPath)
// create a test provider and get main entry point
val provider = Paths.get(testOutput, frameworkName, "provider.swift")
@@ -77,7 +76,7 @@ open class FrameworkTest : DefaultTask() {
// Compile swift sources
val sources = swiftSources.map { Paths.get(it).toString() } +
listOf(provider.toString(), swiftMain)
val options = listOf("-g", "-Xlinker", "-rpath", "-Xlinker", frameworkPath, "-F", frameworkPath)
val options = listOf("-g", "-Xlinker", "-rpath", "-Xlinker", frameworkParentDirPath, "-F", frameworkParentDirPath)
val testExecutable = Paths.get(testOutput, frameworkName, "swiftTestExecutable")
swiftc(sources, options, testExecutable)
@@ -139,4 +138,32 @@ open class FrameworkTest : DefaultTask() {
check(exitCode == 0, { "Compilation failed" })
check(output.toFile().exists(), { "Compiler swiftc hasn't produced an output file: $output" })
}
}
private fun validateBitcodeEmbedding(frameworkBinary: String) {
// Check only the full bitcode embedding for now.
if (!fullBitcode) {
return
}
val testTarget = project.testTarget()
val configurables = project.platformManager().platform(testTarget).configurables as AppleConfigurables
val bitcodeBuildTool = "${configurables.absoluteAdditionalToolsDir}/bin/bitcode-build-tool"
val ldPath = "${configurables.absoluteTargetToolchain}/usr/bin/ld"
val sdk = when (testTarget) {
KonanTarget.IOS_X64 -> Xcode.current.iphonesimulatorSdk
KonanTarget.IOS_ARM64, KonanTarget.IOS_ARM32 -> Xcode.current.iphoneosSdk
KonanTarget.MACOS_X64 -> Xcode.current.macosxSdk
else -> error("Cannot validate bitcode for test target $testTarget")
}
val args = listOf("--sdk", sdk, "-v", "-t", ldPath, frameworkBinary)
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = bitcodeBuildTool, args = args)
check(exitCode == 0) {
"""
|bitcode-build-tool failed:
|stdout: $stdOut
|stderr: $stdErr
""".trimMargin()
}
}
}
+3 -2
View File
@@ -23,8 +23,9 @@ kotlinVersion=1.3.40-dev-2423
testKotlinVersion=1.3.40-dev-2423
# See https://teamcity.jetbrains.com/project.html?projectId=Kotlin_KotlinNativeShared&tab=projectOverview
sharedRepo=https://dl.bintray.com/jetbrains/kotlin-native-dependencies
sharedVersion=1.0-dev-50
sharedVersion=1.0-dev-57
konanVersion=1.3.0
org.gradle.jvmargs='-Dfile.encoding=UTF-8'
org.gradle.workers.max=4
#kotlinProjectPath=/Users/jetbrains/kotlin-native/kotlin
#kotlinProjectPath=/Users/jetbrains/IdeaProjects/kotlin
#sharedProjectPath=/Users/jetbrains/IdeaProjects/kotlin-native-shared
+38 -20
View File
@@ -39,24 +39,30 @@ llvmVersion = 6.0.1
llvmHome.macos_x64 = clang-llvm-6.0.1-darwin-macos
targetToolchain.macos_x64 = target-toolchain-9-macos_x64
libffiDir.macos_x64 = libffi-3.2.1-3-darwin-macos
additionalToolsDir.macos_x64 = xcode-addon-9-macos_x64
arch.macos_x64 = x86_64
targetSysRoot.macos_x64 = target-sysroot-9-macos_x64
llvmLtoFlags.macos_x64 =
llvmLtoOptFlags.macos_x64 = -O3 -function-sections
llvmLtoNooptFlags.macos_x64 = -O1
llvmLtoDynamicFlags.macos_x64 = -relocation-model=pic
clangFlags.macos_x64 = -cc1 -emit-obj -disable-llvm-passes -x ir
clangNooptFlags.macos_x64 = -O1
clangOptFlags.macos_x64 = -O3
clangDebugFlags.macos_x64 = -O0
clangDynamicFlags.macos_x64 =
linkerKonanFlags.macos_x64 = -lSystem -lc++ -lobjc -framework Foundation
linkerOptimizationFlags.macos_x64 = -dead_strip
linkerNoDebugFlags.macos_x64 = -S
linkerDynamicFlags.macos_x64 = -dylib
osVersionMinFlagLd.macos_x64 = -macosx_version_min
osVersionMinFlagClang.macos_x64 = -mmacosx-version-min
osVersionMin.macos_x64 = 10.11
entrySelector.macos_x64 = -alias _Konan_main _main
dependencies.macos_x64 = \
libffi-3.2.1-3-darwin-macos \
clang-llvm-6.0.1-darwin-macos
clang-llvm-6.0.1-darwin-macos \
xcode-addon-9-macos_x64
target-sysroot-9-macos_x64.default = \
remote:internal
@@ -64,6 +70,10 @@ target-sysroot-9-macos_x64.default = \
target-toolchain-9-macos_x64.default = \
remote:internal
xcode-addon-9-macos_x64.default = \
remote:internal
# Apple's 32-bit iOS.
targetToolchain.macos_x64-ios_arm32 = target-toolchain-9-macos_x64
dependencies.macos_x64-ios_arm32 = \
@@ -77,13 +87,15 @@ arch.ios_arm32 = armv7
entrySelector.ios_arm32 = -alias _Konan_main _main
# Shared with 64-bit version.
targetSysRoot.ios_arm32 = target-sysroot-9-ios_arm64
llvmLtoFlags.ios_arm32 =
llvmLtoOptFlags.ios_arm32 = -O3 -function-sections
clangFlags.ios_arm32 = -cc1 -emit-obj -disable-llvm-optzns -x ir
clangNooptFlags.ios_arm32 = -O1
clangOptFlags.ios_arm32 = -O3
clangDebugFlags.ios_arm32 = -O0
clangDynamicFlags.ios_arm32 =
linkerNoDebugFlags.ios_arm32 = -S
linkerDynamicFlags.ios_arm32 = -dylib
llvmLtoNooptFlags.ios_arm32 = -O1
llvmLtoDynamicFlags.ios_arm32 = -relocation-model=pic
linkerKonanFlags.ios_arm32 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 12.2
linkerKonanFlags.ios_arm32 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 11.2
linkerOptimizationFlags.ios_arm32 = -dead_strip
osVersionMinFlagLd.ios_arm32 = -iphoneos_version_min
osVersionMinFlagClang.ios_arm32 = -miphoneos-version-min
@@ -101,13 +113,16 @@ target-sysroot-9-ios_arm64.default = \
arch.ios_arm64 = arm64
entrySelector.ios_arm64 = -alias _Konan_main _main
targetSysRoot.ios_arm64 = target-sysroot-9-ios_arm64
llvmLtoFlags.ios_arm64 =
llvmLtoOptFlags.ios_arm64 = -O3 -function-sections
clangFlags.ios_arm64 = -cc1 -emit-obj -disable-llvm-passes -x ir
clangNooptFlags.ios_arm64 = -O1
clangOptFlags.ios_arm64 = -O3
clangDebugFlags.ios_arm64 = -O0
clangDynamicFlags.ios_arm64 =
linkerNoDebugFlags.ios_arm64 = -S
linkerDynamicFlags.ios_arm64 = -dylib
llvmLtoNooptFlags.ios_arm64 = -O1
llvmLtoDynamicFlags.ios_arm64 = -relocation-model=pic
linkerKonanFlags.ios_arm64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 12.2
linkerKonanFlags.ios_arm64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 11.2
linkerOptimizationFlags.ios_arm64 = -dead_strip
osVersionMinFlagLd.ios_arm64 = -iphoneos_version_min
osVersionMinFlagClang.ios_arm64 = -miphoneos-version-min
@@ -125,11 +140,14 @@ target-sysroot-9-ios_x64.default = \
arch.ios_x64 = x86_64
entrySelector.ios_x64 = -alias _Konan_main _main
targetSysRoot.ios_x64 = target-sysroot-9-ios_x64
llvmLtoFlags.ios_x64 =
llvmLtoOptFlags.ios_x64 = -O3 -function-sections
llvmLtoNooptFlags.ios_x64 = -O1
llvmLtoDynamicFlags.ios_x64 = -relocation-model=pic
linkerKonanFlags.ios_x64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 12.2
clangFlags.ios_x64 = -cc1 -emit-obj -disable-llvm-passes -x ir
clangNooptFlags.ios_x64 = -O1
clangOptFlags.ios_x64 = -O3
clangDebugFlags.ios_x64 = -O0
clangDynamicFlags.ios_x64 =
linkerKonanFlags.ios_x64 = -lSystem -lc++ -lobjc -framework Foundation -sdk_version 11.2
linkerOptimizationFlags.ios_x64 = -dead_strip
linkerNoDebugFlags.ios_x64 = -S
linkerDynamicFlags.ios_x64 = -dylib
+9
View File
@@ -30,6 +30,15 @@ model {
if (!project.parent.convention.plugins.platformInfo.isWindows())
cppCompiler.args "-fPIC"
cppCompiler.args "--std=c++11", "-I${llvmDir}/include", "-I${projectDir}/src/main/include"
if (isMac()) {
cppCompiler.args "-DKONAN_MACOS=1"
} else if (isWindows()) {
cppCompiler.args "-DKONAN_WINDOWS=1"
} else if (isLinux()) {
cppCompiler.args "-DKONAN_LINUX=1"
} else {
throw new Error("Unsupported host OS.")
}
linker.args "-L${llvmDir}/lib", "-lLLVMCore", "-lLLVMSupport"
}
binaries.withType(SharedLibraryBinarySpec) { binary ->
@@ -227,4 +227,22 @@ void LLVMAddInstrProfPass(LLVMPassManagerRef passManagerRef, const char* outputF
LLVMTargetLibraryInfoRef LLVMGetTargetLibraryInfo(LLVMModuleRef moduleRef) {
auto* libraryInfo = new TargetLibraryInfoImpl(Triple(unwrap(moduleRef)->getTargetTriple()));
return llvm::wrap(libraryInfo);
}
void LLVMKotlinInitializeTargets() {
#define INIT_LLVM_TARGET(TargetName) \
LLVMInitialize##TargetName##TargetInfo();\
LLVMInitialize##TargetName##Target();\
LLVMInitialize##TargetName##TargetMC();
#if KONAN_MACOS
INIT_LLVM_TARGET(AArch64)
INIT_LLVM_TARGET(ARM)
INIT_LLVM_TARGET(Mips)
INIT_LLVM_TARGET(X86)
INIT_LLVM_TARGET(WebAssembly)
#elif KONAN_LINUX
#elif KONAN_WINDOWS
#endif
#undef INIT_LLVM_TARGET
}
@@ -74,8 +74,9 @@ void LLVMAddInstrProfPass(LLVMPassManagerRef passManagerRef, const char* outputF
LLVMTargetLibraryInfoRef LLVMGetTargetLibraryInfo(LLVMModuleRef moduleRef);
void LLVMKotlinInitializeTargets();
# ifdef __cplusplus
}
# endif
#endif
+8
View File
@@ -9,6 +9,7 @@ TARBALL_iphonesimulator=target-sysroot-$KONAN_TOOLCHAIN_VERSION-ios_x64
TARBALL_watchos=target-sysroot-$KONAN_TOOLCHAIN_VERSION-watchos_arm32
TARBALL_watchsimulator=target-sysroot-$KONAN_TOOLCHAIN_VERSION-watchos_x64
TARBALL_xcode=target-toolchain-$KONAN_TOOLCHAIN_VERSION-macos_x64
TARBALL_xcode_addon=xcode-addon-$KONAN_TOOLCHAIN_VERSION-macos_x64
OUT=`pwd`
for s in $SDKS; do
@@ -26,3 +27,10 @@ t=`grealpath $t/../..`
tarball=$TARBALL_xcode
echo "Packing toolchain $OUT/$tarball.tar.gz..."
$SHELL -c "tar czf $OUT/$tarball.tar.gz -C $t -s '/^\./$tarball/' ."
t=`xcrun -f bitcode-build-tool`
t=`dirname $t`
t=`grealpath $t/..`
tarball=$TARBALL_xcode_addon
echo "Packing additional tools $OUT/$tarball.tar.gz..."
$SHELL -c "tar czf $OUT/$tarball.tar.gz -C $t -s '/^\./$tarball/' ."