From d5ef60165828444aa6723f32d320ab16325d8556 Mon Sep 17 00:00:00 2001 From: Ilya Matveev Date: Mon, 17 Dec 2018 19:57:31 +0700 Subject: [PATCH] Support bitcode embedding in Gradle plugin --- .../experimental/KotlinNativeBinaries.kt | 8 ++-- .../internal/KotlinNativeBuildType.kt | 18 +++++++-- .../internal/KotlinNativeFrameworkImpl.kt | 9 ++++- .../experimental/tasks/KotlinNativeCompile.kt | 15 ++++++++ .../test/kotlin/ExperimentalPluginTests.kt | 37 +++++++++++++++---- 5 files changed, 72 insertions(+), 15 deletions(-) diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/KotlinNativeBinaries.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/KotlinNativeBinaries.kt index 1a679e829f5..25d1042befa 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/KotlinNativeBinaries.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/KotlinNativeBinaries.kt @@ -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 } /** diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeBuildType.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeBuildType.kt index f894581dff6..76527430a2b 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeBuildType.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeBuildType.kt @@ -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 = Arrays.asList(DEBUG, RELEASE) } -} \ No newline at end of file +} + +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, +} diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeFrameworkImpl.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeFrameworkImpl.kt index dc41a659e8a..6a6896cb075 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeFrameworkImpl.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/internal/KotlinNativeFrameworkImpl.kt @@ -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, @@ -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 + } } \ No newline at end of file diff --git a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/tasks/KotlinNativeCompile.kt b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/tasks/KotlinNativeCompile.kt index 884c978438b..36eb8a1d9dd 100644 --- a/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/tasks/KotlinNativeCompile.kt +++ b/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/experimental/tasks/KotlinNativeCompile.kt @@ -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 }) diff --git a/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt b/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt index 3252e3056eb..ed33b31c98c 100644 --- a/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt +++ b/tools/kotlin-native-gradle-plugin/src/test/kotlin/ExperimentalPluginTests.kt @@ -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) { 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")) + } + } } }