From f564bd7707e7a83877f63aecf2d14fd35964e8f8 Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Wed, 29 Mar 2017 17:46:26 +0300 Subject: [PATCH] Always link bitcode files specified with `-nativelibrary` --- backend.native/build.gradle | 3 ++- .../cli/bc/K2NativeCompilerArguments.java | 2 +- .../kotlin/backend/konan/KonanConfig.kt | 3 +-- .../kotlin/backend/konan/KonanPhases.kt | 1 + .../kotlin/backend/konan/LinkStage.kt | 2 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 10 +++++++ .../kotlin/backend/konan/llvm/LlvmUtils.kt | 26 ++++++++++++++++++- .../kotlin/backend/konan/llvm/Runtime.kt | 25 ++---------------- backend.native/llvm.def | 3 ++- 9 files changed, 45 insertions(+), 30 deletions(-) diff --git a/backend.native/build.gradle b/backend.native/build.gradle index bb6aaa2efb4..a55f1f6496d 100644 --- a/backend.native/build.gradle +++ b/backend.native/build.gradle @@ -127,7 +127,8 @@ List llvmLinkerOpts() { '-lLLVMMC', '-lLLVMCore', '-lLLVMSupport', - '-lLLVMDebugInfoCodeView' + '-lLLVMDebugInfoCodeView', + '-lLLVMLinker' ] final List res = new ArrayList<>() diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java index b6a6d6dde6c..56c5645991a 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.java @@ -37,7 +37,7 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments { @ValueDescription("") public String[] libraries; - @Argument(value = "nativelibrary", alias = "nl", description = "Link with the native library") + @Argument(value = "nativelibrary", alias = "nl", description = "Include the native library") @ValueDescription("") public String[] nativeLibraries; diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index e5970a2f983..989da4ce011 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -39,8 +39,7 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration private val loadedDescriptors = loadLibMetadata(libraries) - internal val librariesToLink: List - get() = libraries + configuration.getList(KonanConfigKeys.NATIVE_LIBRARY_FILES) + internal val nativeLibraries: List = configuration.getList(KonanConfigKeys.NATIVE_LIBRARY_FILES) val moduleId: String get() = configuration.getNotNull(CommonConfigurationKeys.MODULE_NAME) diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt index c3b86c565c4..399a1db1ea7 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanPhases.kt @@ -52,6 +52,7 @@ enum class KonanPhase(val description: String, /* ... ... */ RTTI("RTTI Generation"), /* ... ... */ CODEGEN("Code Generation"), /* ... ... */ METADATOR("Metadata Generation"), + /* ... ... */ BITCODE_LINKER("Bitcode linking"), /* */ LINK_STAGE("Link stage"), /* ... */ OBJECT_FILES("Bitcode to object file"), /* ... */ LINKER("Linker"); diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt index 401259f6c29..53190e5dd01 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt @@ -194,7 +194,7 @@ internal class LinkStage(val context: Context) { val optimize = config.get(KonanConfigKeys.OPTIMIZATION) ?: false val emitted = config.get(KonanConfigKeys.BITCODE_FILE)!! val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false - val libraries = context.config.librariesToLink + val libraries = context.config.libraries fun llvmLto(files: List): ObjectFile { val tmpCombined = File.createTempFile("combined", ".o") diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt index f750dff0969..a75b8a1b18c 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt @@ -76,6 +76,16 @@ internal fun emitLLVM(context: Context) { irModule.acceptVoid(MetadatorVisitor(context)) } + phaser.phase(KonanPhase.BITCODE_LINKER) { + for (library in context.config.nativeLibraries) { + val libraryModule = parseBitcodeFile(library) + val failed = LLVMLinkModules2(llvmModule, libraryModule) + if (failed != 0) { + throw Error("failed to link $library") // TODO: retrieve error message from LLVM. + } + } + } + val outFile = context.config.configuration.get(KonanConfigKeys.BITCODE_FILE)!! LLVMWriteBitcodeToFile(llvmModule, outFile) } diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt index dd38b884a99..c6ee0a5d2a9 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/LlvmUtils.kt @@ -216,4 +216,28 @@ fun getStructElements(type: LLVMTypeRef): List { return (0 until count).map { LLVMStructGetTypeAtIndex(type, it)!! } -} \ No newline at end of file +} + +fun parseBitcodeFile(path: String): LLVMModuleRef = memScoped { + val bufRef = alloc() + val errorRef = allocPointerTo() + + val res = LLVMCreateMemoryBufferWithContentsOfFile(path, bufRef.ptr, errorRef.ptr) + if (res != 0) { + throw Error(errorRef.value?.toKString()) + } + + val memoryBuffer = bufRef.value + try { + + val moduleRef = alloc() + val parseRes = LLVMParseBitcode2(memoryBuffer, moduleRef.ptr) + if (parseRes != 0) { + throw Error(parseRes.toString()) + } + + moduleRef.value!! + } finally { + LLVMDisposeMemoryBuffer(memoryBuffer) + } +} diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt index 1ab80dc5362..a034d4f5679 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/Runtime.kt @@ -26,29 +26,8 @@ interface RuntimeAware { val runtime: Runtime } -class Runtime(private val bitcodeFile: String) { - val llvmModule: LLVMModuleRef - - init { - llvmModule = memScoped { - - val bufRef = alloc() - val errorRef = allocPointerTo() - - val res = LLVMCreateMemoryBufferWithContentsOfFile(bitcodeFile, bufRef.ptr, errorRef.ptr) - if (res != 0) { - throw Error(errorRef.value?.toKString()) - } - - val moduleRef = alloc() - val parseRes = LLVMParseBitcode2(bufRef.value, moduleRef.ptr) - if (parseRes != 0) { - throw Error(parseRes.toString()) - } - - moduleRef.value!! - } - } +class Runtime(bitcodeFile: String) { + val llvmModule: LLVMModuleRef = parseBitcodeFile(bitcodeFile) private fun getStructType(name: String) = LLVMGetTypeByName(llvmModule, "struct.$name")!! diff --git a/backend.native/llvm.def b/backend.native/llvm.def index ab769cf1607..c169ff03256 100644 --- a/backend.native/llvm.def +++ b/backend.native/llvm.def @@ -1,4 +1,5 @@ -headers = llvm-c/Core.h llvm-c/ExecutionEngine.h llvm-c/Target.h llvm-c/Analysis.h llvm-c/BitWriter.h llvm-c/BitReader.h +headers = llvm-c/Core.h llvm-c/ExecutionEngine.h llvm-c/Target.h llvm-c/Analysis.h llvm-c/BitWriter.h \ + llvm-c/BitReader.h llvm-c/Linker.h compilerOpts = -std=c99 -fPIC \ -Wall -W -Wno-unused-parameter -Wwrite-strings -Wmissing-field-initializers \