diff --git a/FAQ.md b/FAQ.md
index 9cf4ba92045..97bc50a8d38 100644
--- a/FAQ.md
+++ b/FAQ.md
@@ -50,6 +50,25 @@ framework("MyCustomFramework") {
+### Q: How do I enable bitcode for my Kotlin framework?
+
+A: Use either `-Xembed-bitcode` or `-Xembed-bitcode-marker` compiler option
+or matching Gradle DSL statement, i.e.
+
+
+
+```groovy
+framework("MyCustomFramework") {
+ extraOpts '-Xembed-bitcode' // for release binaries
+ // or '-Xembed-bitcode-marker' for debug binaries
+}
+```
+
+These options have nearly the same effect as clang's `-fembed-bitcode`/`-fembed-bitcode-marker`
+and swiftc's `-embed-bitcode`/`-embed-bitcode-marker`.
+
+
+
### Q: Why do I see `InvalidMutabilityException`?
A: It likely happens, because you are trying to mutate a frozen object. An object can transfer to the
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 b749ffc9e5e..7c0ab1152a4 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
@@ -14,17 +14,14 @@ import org.jetbrains.kotlin.cli.common.CLITool
import org.jetbrains.kotlin.cli.common.CommonCompilerPerformanceManager
import org.jetbrains.kotlin.cli.common.ExitCode
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
-import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
-import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
+import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
import org.jetbrains.kotlin.config.CommonConfigurationKeys
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.config.Services
-import org.jetbrains.kotlin.konan.KonanAbiVersion
import org.jetbrains.kotlin.konan.KonanVersion
import org.jetbrains.kotlin.konan.file.File
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -190,6 +187,8 @@ class K2Native : CLICompiler() {
})
if (arguments.friendModules != null)
put(FRIEND_MODULES, arguments.friendModules!!.split(File.pathSeparator).filterNot(String::isEmpty))
+
+ put(BITCODE_EMBEDDING_MODE, selectBitcodeEmbeddingMode(this, arguments, outputKind))
}
}
}
@@ -214,5 +213,45 @@ class K2Native : CLICompiler() {
}
}
}
+
+private fun selectBitcodeEmbeddingMode(
+ configuration: CompilerConfiguration,
+ arguments: K2NativeCompilerArguments,
+ outputKind: CompilerOutputKind
+): BitcodeEmbedding.Mode {
+
+ if (outputKind != CompilerOutputKind.FRAMEWORK) {
+ return BitcodeEmbedding.Mode.NONE.also {
+ val flag = when {
+ arguments.embedBitcodeMarker -> EMBED_BITCODE_MARKER_FLAG
+ arguments.embedBitcode -> EMBED_BITCODE_FLAG
+ else -> return@also
+ }
+
+ configuration.report(
+ STRONG_WARNING,
+ "'$flag' is only supported when producing frameworks, " +
+ "but the compiler is producing ${outputKind.name.toLowerCase()}"
+ )
+ }
+ }
+
+ return when {
+ arguments.embedBitcodeMarker -> {
+ if (arguments.embedBitcode) {
+ configuration.report(
+ STRONG_WARNING,
+ "'$EMBED_BITCODE_FLAG' is ignored because '$EMBED_BITCODE_MARKER_FLAG' is specified"
+ )
+ }
+ BitcodeEmbedding.Mode.MARKER
+ }
+ arguments.embedBitcode -> {
+ BitcodeEmbedding.Mode.FULL
+ }
+ else -> BitcodeEmbedding.Mode.NONE
+ }
+}
+
fun main(args: Array) = K2Native.main(args)
diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt
index 1bac1f8fa35..bc7daf8ec01 100644
--- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt
+++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt
@@ -94,6 +94,12 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xdisable", deprecatedName = "--disable", valueDescription = "", description = "Disable backend phase")
var disablePhases: Array? = null
+ @Argument(value = EMBED_BITCODE_FLAG, description = "Embed LLVM IR bitcode as data")
+ var embedBitcode: Boolean = false
+
+ @Argument(value = EMBED_BITCODE_MARKER_FLAG, description = "Embed placeholder LLVM IR data as a marker")
+ var embedBitcodeMarker: Boolean = false
+
@Argument(value = "-Xenable", deprecatedName = "--enable", valueDescription = "", description = "Enable backend phase")
var enablePhases: Array? = null
@@ -153,3 +159,5 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
}
}
+const val EMBED_BITCODE_FLAG = "-Xembed-bitcode"
+const val EMBED_BITCODE_MARKER_FLAG = "-Xembed-bitcode-marker"
diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeEmbedding.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeEmbedding.kt
new file mode 100644
index 00000000000..87e37addc89
--- /dev/null
+++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/BitcodeEmbedding.kt
@@ -0,0 +1,41 @@
+package org.jetbrains.kotlin.backend.konan
+
+import org.jetbrains.kotlin.backend.konan.llvm.Int8
+import org.jetbrains.kotlin.backend.konan.llvm.Llvm
+import org.jetbrains.kotlin.konan.target.CompilerOutputKind
+
+object BitcodeEmbedding {
+
+ enum class Mode {
+ NONE, MARKER, FULL
+ }
+
+ internal fun getLinkerOptions(config: KonanConfig): List = when (config.bitcodeEmbeddingMode) {
+ Mode.NONE -> emptyList()
+ Mode.MARKER -> listOf("-bitcode_bundle", "-bitcode_process_mode", "marker")
+ Mode.FULL -> listOf("-bitcode_bundle")
+ }
+
+ 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()}"
+ }
+ }
+
+ internal fun processModule(llvm: Llvm) = when (llvm.context.config.bitcodeEmbeddingMode) {
+ Mode.NONE -> {}
+ Mode.MARKER -> {
+ addEmptyMarker(llvm, "konan_llvm_bitcode", "__LLVM,__bitcode")
+ addEmptyMarker(llvm, "konan_llvm_cmdline", "__LLVM,__cmdline")
+ }
+ Mode.FULL -> {
+ addEmptyMarker(llvm, "konan_llvm_asm", "__LLVM,__asm")
+ }
+ }
+
+ private fun addEmptyMarker(llvm: Llvm, name: String, section: String) {
+ val global = llvm.staticData.placeGlobal(name, Int8(0), isExported = false)
+ global.setSection(section)
+ llvm.usedGlobals += global.llvmGlobal
+ }
+}
\ No newline at end of file
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 62ad8452c39..ab898c93b63 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
@@ -20,6 +20,8 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("add debug information")
val DISABLED_PHASES: CompilerConfigurationKey>
= CompilerConfigurationKey.create("disable backend phases")
+ val BITCODE_EMBEDDING_MODE: CompilerConfigurationKey
+ = CompilerConfigurationKey.create("bitcode embedding mode")
val ENABLE_ASSERTIONS: CompilerConfigurationKey
= CompilerConfigurationKey.create("enable runtime assertions in generated code")
val ENABLED_PHASES: CompilerConfigurationKey>
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 60dc6b95575..e90c53c79f0 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
@@ -183,6 +183,7 @@ internal class LinkStage(val context: Context, val phaser: PhaseManager) {
libraries = linker.targetLibffi + linker.linkStaticLibraries(includedBinaries),
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 {
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 76d7beedd2b..ba89211a33a 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
@@ -383,6 +383,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map