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:
committed by
SvyatoslavScherbina
parent
af769d958e
commit
6cb4d0c241
@@ -50,6 +50,25 @@ framework("MyCustomFramework") {
|
|||||||
|
|
||||||
</div>
|
</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`?
|
### 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
|
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.CommonCompilerPerformanceManager
|
||||||
import org.jetbrains.kotlin.cli.common.ExitCode
|
import org.jetbrains.kotlin.cli.common.ExitCode
|
||||||
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
|
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.config.kotlinSourceRoots
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
|
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
|
||||||
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
|
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
|
||||||
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
|
||||||
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
|
||||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
import org.jetbrains.kotlin.config.Services
|
import org.jetbrains.kotlin.config.Services
|
||||||
import org.jetbrains.kotlin.konan.KonanAbiVersion
|
|
||||||
import org.jetbrains.kotlin.konan.KonanVersion
|
import org.jetbrains.kotlin.konan.KonanVersion
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
@@ -190,6 +187,8 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
})
|
})
|
||||||
if (arguments.friendModules != null)
|
if (arguments.friendModules != null)
|
||||||
put(FRIEND_MODULES, arguments.friendModules!!.split(File.pathSeparator).filterNot(String::isEmpty))
|
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)
|
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")
|
@Argument(value = "-Xdisable", deprecatedName = "--disable", valueDescription = "<Phase>", description = "Disable backend phase")
|
||||||
var disablePhases: Array<String>? = null
|
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")
|
@Argument(value = "-Xenable", deprecatedName = "--enable", valueDescription = "<Phase>", description = "Enable backend phase")
|
||||||
var enablePhases: Array<String>? = null
|
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"
|
||||||
|
|||||||
+41
@@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
+2
@@ -20,6 +20,8 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create("add debug information")
|
= CompilerConfigurationKey.create("add debug information")
|
||||||
val DISABLED_PHASES: CompilerConfigurationKey<List<String>>
|
val DISABLED_PHASES: CompilerConfigurationKey<List<String>>
|
||||||
= CompilerConfigurationKey.create("disable backend phases")
|
= CompilerConfigurationKey.create("disable backend phases")
|
||||||
|
val BITCODE_EMBEDDING_MODE: CompilerConfigurationKey<BitcodeEmbedding.Mode>
|
||||||
|
= CompilerConfigurationKey.create("bitcode embedding mode")
|
||||||
val ENABLE_ASSERTIONS: CompilerConfigurationKey<Boolean>
|
val ENABLE_ASSERTIONS: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create("enable runtime assertions in generated code")
|
= CompilerConfigurationKey.create("enable runtime assertions in generated code")
|
||||||
val ENABLED_PHASES: CompilerConfigurationKey<List<String>>
|
val ENABLED_PHASES: CompilerConfigurationKey<List<String>>
|
||||||
|
|||||||
+1
@@ -183,6 +183,7 @@ internal class LinkStage(val context: Context, val phaser: PhaseManager) {
|
|||||||
libraries = linker.targetLibffi + linker.linkStaticLibraries(includedBinaries),
|
libraries = linker.targetLibffi + linker.linkStaticLibraries(includedBinaries),
|
||||||
linkerArgs = entryPointSelector +
|
linkerArgs = entryPointSelector +
|
||||||
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
|
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
|
||||||
|
BitcodeEmbedding.getLinkerOptions(context.config) +
|
||||||
libraryProvidedLinkerFlags + frameworkLinkerArgs,
|
libraryProvidedLinkerFlags + frameworkLinkerArgs,
|
||||||
optimize = optimize, debug = debug, kind = linkerOutput,
|
optimize = optimize, debug = debug, kind = linkerOutput,
|
||||||
outputDsymBundle = context.config.outputFile + ".dSYM").forEach {
|
outputDsymBundle = context.config.outputFile + ".dSYM").forEach {
|
||||||
|
|||||||
+2
@@ -383,6 +383,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
|
|||||||
|
|
||||||
codegen.objCDataGenerator?.finishModule()
|
codegen.objCDataGenerator?.finishModule()
|
||||||
|
|
||||||
|
BitcodeEmbedding.processModule(context.llvm)
|
||||||
|
|
||||||
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
|
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
|
||||||
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
|
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
|
||||||
appendStaticInitializers()
|
appendStaticInitializers()
|
||||||
|
|||||||
@@ -2998,6 +2998,8 @@ if (isMac() && project.testTarget != 'wasm32') {
|
|||||||
if (!useCustomDist) {
|
if (!useCustomDist) {
|
||||||
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
|
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraOpts "-Xembed-bitcode-marker"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
swiftSources = ['framework/values/values.swift']
|
swiftSources = ['framework/values/values.swift']
|
||||||
@@ -3005,6 +3007,7 @@ if (isMac() && project.testTarget != 'wasm32') {
|
|||||||
|
|
||||||
task testStdlibFramework(type: FrameworkTest) {
|
task testStdlibFramework(type: FrameworkTest) {
|
||||||
frameworkName = 'Stdlib'
|
frameworkName = 'Stdlib'
|
||||||
|
fullBitcode = true
|
||||||
konanArtifacts {
|
konanArtifacts {
|
||||||
framework(frameworkName, targets: [ target ]) {
|
framework(frameworkName, targets: [ target ]) {
|
||||||
srcDir 'framework/stdlib'
|
srcDir 'framework/stdlib'
|
||||||
@@ -3013,6 +3016,8 @@ if (isMac() && project.testTarget != 'wasm32') {
|
|||||||
if (!useCustomDist) {
|
if (!useCustomDist) {
|
||||||
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
|
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
extraOpts "-Xembed-bitcode"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
swiftSources = ['framework/stdlib/stdlib.swift']
|
swiftSources = ['framework/stdlib/stdlib.swift']
|
||||||
|
|||||||
@@ -31,6 +31,9 @@ open class FrameworkTest : DefaultTask() {
|
|||||||
@Input
|
@Input
|
||||||
lateinit var frameworkName: String
|
lateinit var frameworkName: String
|
||||||
|
|
||||||
|
@Input
|
||||||
|
var fullBitcode: Boolean = false
|
||||||
|
|
||||||
private val testOutput: String by lazy {
|
private val testOutput: String by lazy {
|
||||||
project.file(project.property("testOutputFramework")!!).absolutePath
|
project.file(project.property("testOutputFramework")!!).absolutePath
|
||||||
}
|
}
|
||||||
@@ -109,7 +112,8 @@ open class FrameworkTest : DefaultTask() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
val args = listOf("-sdk", configs.absoluteTargetSysRoot, "-target", swiftTarget) +
|
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)
|
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = compiler, args = args)
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user