Support bitcode embedding in Gradle plugin

This commit is contained in:
Ilya Matveev
2018-12-17 19:57:31 +07:00
committed by Ilya Matveev
parent 1ef76cf289
commit d5ef601658
5 changed files with 72 additions and 15 deletions
@@ -26,6 +26,7 @@ import org.gradle.language.ComponentWithOutputs
import org.gradle.language.nativeplatform.internal.ConfigurableComponentWithLinkUsage
import org.gradle.language.nativeplatform.internal.ConfigurableComponentWithRuntimeUsage
import org.gradle.nativeplatform.test.TestComponent
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.BitcodeEmbeddingMode
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.KotlinNativePlatform
import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -108,10 +109,11 @@ interface KotlinNativeLibrary : KotlinNativeBinary,
* Represents an Objective C framework compiled from Kotlin/Native sources.
*/
interface KotlinNativeFramework : KotlinNativeBinary {
/**
* Klibs exported in the framework.
*/
/** Klibs exported in the framework. */
val export: FileCollection
/** Mode of bitcode embedding: disabled, enabled or marker. */
var embedBitcode: BitcodeEmbeddingMode
}
/**
@@ -22,14 +22,24 @@ import java.util.*
class KotlinNativeBuildType(
private val name: String,
val debuggable: Boolean,
val optimized: Boolean
val optimized: Boolean,
internal val iosEmbedBitcode: BitcodeEmbeddingMode
) : Named {
override fun getName() = name
companion object {
val DEBUG = KotlinNativeBuildType("debug", true, false)
val RELEASE = KotlinNativeBuildType("release", false, true)
val DEBUG = KotlinNativeBuildType("debug", true, false, BitcodeEmbeddingMode.MARKER)
val RELEASE = KotlinNativeBuildType("release", false, true, BitcodeEmbeddingMode.BITCODE)
val DEFAULT_BUILD_TYPES: Collection<KotlinNativeBuildType> = Arrays.asList(DEBUG, RELEASE)
}
}
}
enum class BitcodeEmbeddingMode {
/** Don't embed LLVM IR bitcode. */
DISABLE,
/** Embed LLVM IR bitcode as data. */
BITCODE,
/** Embed placeholder LLVM IR data as a marker. */
MARKER,
}
@@ -29,9 +29,9 @@ import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeBinary
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeFramework
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinUsages
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.Family
import javax.inject.Inject
open class KotlinNativeFrameworkImpl @Inject constructor(
name: String,
baseName: Provider<String>,
@@ -54,6 +54,7 @@ open class KotlinNativeFrameworkImpl @Inject constructor(
configurations,
fileOperations
), KotlinNativeFramework {
override val outputRootName: String = "lib"
// A configuration containing exported klibs.
@@ -69,4 +70,10 @@ open class KotlinNativeFrameworkImpl @Inject constructor(
extendsFrom(componentDependencies.exportDependencies)
getImplementationDependencies().extendsFrom(this)
}
override var embedBitcode: BitcodeEmbeddingMode = if (konanTarget.family == Family.IOS) {
buildType.iosEmbedBitcode
} else {
BitcodeEmbeddingMode.DISABLE
}
}
@@ -28,6 +28,7 @@ import org.gradle.api.tasks.TaskAction
import org.gradle.api.tasks.compile.AbstractCompile
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeFramework
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeBinary
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.BitcodeEmbeddingMode
import org.jetbrains.kotlin.gradle.plugin.konan.*
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -91,6 +92,14 @@ open class KotlinNativeCompile @Inject constructor(internal val binary: Abstract
val outputFile: File
get() = outputLocationProvider.get().asFile
@get:Input
val embedBitcode: BitcodeEmbeddingMode
get() = if (binary is KotlinNativeFramework) {
binary.embedBitcode
} else {
BitcodeEmbeddingMode.DISABLE
}
val konanVersion: String
@Input get() = project.konanVersion.toString(true, true)
@@ -181,6 +190,12 @@ open class KotlinNativeCompile @Inject constructor(internal val binary: Abstract
add("-Xexport-library=${it.absolutePath}")
}
when (embedBitcode) {
BitcodeEmbeddingMode.MARKER -> add("-Xembed-bitcode-marker")
BitcodeEmbeddingMode.BITCODE -> add("-Xembed-bitcode")
else -> { /* Do nothing. */ }
}
addListArg("-linker-options", linkerOpts)
addAll(sources.files.map { it.absolutePath })
@@ -1132,6 +1132,14 @@ class ExperimentalPluginTests {
assertTrue(result.output.contains("A.a"))
}
private fun BuildResult.checkFrameworkCompilationCommandLine(check: (String) -> Unit) {
output.lineSequence().filter {
it.contains("Run tool: konanc") && it.contains("-p framework")
}.toList().also {
assertTrue(it.isNotEmpty())
}.forEach(check)
}
@Test
fun `Plugin should support symbol exporting for frameworks`() {
assumeTrue(HostManager.hostIsMac)
@@ -1139,6 +1147,7 @@ class ExperimentalPluginTests {
val libraryProject = KonanProject.createEmpty(libraryDir).apply {
buildFile.writeText("""
plugins { id 'kotlin-native' }
components.main.targets = [ 'ios_x64' ]
""".trimIndent())
generateSrcFile("library.kt", "fun foo() = 42")
}
@@ -1156,18 +1165,32 @@ class ExperimentalPluginTests {
}
sourceSets.main.component {
targets = [ 'ios_x64' ]
outputKinds = [ FRAMEWORK ]
}
""".trimIndent())
generateSrcFile("main.kt", "fun main(args: Array<String>) { println(foo()) }")
}
val compileDebugResult = project.createRunner().withArguments("compileDebugKotlinNative").build()
assertEquals(TaskOutcome.SUCCESS, compileDebugResult.task(":compileDebugKotlinNative")?.outcome)
assertEquals(TaskOutcome.SUCCESS, compileDebugResult.task(":library:compileDebugKotlinNative")?.outcome)
assertTrue(projectDirectory.resolve("build/lib/main/debug/test.framework").exists())
val header = projectDirectory.resolve("build/lib/main/debug/test.framework/Headers/test.h")
assertTrue(header.exists())
assertTrue(header.readText().contains("+ (int32_t)foo "))
with(project.createRunner().withArguments("compileDebugKotlinNative", "--info").build()) {
assertEquals(TaskOutcome.SUCCESS, task(":compileDebugKotlinNative")?.outcome)
assertEquals(TaskOutcome.SUCCESS, task(":library:compileDebugKotlinNative")?.outcome)
assertTrue(projectDirectory.resolve("build/lib/main/debug/test.framework").exists())
val header = projectDirectory.resolve("build/lib/main/debug/test.framework/Headers/test.h")
assertTrue(header.exists())
assertTrue(header.readText().contains("+ (int32_t)foo "))
checkFrameworkCompilationCommandLine {
assertTrue(it.contains("-Xembed-bitcode-marker"))
assertTrue(it.contains("-g"))
}
}
with(project.createRunner().withArguments("compileReleaseKotlinNative", "--info").build()) {
assertEquals(TaskOutcome.SUCCESS, task(":compileReleaseKotlinNative")?.outcome)
checkFrameworkCompilationCommandLine {
assertTrue(it.contains("-Xembed-bitcode"))
assertTrue(it.contains("-opt"))
}
}
}
}