[gradle-plugin] Support static and shared libraries (#1942)
This commit is contained in:
+11
-1
@@ -102,10 +102,20 @@ interface KotlinNativeLibrary : KotlinNativeBinary,
|
|||||||
ConfigurableComponentWithLinkUsage
|
ConfigurableComponentWithLinkUsage
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents an Objective C framework compiled from KN sources.
|
* Represents an Objective C framework compiled from Kotlin/Native sources.
|
||||||
*/
|
*/
|
||||||
interface KotlinNativeFramework : KotlinNativeBinary, ComponentWithOutputs
|
interface KotlinNativeFramework : KotlinNativeBinary, ComponentWithOutputs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A shared library compiled from Kotlin/Native sources.
|
||||||
|
*/
|
||||||
|
interface KotlinNativeDynamic : KotlinNativeBinary, ComponentWithOutputs
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A static library compiled from Kotlin/Native sources.
|
||||||
|
*/
|
||||||
|
interface KotlinNativeStatic : KotlinNativeBinary, ComponentWithOutputs
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Represents a test executable.
|
* Represents a test executable.
|
||||||
*/
|
*/
|
||||||
|
|||||||
+52
@@ -0,0 +1,52 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.plugin.experimental.internal
|
||||||
|
|
||||||
|
import org.gradle.api.artifacts.Configuration
|
||||||
|
import org.gradle.api.artifacts.ConfigurationContainer
|
||||||
|
import org.gradle.api.file.ProjectLayout
|
||||||
|
import org.gradle.api.internal.file.FileOperations
|
||||||
|
import org.gradle.api.model.ObjectFactory
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeDynamic
|
||||||
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
open class KotlinNativeDynamicImpl @Inject constructor(
|
||||||
|
name: String,
|
||||||
|
baseName: Provider<String>,
|
||||||
|
componentImplementation: Configuration,
|
||||||
|
component: KotlinNativeMainComponent,
|
||||||
|
identity: KotlinNativeVariantIdentity,
|
||||||
|
projectLayout: ProjectLayout,
|
||||||
|
objects: ObjectFactory,
|
||||||
|
configurations: ConfigurationContainer,
|
||||||
|
fileOperations: FileOperations
|
||||||
|
) : AbstractKotlinNativeBinary(
|
||||||
|
name,
|
||||||
|
baseName,
|
||||||
|
component,
|
||||||
|
identity,
|
||||||
|
projectLayout,
|
||||||
|
CompilerOutputKind.DYNAMIC,
|
||||||
|
objects,
|
||||||
|
componentImplementation,
|
||||||
|
configurations,
|
||||||
|
fileOperations
|
||||||
|
), KotlinNativeDynamic {
|
||||||
|
override val outputRootName: String = "lib"
|
||||||
|
}
|
||||||
+5
-8
@@ -93,13 +93,10 @@ open class KotlinNativeMainComponent @Inject constructor(
|
|||||||
// endregion
|
// endregion
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
@JvmStatic
|
@JvmStatic val EXECUTABLE = OutputKind.EXECUTABLE
|
||||||
val EXECUTABLE = OutputKind.EXECUTABLE
|
@JvmStatic val KLIBRARY = OutputKind.KLIBRARY
|
||||||
|
@JvmStatic val FRAMEWORK = OutputKind.FRAMEWORK
|
||||||
@JvmStatic
|
@JvmStatic val DYNAMIC = OutputKind.DYNAMIC
|
||||||
val KLIBRARY = OutputKind.KLIBRARY
|
@JvmStatic val STATIC = OutputKind.STATIC
|
||||||
|
|
||||||
@JvmStatic
|
|
||||||
val FRAMEWORK = OutputKind.FRAMEWORK
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+53
@@ -0,0 +1,53 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.gradle.plugin.experimental.internal
|
||||||
|
|
||||||
|
import org.gradle.api.artifacts.Configuration
|
||||||
|
import org.gradle.api.artifacts.ConfigurationContainer
|
||||||
|
import org.gradle.api.file.ProjectLayout
|
||||||
|
import org.gradle.api.internal.file.FileOperations
|
||||||
|
import org.gradle.api.model.ObjectFactory
|
||||||
|
import org.gradle.api.provider.Provider
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeStatic
|
||||||
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
|
||||||
|
open class KotlinNativeStaticImpl @Inject constructor(
|
||||||
|
name: String,
|
||||||
|
baseName: Provider<String>,
|
||||||
|
componentImplementation: Configuration,
|
||||||
|
component: KotlinNativeMainComponent,
|
||||||
|
identity: KotlinNativeVariantIdentity,
|
||||||
|
projectLayout: ProjectLayout,
|
||||||
|
objects: ObjectFactory,
|
||||||
|
configurations: ConfigurationContainer,
|
||||||
|
fileOperations: FileOperations
|
||||||
|
) : AbstractKotlinNativeBinary(
|
||||||
|
name,
|
||||||
|
baseName,
|
||||||
|
component,
|
||||||
|
identity,
|
||||||
|
projectLayout,
|
||||||
|
CompilerOutputKind.STATIC,
|
||||||
|
objects,
|
||||||
|
componentImplementation,
|
||||||
|
configurations,
|
||||||
|
fileOperations
|
||||||
|
), KotlinNativeStatic {
|
||||||
|
override val outputRootName: String = "lib"
|
||||||
|
}
|
||||||
+20
@@ -54,6 +54,26 @@ enum class OutputKind(
|
|||||||
) {
|
) {
|
||||||
override fun availableFor(target: KonanTarget) =
|
override fun availableFor(target: KonanTarget) =
|
||||||
target.family == Family.OSX || target.family == Family.IOS
|
target.family == Family.OSX || target.family == Family.IOS
|
||||||
|
},
|
||||||
|
DYNAMIC(
|
||||||
|
CompilerOutputKind.DYNAMIC,
|
||||||
|
KotlinNativeDynamicImpl::class.java,
|
||||||
|
3,
|
||||||
|
Usage.NATIVE_RUNTIME,
|
||||||
|
Usage.NATIVE_LINK,
|
||||||
|
false
|
||||||
|
) {
|
||||||
|
override fun availableFor(target: KonanTarget): Boolean = target != KonanTarget.WASM32
|
||||||
|
},
|
||||||
|
STATIC(
|
||||||
|
CompilerOutputKind.STATIC,
|
||||||
|
KotlinNativeStaticImpl::class.java,
|
||||||
|
4,
|
||||||
|
Usage.NATIVE_RUNTIME,
|
||||||
|
Usage.NATIVE_LINK,
|
||||||
|
false
|
||||||
|
) {
|
||||||
|
override fun availableFor(target: KonanTarget): Boolean = target != KonanTarget.WASM32
|
||||||
};
|
};
|
||||||
|
|
||||||
open fun availableFor(target: KonanTarget) = true
|
open fun availableFor(target: KonanTarget) = true
|
||||||
|
|||||||
+13
@@ -42,6 +42,7 @@ import org.jetbrains.kotlin.gradle.plugin.hasProperty
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.konanCompilerDownloadDir
|
import org.jetbrains.kotlin.gradle.plugin.konanCompilerDownloadDir
|
||||||
import org.jetbrains.kotlin.gradle.plugin.setProperty
|
import org.jetbrains.kotlin.gradle.plugin.setProperty
|
||||||
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanCompilerDownloadTask
|
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanCompilerDownloadTask
|
||||||
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import java.io.File
|
import java.io.File
|
||||||
@@ -120,6 +121,18 @@ class KotlinNativeBasePlugin: Plugin<ProjectInternal> {
|
|||||||
).apply {
|
).apply {
|
||||||
group = BasePlugin.BUILD_GROUP
|
group = BasePlugin.BUILD_GROUP
|
||||||
description = "Compiles Kotlin/Native source set '${binary.sourceSet.name}' into a ${binary.kind.name.toLowerCase()}"
|
description = "Compiles Kotlin/Native source set '${binary.sourceSet.name}' into a ${binary.kind.name.toLowerCase()}"
|
||||||
|
|
||||||
|
// Register an API header produced for shared/static library as a task output.
|
||||||
|
if (binary.kind == CompilerOutputKind.DYNAMIC || binary.kind == CompilerOutputKind.STATIC) {
|
||||||
|
val headerFileProvider = provider {
|
||||||
|
with(binary) {
|
||||||
|
val prefix = kind.prefix(konanTarget)
|
||||||
|
val baseName = getBaseName().get().replace('-', '_')
|
||||||
|
outputFile.parentFile.resolve("$prefix${baseName}_api.h")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
outputs.file(headerFileProvider)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
binary.compileTask.set(compileTask)
|
binary.compileTask.set(compileTask)
|
||||||
binary.outputs.from(compileTask.outputLocationProvider)
|
binary.outputs.from(compileTask.outputLocationProvider)
|
||||||
|
|||||||
+7
-1
@@ -30,6 +30,8 @@ import org.jetbrains.kotlin.gradle.plugin.addArg
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.addKey
|
import org.jetbrains.kotlin.gradle.plugin.addKey
|
||||||
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeBinary
|
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeBinary
|
||||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind.*
|
||||||
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import java.io.File
|
import java.io.File
|
||||||
import javax.inject.Inject
|
import javax.inject.Inject
|
||||||
|
|
||||||
@@ -68,7 +70,11 @@ open class KotlinNativeCompile @Inject constructor(internal val binary: Abstract
|
|||||||
val baseName = getBaseName().get()
|
val baseName = getBaseName().get()
|
||||||
|
|
||||||
var fileName = "${prefix}${baseName}${suffix}"
|
var fileName = "${prefix}${baseName}${suffix}"
|
||||||
if (kind == CompilerOutputKind.FRAMEWORK) {
|
if (kind == FRAMEWORK ||
|
||||||
|
kind == STATIC ||
|
||||||
|
kind == DYNAMIC ||
|
||||||
|
kind == PROGRAM && konanTarget == KonanTarget.WASM32
|
||||||
|
) {
|
||||||
fileName = fileName.replace('-', '_')
|
fileName = fileName.replace('-', '_')
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.gradle.plugin.experimental.internal.KotlinNativeMain
|
|||||||
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.OutputKind
|
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.OutputKind
|
||||||
import org.jetbrains.kotlin.gradle.plugin.experimental.plugins.KotlinNativePlugin
|
import org.jetbrains.kotlin.gradle.plugin.experimental.plugins.KotlinNativePlugin
|
||||||
import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile
|
import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile
|
||||||
|
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||||
import org.jetbrains.kotlin.konan.target.HostManager
|
import org.jetbrains.kotlin.konan.target.HostManager
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||||
import org.junit.Assume.assumeTrue
|
import org.junit.Assume.assumeTrue
|
||||||
@@ -45,6 +46,9 @@ class ExperimentalPluginTests {
|
|||||||
project.block()
|
project.block()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun assertFileExists(path: String, message: String = "No such file: $path")
|
||||||
|
= assertTrue(projectDirectory.resolve(path).exists(), message)
|
||||||
|
|
||||||
@Test
|
@Test
|
||||||
fun `Plugin should compile one executable`() {
|
fun `Plugin should compile one executable`() {
|
||||||
val project = KonanProject.create(projectDirectory).apply {
|
val project = KonanProject.create(projectDirectory).apply {
|
||||||
@@ -457,9 +461,6 @@ class ExperimentalPluginTests {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val ttt = project.createRunner().withArguments("tasks").build()
|
|
||||||
println(ttt.output)
|
|
||||||
|
|
||||||
val result1 = project.createRunner().withArguments("assemble").build()
|
val result1 = project.createRunner().withArguments("assemble").build()
|
||||||
assertCompileOutcome(result1, compileTasks, TaskOutcome.SUCCESS)
|
assertCompileOutcome(result1, compileTasks, TaskOutcome.SUCCESS)
|
||||||
|
|
||||||
@@ -484,4 +485,72 @@ class ExperimentalPluginTests {
|
|||||||
assertEquals("test_framework_project", frameworkTask.outputFile.nameWithoutExtension)
|
assertEquals("test_framework_project", frameworkTask.outputFile.nameWithoutExtension)
|
||||||
assertEquals("test-framework-project", klibraryTask.outputFile.nameWithoutExtension)
|
assertEquals("test-framework-project", klibraryTask.outputFile.nameWithoutExtension)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun `Plugin should be able to build static and dynamic libraries`() {
|
||||||
|
|
||||||
|
val project = KonanProject.create(projectDirectory).apply {
|
||||||
|
buildFile.writeText("""
|
||||||
|
plugins { id 'kotlin-native' }
|
||||||
|
|
||||||
|
sourceSets.main {
|
||||||
|
component {
|
||||||
|
outputKinds = [ DYNAMIC, STATIC ]
|
||||||
|
target 'host'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
""".trimIndent())
|
||||||
|
settingsFile.appendText("\nrootProject.name = 'test-library'")
|
||||||
|
}
|
||||||
|
|
||||||
|
val baseName = "test_library"
|
||||||
|
val sharedPrefix = CompilerOutputKind.DYNAMIC.prefix(HostManager.host)
|
||||||
|
val sharedSuffix = CompilerOutputKind.DYNAMIC.suffix(HostManager.host)
|
||||||
|
val staticPrefix = CompilerOutputKind.STATIC.prefix(HostManager.host)
|
||||||
|
val staticSuffix = CompilerOutputKind.STATIC.suffix(HostManager.host)
|
||||||
|
|
||||||
|
val libraryPaths = listOf(
|
||||||
|
"build/lib/main/debug/dynamic/$sharedPrefix$baseName$sharedSuffix",
|
||||||
|
"build/lib/main/release/dynamic/$sharedPrefix$baseName$sharedSuffix",
|
||||||
|
"build/lib/main/debug/static/$staticPrefix$baseName$staticSuffix",
|
||||||
|
"build/lib/main/release/static/$staticPrefix$baseName$staticSuffix"
|
||||||
|
)
|
||||||
|
|
||||||
|
val headerPaths = listOf(
|
||||||
|
"build/lib/main/debug/dynamic/$sharedPrefix${baseName}_api.h",
|
||||||
|
"build/lib/main/release/dynamic/$sharedPrefix${baseName}_api.h",
|
||||||
|
"build/lib/main/debug/static/$staticPrefix${baseName}_api.h",
|
||||||
|
"build/lib/main/release/static/$staticPrefix${baseName}_api.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
val linkTasks = listOf(
|
||||||
|
":compileDebugDynamicKotlinNative",
|
||||||
|
":compileReleaseDynamicKotlinNative",
|
||||||
|
":compileDebugStaticKotlinNative",
|
||||||
|
":compileReleaseStaticKotlinNative"
|
||||||
|
)
|
||||||
|
|
||||||
|
project.createRunner().withArguments("assemble", "-i").build().let { result ->
|
||||||
|
libraryPaths.forEach { assertFileExists(it) }
|
||||||
|
headerPaths.forEach { assertFileExists(it) }
|
||||||
|
linkTasks.forEach { assertEquals(TaskOutcome.SUCCESS, result.task(it)!!.outcome) }
|
||||||
|
}
|
||||||
|
|
||||||
|
project.createRunner().withArguments("assemble").build().let { result ->
|
||||||
|
linkTasks.forEach { assertEquals(TaskOutcome.UP_TO_DATE, result.task(it)!!.outcome) }
|
||||||
|
}
|
||||||
|
|
||||||
|
assertTrue(projectDirectory.resolve(headerPaths[0]).delete())
|
||||||
|
|
||||||
|
project.createRunner().withArguments("assemble").build().let { result ->
|
||||||
|
assertEquals(TaskOutcome.SUCCESS, result.task(linkTasks[0])!!.outcome)
|
||||||
|
linkTasks.drop(1).forEach {
|
||||||
|
assertEquals(TaskOutcome.UP_TO_DATE, result.task(it)!!.outcome)
|
||||||
|
}
|
||||||
|
|
||||||
|
libraryPaths.forEach { assertFileExists(it) }
|
||||||
|
headerPaths.forEach { assertFileExists(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Reference in New Issue
Block a user