From 380010d1ee40a8e8277dee90240860e284386e1a Mon Sep 17 00:00:00 2001 From: Alexander Gorshenev Date: Tue, 23 May 2017 18:49:45 +0300 Subject: [PATCH] -produce program|library|bitcode 'program' makes a kexe. 'library' makes a klib. 'bitcode' makes just a bare bitcode file. The default is 'program'. --- backend.native/build.gradle | 8 +- .../org/jetbrains/kotlin/cli/bc/K2Native.kt | 35 ++++-- .../cli/bc/K2NativeCompilerArguments.java | 7 +- .../backend/konan/KonanConfigurationKeys.kt | 113 +++++++++--------- .../kotlin/backend/konan/KonanPhases.kt | 5 +- .../kotlin/backend/konan/LinkStage.kt | 2 +- .../kotlin/backend/konan/llvm/DebugUtils.kt | 9 +- .../kotlin/backend/konan/llvm/IrToBitcode.kt | 68 ++++++----- build.gradle | 5 +- 9 files changed, 132 insertions(+), 120 deletions(-) diff --git a/backend.native/build.gradle b/backend.native/build.gradle index 55375404510..9f21fe923b2 100644 --- a/backend.native/build.gradle +++ b/backend.native/build.gradle @@ -209,8 +209,8 @@ targetList.each { target -> "-Dkonan.home=${project.parent.file('dist')}", "-Djava.library.path=${project.buildDir}/nativelibs" args('-output', project(':runtime').file("build/${target}Stdlib"), - '-nolink', '-nopack', '-nostdlib','-ea', - '-target', target, + '-nopack', '-nostdlib','-ea', + '-produce', 'library', '-target', target, '-runtime', project(':runtime').file("build/${target}/runtime.bc"), '-properties', project(':backend.native').file('konan.properties'), project(':runtime').file('src/main/kotlin'), @@ -235,8 +235,8 @@ targetList.each { target -> "-Dkonan.home=${project.parent.file('dist')}", "-Djava.library.path=${project.buildDir}/nativelibs" args('-output', project(':runtime').file("build/${target}Start"), - '-nolink', '-nopack', '-nostdlib', '-ea', - '-target', target, + '-nopack', '-nostdlib', '-ea', + '-produce', 'bitcode', '-target', target, '-library', project(':runtime').file("build/${target}Stdlib"), '-runtime', project(':runtime').file("build/${target}/runtime.bc"), '-properties', rootProject.konanPropertiesFile.canonicalPath, diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index c86bfbcedc8..910de7c36b6 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.cli.bc import com.intellij.openapi.Disposable import org.jetbrains.kotlin.backend.konan.* +import org.jetbrains.kotlin.backend.konan.CompilerOutputKind.* import org.jetbrains.kotlin.backend.konan.util.profile import org.jetbrains.kotlin.cli.common.CLICompiler import org.jetbrains.kotlin.cli.common.ExitCode @@ -91,7 +92,6 @@ class K2Native : CLICompiler() { with(configuration) { put(NOSTDLIB, arguments.nostdlib) - put(NOLINK, arguments.nolink) put(NOPACK, arguments.nopack) put(NOMAIN, arguments.nomain) put(LIBRARY_FILES, @@ -108,18 +108,31 @@ class K2Native : CLICompiler() { // TODO: Collect all the explicit file names into an object // and teach the compiler to work with temporaries and -save-temps. - val library = arguments.outputFile ?: "library" - if (arguments.nolink) - put(LIBRARY_NAME, library) - put(LIBRARY_FILE, suffixIfNot(library, ".klib")) - val program = arguments.outputFile ?: "program" - if (!arguments.nolink) { - put(PROGRAM_NAME, program) - put(EXECUTABLE_FILE, suffixIfNot(program, ".kexe")) + + val outputKind = CompilerOutputKind.valueOf( + (arguments.produce ?: "program").toUpperCase()) + + put(PRODUCE, outputKind) + val (defaultName, suffix) = when (outputKind) { + CompilerOutputKind.LIBRARY -> { + put(NOLINK, true) + Pair("library", ".klib") + } + CompilerOutputKind.PROGRAM -> { + put(NOLINK, false) + Pair("program", ".kexe") + } + CompilerOutputKind.BITCODE -> { + put(NOLINK, true) + Pair("output", ".bc") + } } + val output = arguments.outputFile ?: defaultName + put(OUTPUT_NAME, output) + put(OUTPUT_FILE, suffixIfNot(output, suffix)) + // This is a decision we could change - val module = if (arguments.nolink) library else program - put(CommonConfigurationKeys.MODULE_NAME, module) + put(CommonConfigurationKeys.MODULE_NAME, output) put(ABI_VERSION, 1) if (arguments.runtimeFile != null) 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 aaaaf2cf765..61c4f4e8e3d 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 @@ -42,9 +42,6 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments { @Argument(value = "-nativelibrary", shortName = "-nl", valueDescription = "", description = "Include the native library") public String[] nativeLibraries; - @Argument(value = "-nolink", description = "Don't link, just produce a bitcode file") - public boolean nolink; - @Argument(value = "-nomain", description = "Assume 'main' entry point to be provided by external libraries") public boolean nomain; @@ -60,6 +57,9 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments { @Argument(value = "-output", shortName = "-o", valueDescription = "", description = "Output file path") public String outputFile; + @Argument(value = "-produce", valueDescription = "{program|library|bitcode}", description = "Produce either .kexe, .klib or a .bc file.") + public String produce; + @Argument(value = "-properties", valueDescription = "", description = "Override standard 'konan.properties' location") public String propertyFile; @@ -116,3 +116,4 @@ public class K2NativeCompilerArguments extends CommonCompilerArguments { public boolean verifyIr; } + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 9fc523efa29..59b0cd83eda 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -21,83 +21,82 @@ import org.jetbrains.kotlin.serialization.js.ModuleKind class KonanConfigKeys { companion object { - val LIBRARY_FILES: CompilerConfigurationKey> - = CompilerConfigurationKey.create("library file paths") - val NATIVE_LIBRARY_FILES: CompilerConfigurationKey> - = CompilerConfigurationKey.create("native library file paths") - val LIBRARY_NAME: CompilerConfigurationKey - = CompilerConfigurationKey.create("library name") - val LIBRARY_FILE: CompilerConfigurationKey - = CompilerConfigurationKey.create("library file path") - val PROGRAM_NAME: CompilerConfigurationKey - = CompilerConfigurationKey.create("program name") - val EXECUTABLE_FILE: CompilerConfigurationKey - = CompilerConfigurationKey.create("final executable file path") - val RUNTIME_FILE: CompilerConfigurationKey - = CompilerConfigurationKey.create("override default runtime file path") - val PROPERTY_FILE: CompilerConfigurationKey - = CompilerConfigurationKey.create("override default property file path") + // Keep the list lexically sorted. val ABI_VERSION: CompilerConfigurationKey = CompilerConfigurationKey.create("current abi version") - val OPTIMIZATION: CompilerConfigurationKey - = CompilerConfigurationKey.create("optimized compilation") val DEBUG: CompilerConfigurationKey = CompilerConfigurationKey.create("add debug information") - val NOSTDLIB: CompilerConfigurationKey - = CompilerConfigurationKey.create("don't link with stdlib") - val NOLINK: CompilerConfigurationKey - = CompilerConfigurationKey.create("don't link, only produce a bitcode file ") - val NOPACK: CompilerConfigurationKey - = CompilerConfigurationKey.create("don't the library into a klib file") - val NOMAIN: CompilerConfigurationKey - = CompilerConfigurationKey.create("assume 'main' entry point to be provided by external libraries") + val DISABLED_PHASES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("disable backend phases") + val ENABLE_ASSERTIONS: CompilerConfigurationKey + = CompilerConfigurationKey.create("enable runtime assertions in generated code") + val ENABLED_PHASES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("enable backend phases") + val LIBRARY_FILES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("library file paths") val LINKER_ARGS: CompilerConfigurationKey> = CompilerConfigurationKey.create("additional linker arguments") - val REPOSITORIES: CompilerConfigurationKey> - = CompilerConfigurationKey.create("library search path repositories") - val TARGET: CompilerConfigurationKey - = CompilerConfigurationKey.create("target we compile for") + val LIST_PHASES: CompilerConfigurationKey + = CompilerConfigurationKey.create("list backend phases") val LIST_TARGETS: CompilerConfigurationKey = CompilerConfigurationKey.create("list available targets") - - val SOURCE_MAP: CompilerConfigurationKey> - = CompilerConfigurationKey.create("generate source map") val META_INFO: CompilerConfigurationKey> = CompilerConfigurationKey.create("generate metadata") val MODULE_KIND: CompilerConfigurationKey = CompilerConfigurationKey.create("module kind") - - val VERIFY_IR: CompilerConfigurationKey - = CompilerConfigurationKey.create("verify ir") - val VERIFY_DESCRIPTORS: CompilerConfigurationKey - = CompilerConfigurationKey.create("verify descriptors") - val VERIFY_BITCODE: CompilerConfigurationKey - = CompilerConfigurationKey.create("verify bitcode") - + val NATIVE_LIBRARY_FILES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("native library file paths") + val NOLINK: CompilerConfigurationKey + = CompilerConfigurationKey.create("don't link, only produce a bitcode file ") + val NOMAIN: CompilerConfigurationKey + = CompilerConfigurationKey.create("assume 'main' entry point to be provided by external libraries") + val NOSTDLIB: CompilerConfigurationKey + = CompilerConfigurationKey.create("don't link with stdlib") + val NOPACK: CompilerConfigurationKey + = CompilerConfigurationKey.create("don't the library into a klib file") + val OPTIMIZATION: CompilerConfigurationKey + = CompilerConfigurationKey.create("optimized compilation") + val OUTPUT_FILE: CompilerConfigurationKey + = CompilerConfigurationKey.create("final executable file path") + val OUTPUT_NAME: CompilerConfigurationKey + = CompilerConfigurationKey.create("program or library name") + val PRINT_BITCODE: CompilerConfigurationKey + = CompilerConfigurationKey.create("print bitcode") + val PRINT_DESCRIPTORS: CompilerConfigurationKey + = CompilerConfigurationKey.create("print descriptors") val PRINT_IR: CompilerConfigurationKey = CompilerConfigurationKey.create("print ir") val PRINT_IR_WITH_DESCRIPTORS: CompilerConfigurationKey = CompilerConfigurationKey.create("print ir with descriptors") - val PRINT_DESCRIPTORS: CompilerConfigurationKey - = CompilerConfigurationKey.create("print descriptors") - val PRINT_BITCODE: CompilerConfigurationKey - = CompilerConfigurationKey.create("print bitcode") val PRINT_LOCATIONS: CompilerConfigurationKey = CompilerConfigurationKey.create("print locations") - - val ENABLED_PHASES: CompilerConfigurationKey> - = CompilerConfigurationKey.create("enable backend phases") - val DISABLED_PHASES: CompilerConfigurationKey> - = CompilerConfigurationKey.create("disable backend phases") - val VERBOSE_PHASES: CompilerConfigurationKey> - = CompilerConfigurationKey.create("verbose backend phases") - val LIST_PHASES: CompilerConfigurationKey - = CompilerConfigurationKey.create("list backend phases") + val PRODUCE: CompilerConfigurationKey + = CompilerConfigurationKey.create("compiler output kind") + val PROPERTY_FILE: CompilerConfigurationKey + = CompilerConfigurationKey.create("override default property file path") + val REPOSITORIES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("library search path repositories") + val RUNTIME_FILE: CompilerConfigurationKey + = CompilerConfigurationKey.create("override default runtime file path") + val SOURCE_MAP: CompilerConfigurationKey> + = CompilerConfigurationKey.create("generate source map") + val TARGET: CompilerConfigurationKey + = CompilerConfigurationKey.create("target we compile for") val TIME_PHASES: CompilerConfigurationKey = CompilerConfigurationKey.create("time backend phases") - - val ENABLE_ASSERTIONS: CompilerConfigurationKey - = CompilerConfigurationKey.create("enable runtime assertions in generated code") + val VERIFY_BITCODE: CompilerConfigurationKey + = CompilerConfigurationKey.create("verify bitcode") + val VERIFY_DESCRIPTORS: CompilerConfigurationKey + = CompilerConfigurationKey.create("verify descriptors") + val VERIFY_IR: CompilerConfigurationKey + = CompilerConfigurationKey.create("verify ir") + val VERBOSE_PHASES: CompilerConfigurationKey> + = CompilerConfigurationKey.create("verbose backend phases") } } +enum class CompilerOutputKind { + PROGRAM, + LIBRARY, + BITCODE +} 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 23de0d97592..18cb6b95e8f 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 @@ -53,7 +53,6 @@ enum class KonanPhase(val description: String, /* ... */ BITCODE("LLVM BitCode Generation"), /* ... ... */ RTTI("RTTI Generation"), /* ... ... */ CODEGEN("Code Generation"), - /* ... ... */ METADATOR("Metadata Generation"), /* ... ... */ BITCODE_LINKER("Bitcode linking"), /* */ LINK_STAGE("Link stage"), /* ... */ OBJECT_FILES("Bitcode to object file"), @@ -76,8 +75,8 @@ object KonanPhases { with (config.configuration) { with (KonanConfigKeys) { // Don't serialize anything to a final executable. - KonanPhase.SERIALIZER.enabled = getBoolean(NOLINK) - KonanPhase.METADATOR.enabled = getBoolean(NOLINK) + KonanPhase.SERIALIZER.enabled = + (get(PRODUCE) == CompilerOutputKind.LIBRARY) val disabled = get(DISABLED_PHASES) disabled?.forEach { phases[known(it)]!!.enabled = false } 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 becb476dbbf..d628ab45768 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 @@ -205,7 +205,7 @@ internal class LinkStage(val context: Context) { get() = if (nomain) emptyList() else platform.entrySelector fun link(objectFiles: List): ExecutableFile { - val executable = config.get(KonanConfigKeys.EXECUTABLE_FILE)!! + val executable = config.get(KonanConfigKeys.OUTPUT_FILE)!! val linkCommand = platform.linkCommand(objectFiles, executable, optimize) + distribution.libffi + asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) + diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt index eb72b957a54..ed166f52697 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/DebugUtils.kt @@ -103,13 +103,8 @@ internal fun String?.toFileAndFolder():FileAndFolder { internal fun generateDebugInfoHeader(context: Context) { if (context.shouldContainDebugInfo()) { - val path = with(context.config.configuration) { - if (!getBoolean(KonanConfigKeys.NOLINK)) { - get(KonanConfigKeys.EXECUTABLE_FILE)!! - } else { - get(KonanConfigKeys.LIBRARY_NAME)!! - } - }.toFileAndFolder() + val path = context.config.configuration.get(KonanConfigKeys.OUTPUT_FILE)!! + .toFileAndFolder() context.debugInfo.module = DICreateModule( builder = context.debugInfo.builder, 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 a6411fd79a1..0bc35c727e6 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 @@ -22,6 +22,7 @@ import org.jetbrains.kotlin.backend.common.descriptors.allParameters import org.jetbrains.kotlin.backend.common.descriptors.isSuspend import org.jetbrains.kotlin.backend.konan.Context import org.jetbrains.kotlin.backend.konan.KonanConfigKeys +import org.jetbrains.kotlin.backend.konan.CompilerOutputKind import org.jetbrains.kotlin.backend.konan.KonanPhase import org.jetbrains.kotlin.backend.konan.library.LinkData import org.jetbrains.kotlin.backend.konan.PhaseManager @@ -85,41 +86,48 @@ internal fun emitLLVM(context: Context) { DIFinalize(context.debugInfo.builder) } - if (!config.getBoolean(KonanConfigKeys.NOLINK)) { - val program = config.get(KonanConfigKeys.PROGRAM_NAME)!! - val output = "${program}.kt.bc" - context.bitcodeFileName = output + when (config.get(KonanConfigKeys.PRODUCE)) { + CompilerOutputKind.PROGRAM -> { + val program = config.get(KonanConfigKeys.OUTPUT_NAME)!! + val output = "${program}.kt.bc" + context.bitcodeFileName = output - 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. + 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. + } } - } + } + + LLVMWriteBitcodeToFile(llvmModule, output) } + CompilerOutputKind.LIBRARY -> { - LLVMWriteBitcodeToFile(llvmModule, output) - } else { + val libraryName = config.get(KonanConfigKeys.OUTPUT_NAME)!! + val nopack = config.getBoolean(KonanConfigKeys.NOPACK) + val targetName = context.config.targetManager.currentName - val libraryName = config.get(KonanConfigKeys.LIBRARY_NAME)!! - val nopack = config.getBoolean(KonanConfigKeys.NOPACK) - val targetName = context.config.targetManager.currentName + val library = buildLibrary( + phaser, + context.config.nativeLibraries, + context.serializedLinkData!!, + targetName, + libraryName, + llvmModule, + nopack) - val library = buildLibrary( - phaser, - context.config.nativeLibraries, - context.serializedLinkData!!, - targetName, - libraryName, - llvmModule, - nopack) + context.library = library - context.library = library - - context.bitcodeFileName = - library.mainBitcodeFileName + context.bitcodeFileName = library.mainBitcodeFileName + } + CompilerOutputKind.BITCODE -> { + val output = config.get(KonanConfigKeys.OUTPUT_FILE)!! + context.bitcodeFileName = output + LLVMWriteBitcodeToFile(llvmModule, output) + } } } @@ -130,9 +138,7 @@ internal fun buildLibrary(phaser: PhaseManager, natives: List, linkData: library.addKotlinBitcode(llvmModule) - phaser.phase(KonanPhase.METADATOR) { - library.addLinkData(linkData) - } + library.addLinkData(linkData) phaser.phase(KonanPhase.BITCODE_LINKER) { natives.forEach { diff --git a/build.gradle b/build.gradle index c172671ff9a..ff800f1e571 100644 --- a/build.gradle +++ b/build.gradle @@ -286,9 +286,8 @@ targetList.each { target -> include('**') into('klib/stdlib') } - from(project(':runtime').file("build/${target}Start/$target/kotlin")) { - include("program.kt.bc") - rename('program.kt.bc', 'start.kt.bc') + from(project(':runtime').file("build/${target}Start.bc")) { + rename("${target}Start.bc", 'start.bc') into("klib/stdlib/$target/native") } }