Implement -Xembed-bitcode and -Xembed-bitcode-marker

These options currently make the produced framework bitcode-friendly
in release and debug environments correspondigly without embedding
real bitcode.
This commit is contained in:
Svyatoslav Scherbina
2018-10-08 14:49:18 +03:00
committed by SvyatoslavScherbina
parent af769d958e
commit 6cb4d0c241
9 changed files with 126 additions and 5 deletions
+19
View File
@@ -50,6 +50,25 @@ framework("MyCustomFramework") {
</div>
### 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.
<div class="sample" markdown="1" theme="idea" mode="groovy">
```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`.
</div>
### 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
@@ -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<K2NativeCompilerArguments>() {
})
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<K2NativeCompilerArguments>() {
}
}
}
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<String>) = K2Native.main(args)
@@ -94,6 +94,12 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value = "-Xdisable", deprecatedName = "--disable", valueDescription = "<Phase>", description = "Disable backend phase")
var disablePhases: Array<String>? = 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 = "<Phase>", description = "Enable backend phase")
var enablePhases: Array<String>? = null
@@ -153,3 +159,5 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
}
}
const val EMBED_BITCODE_FLAG = "-Xembed-bitcode"
const val EMBED_BITCODE_MARKER_FLAG = "-Xembed-bitcode-marker"
@@ -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<String> = 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
}
}
@@ -20,6 +20,8 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("add debug information")
val DISABLED_PHASES: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create("disable backend phases")
val BITCODE_EMBEDDING_MODE: CompilerConfigurationKey<BitcodeEmbedding.Mode>
= CompilerConfigurationKey.create("bitcode embedding mode")
val ENABLE_ASSERTIONS: CompilerConfigurationKey<Boolean>
= CompilerConfigurationKey.create("enable runtime assertions in generated code")
val ENABLED_PHASES: CompilerConfigurationKey<List<String>>
@@ -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 {
@@ -383,6 +383,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
codegen.objCDataGenerator?.finishModule()
BitcodeEmbedding.processModule(context.llvm)
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
appendStaticInitializers()
+5
View File
@@ -2998,6 +2998,8 @@ if (isMac() && project.testTarget != 'wasm32') {
if (!useCustomDist) {
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
}
extraOpts "-Xembed-bitcode-marker"
}
}
swiftSources = ['framework/values/values.swift']
@@ -3005,6 +3007,7 @@ if (isMac() && project.testTarget != 'wasm32') {
task testStdlibFramework(type: FrameworkTest) {
frameworkName = 'Stdlib'
fullBitcode = true
konanArtifacts {
framework(frameworkName, targets: [ target ]) {
srcDir 'framework/stdlib'
@@ -3013,6 +3016,8 @@ if (isMac() && project.testTarget != 'wasm32') {
if (!useCustomDist) {
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
}
extraOpts "-Xembed-bitcode"
}
}
swiftSources = ['framework/stdlib/stdlib.swift']
@@ -31,6 +31,9 @@ open class FrameworkTest : DefaultTask() {
@Input
lateinit var frameworkName: String
@Input
var fullBitcode: Boolean = false
private val testOutput: String by lazy {
project.file(project.property("testOutputFramework")!!).absolutePath
}
@@ -109,7 +112,8 @@ open class FrameworkTest : DefaultTask() {
}
val args = listOf("-sdk", configs.absoluteTargetSysRoot, "-target", swiftTarget) +
options + "-o" + output.toString() + sources
options + "-o" + output.toString() + sources +
if (fullBitcode) listOf("-embed-bitcode", "-Xlinker", "-bitcode_verify") else listOf("-embed-bitcode-marker")
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = compiler, args = args)