Skip to content
This repository was archived by the owner on Aug 10, 2021. It is now read-only.

Commit 00eb378

Browse files
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.
1 parent d538768 commit 00eb378

File tree

9 files changed

+126
-5
lines changed

9 files changed

+126
-5
lines changed

FAQ.md

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,25 @@ framework("MyCustomFramework") {
5050

5151
</div>
5252

53+
### Q: How do I enable bitcode for my Kotlin framework?
54+
55+
A: Use either `-Xembed-bitcode` or `-Xembed-bitcode-marker` compiler option
56+
or matching Gradle DSL statement, i.e.
57+
58+
<div class="sample" markdown="1" theme="idea" mode="groovy">
59+
60+
```groovy
61+
framework("MyCustomFramework") {
62+
extraOpts '-Xembed-bitcode' // for release binaries
63+
// or '-Xembed-bitcode-marker' for debug binaries
64+
}
65+
```
66+
67+
These options have nearly the same effect as clang's `-fembed-bitcode`/`-fembed-bitcode-marker`
68+
and swiftc's `-embed-bitcode`/`-embed-bitcode-marker`.
69+
70+
</div>
71+
5372
### Q: Why do I see `InvalidMutabilityException`?
5473

5574
A: It likely happens, because you are trying to mutate a frozen object. An object can transfer to the

backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt

Lines changed: 43 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -14,17 +14,14 @@ import org.jetbrains.kotlin.cli.common.CLITool
1414
import org.jetbrains.kotlin.cli.common.CommonCompilerPerformanceManager
1515
import org.jetbrains.kotlin.cli.common.ExitCode
1616
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot
17-
import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoots
1817
import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots
19-
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.ERROR
20-
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING
18+
import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.*
2119
import org.jetbrains.kotlin.cli.jvm.compiler.EnvironmentConfigFiles
2220
import org.jetbrains.kotlin.cli.jvm.compiler.KotlinCoreEnvironment
2321
import org.jetbrains.kotlin.cli.jvm.plugins.PluginCliParser
2422
import org.jetbrains.kotlin.config.CommonConfigurationKeys
2523
import org.jetbrains.kotlin.config.CompilerConfiguration
2624
import org.jetbrains.kotlin.config.Services
27-
import org.jetbrains.kotlin.konan.KonanAbiVersion
2825
import org.jetbrains.kotlin.konan.KonanVersion
2926
import org.jetbrains.kotlin.konan.file.File
3027
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -190,6 +187,8 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
190187
})
191188
if (arguments.friendModules != null)
192189
put(FRIEND_MODULES, arguments.friendModules!!.split(File.pathSeparator).filterNot(String::isEmpty))
190+
191+
put(BITCODE_EMBEDDING_MODE, selectBitcodeEmbeddingMode(this, arguments, outputKind))
193192
}
194193
}
195194
}
@@ -214,5 +213,45 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
214213
}
215214
}
216215
}
216+
217+
private fun selectBitcodeEmbeddingMode(
218+
configuration: CompilerConfiguration,
219+
arguments: K2NativeCompilerArguments,
220+
outputKind: CompilerOutputKind
221+
): BitcodeEmbedding.Mode {
222+
223+
if (outputKind != CompilerOutputKind.FRAMEWORK) {
224+
return BitcodeEmbedding.Mode.NONE.also {
225+
val flag = when {
226+
arguments.embedBitcodeMarker -> EMBED_BITCODE_MARKER_FLAG
227+
arguments.embedBitcode -> EMBED_BITCODE_FLAG
228+
else -> return@also
229+
}
230+
231+
configuration.report(
232+
STRONG_WARNING,
233+
"'$flag' is only supported when producing frameworks, " +
234+
"but the compiler is producing ${outputKind.name.toLowerCase()}"
235+
)
236+
}
237+
}
238+
239+
return when {
240+
arguments.embedBitcodeMarker -> {
241+
if (arguments.embedBitcode) {
242+
configuration.report(
243+
STRONG_WARNING,
244+
"'$EMBED_BITCODE_FLAG' is ignored because '$EMBED_BITCODE_MARKER_FLAG' is specified"
245+
)
246+
}
247+
BitcodeEmbedding.Mode.MARKER
248+
}
249+
arguments.embedBitcode -> {
250+
BitcodeEmbedding.Mode.FULL
251+
}
252+
else -> BitcodeEmbedding.Mode.NONE
253+
}
254+
}
255+
217256
fun main(args: Array<String>) = K2Native.main(args)
218257

backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,12 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
9494
@Argument(value = "-Xdisable", deprecatedName = "--disable", valueDescription = "<Phase>", description = "Disable backend phase")
9595
var disablePhases: Array<String>? = null
9696

97+
@Argument(value = EMBED_BITCODE_FLAG, description = "Embed LLVM IR bitcode as data")
98+
var embedBitcode: Boolean = false
99+
100+
@Argument(value = EMBED_BITCODE_MARKER_FLAG, description = "Embed placeholder LLVM IR data as a marker")
101+
var embedBitcodeMarker: Boolean = false
102+
97103
@Argument(value = "-Xenable", deprecatedName = "--enable", valueDescription = "<Phase>", description = "Enable backend phase")
98104
var enablePhases: Array<String>? = null
99105

@@ -153,3 +159,5 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
153159
}
154160
}
155161

162+
const val EMBED_BITCODE_FLAG = "-Xembed-bitcode"
163+
const val EMBED_BITCODE_MARKER_FLAG = "-Xembed-bitcode-marker"
Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
package org.jetbrains.kotlin.backend.konan
2+
3+
import org.jetbrains.kotlin.backend.konan.llvm.Int8
4+
import org.jetbrains.kotlin.backend.konan.llvm.Llvm
5+
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
6+
7+
object BitcodeEmbedding {
8+
9+
enum class Mode {
10+
NONE, MARKER, FULL
11+
}
12+
13+
internal fun getLinkerOptions(config: KonanConfig): List<String> = when (config.bitcodeEmbeddingMode) {
14+
Mode.NONE -> emptyList()
15+
Mode.MARKER -> listOf("-bitcode_bundle", "-bitcode_process_mode", "marker")
16+
Mode.FULL -> listOf("-bitcode_bundle")
17+
}
18+
19+
private val KonanConfig.bitcodeEmbeddingMode get() = configuration.get(KonanConfigKeys.BITCODE_EMBEDDING_MODE)!!.also {
20+
require(it == Mode.NONE || this.produce == CompilerOutputKind.FRAMEWORK) {
21+
"${it.name.toLowerCase()} bitcode embedding mode is not supported when producing ${this.produce.name.toLowerCase()}"
22+
}
23+
}
24+
25+
internal fun processModule(llvm: Llvm) = when (llvm.context.config.bitcodeEmbeddingMode) {
26+
Mode.NONE -> {}
27+
Mode.MARKER -> {
28+
addEmptyMarker(llvm, "konan_llvm_bitcode", "__LLVM,__bitcode")
29+
addEmptyMarker(llvm, "konan_llvm_cmdline", "__LLVM,__cmdline")
30+
}
31+
Mode.FULL -> {
32+
addEmptyMarker(llvm, "konan_llvm_asm", "__LLVM,__asm")
33+
}
34+
}
35+
36+
private fun addEmptyMarker(llvm: Llvm, name: String, section: String) {
37+
val global = llvm.staticData.placeGlobal(name, Int8(0), isExported = false)
38+
global.setSection(section)
39+
llvm.usedGlobals += global.llvmGlobal
40+
}
41+
}

backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,8 @@ class KonanConfigKeys {
2020
= CompilerConfigurationKey.create("add debug information")
2121
val DISABLED_PHASES: CompilerConfigurationKey<List<String>>
2222
= CompilerConfigurationKey.create("disable backend phases")
23+
val BITCODE_EMBEDDING_MODE: CompilerConfigurationKey<BitcodeEmbedding.Mode>
24+
= CompilerConfigurationKey.create("bitcode embedding mode")
2325
val ENABLE_ASSERTIONS: CompilerConfigurationKey<Boolean>
2426
= CompilerConfigurationKey.create("enable runtime assertions in generated code")
2527
val ENABLED_PHASES: CompilerConfigurationKey<List<String>>

backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/LinkStage.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,7 @@ internal class LinkStage(val context: Context, val phaser: PhaseManager) {
183183
libraries = linker.targetLibffi + linker.linkStaticLibraries(includedBinaries),
184184
linkerArgs = entryPointSelector +
185185
asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) +
186+
BitcodeEmbedding.getLinkerOptions(context.config) +
186187
libraryProvidedLinkerFlags + frameworkLinkerArgs,
187188
optimize = optimize, debug = debug, kind = linkerOutput,
188189
outputDsymBundle = context.config.outputFile + ".dSYM").forEach {

backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/IrToBitcode.kt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -383,6 +383,8 @@ internal class CodeGeneratorVisitor(val context: Context, val lifetimes: Map<IrE
383383

384384
codegen.objCDataGenerator?.finishModule()
385385

386+
BitcodeEmbedding.processModule(context.llvm)
387+
386388
appendLlvmUsed("llvm.used", context.llvm.usedFunctions + context.llvm.usedGlobals)
387389
appendLlvmUsed("llvm.compiler.used", context.llvm.compilerUsedGlobals)
388390
appendStaticInitializers()

backend.native/tests/build.gradle

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2993,13 +2993,16 @@ if (isMac() && project.testTarget != 'wasm32') {
29932993
if (!useCustomDist) {
29942994
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
29952995
}
2996+
2997+
extraOpts "-Xembed-bitcode-marker"
29962998
}
29972999
}
29983000
swiftSources = ['framework/values/values.swift']
29993001
}
30003002

30013003
task testStdlibFramework(type: FrameworkTest) {
30023004
frameworkName = 'Stdlib'
3005+
fullBitcode = true
30033006
konanArtifacts {
30043007
framework(frameworkName, targets: [ target ]) {
30053008
srcDir 'framework/stdlib'
@@ -3008,6 +3011,8 @@ if (isMac() && project.testTarget != 'wasm32') {
30083011
if (!useCustomDist) {
30093012
dependsOn ":${target}CrossDistRuntime", ':commonDistRuntime', ':distCompiler'
30103013
}
3014+
3015+
extraOpts "-Xembed-bitcode"
30113016
}
30123017
}
30133018
swiftSources = ['framework/stdlib/stdlib.swift']

buildSrc/plugins/src/main/kotlin/org/jetbrains/kotlin/FrameworkTest.kt

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,9 @@ open class FrameworkTest : DefaultTask() {
3131
@Input
3232
lateinit var frameworkName: String
3333

34+
@Input
35+
var fullBitcode: Boolean = false
36+
3437
private val testOutput: String by lazy {
3538
project.file(project.property("testOutputFramework")!!).absolutePath
3639
}
@@ -109,7 +112,8 @@ open class FrameworkTest : DefaultTask() {
109112
}
110113

111114
val args = listOf("-sdk", configs.absoluteTargetSysRoot, "-target", swiftTarget) +
112-
options + "-o" + output.toString() + sources
115+
options + "-o" + output.toString() + sources +
116+
if (fullBitcode) listOf("-embed-bitcode", "-Xlinker", "-bitcode_verify") else listOf("-embed-bitcode-marker")
113117

114118
val (stdOut, stdErr, exitCode) = runProcess(executor = localExecutor(project), executable = compiler, args = args)
115119

0 commit comments

Comments
 (0)