[gradle-plugin] Support static and shared libraries (#1942)
This commit is contained in:
+11
-1
@@ -102,10 +102,20 @@ interface KotlinNativeLibrary : KotlinNativeBinary,
|
||||
ConfigurableComponentWithLinkUsage
|
||||
|
||||
/**
|
||||
* Represents an Objective C framework compiled from KN sources.
|
||||
* Represents an Objective C framework compiled from Kotlin/Native sources.
|
||||
*/
|
||||
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.
|
||||
*/
|
||||
|
||||
+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
|
||||
|
||||
companion object {
|
||||
@JvmStatic
|
||||
val EXECUTABLE = OutputKind.EXECUTABLE
|
||||
|
||||
@JvmStatic
|
||||
val KLIBRARY = OutputKind.KLIBRARY
|
||||
|
||||
@JvmStatic
|
||||
val FRAMEWORK = OutputKind.FRAMEWORK
|
||||
@JvmStatic val EXECUTABLE = OutputKind.EXECUTABLE
|
||||
@JvmStatic val KLIBRARY = OutputKind.KLIBRARY
|
||||
@JvmStatic val FRAMEWORK = OutputKind.FRAMEWORK
|
||||
@JvmStatic val DYNAMIC = OutputKind.DYNAMIC
|
||||
@JvmStatic val STATIC = OutputKind.STATIC
|
||||
}
|
||||
}
|
||||
|
||||
+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) =
|
||||
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
|
||||
|
||||
+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.setProperty
|
||||
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.KonanTarget
|
||||
import java.io.File
|
||||
@@ -120,6 +121,18 @@ class KotlinNativeBasePlugin: Plugin<ProjectInternal> {
|
||||
).apply {
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
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.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.experimental.internal.AbstractKotlinNativeBinary
|
||||
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 javax.inject.Inject
|
||||
|
||||
@@ -68,7 +70,11 @@ open class KotlinNativeCompile @Inject constructor(internal val binary: Abstract
|
||||
val baseName = getBaseName().get()
|
||||
|
||||
var fileName = "${prefix}${baseName}${suffix}"
|
||||
if (kind == CompilerOutputKind.FRAMEWORK) {
|
||||
if (kind == FRAMEWORK ||
|
||||
kind == STATIC ||
|
||||
kind == DYNAMIC ||
|
||||
kind == PROGRAM && konanTarget == KonanTarget.WASM32
|
||||
) {
|
||||
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.plugins.KotlinNativePlugin
|
||||
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.KonanTarget
|
||||
import org.junit.Assume.assumeTrue
|
||||
@@ -45,6 +46,9 @@ class ExperimentalPluginTests {
|
||||
project.block()
|
||||
}
|
||||
|
||||
private fun assertFileExists(path: String, message: String = "No such file: $path")
|
||||
= assertTrue(projectDirectory.resolve(path).exists(), message)
|
||||
|
||||
@Test
|
||||
fun `Plugin should compile one executable`() {
|
||||
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()
|
||||
assertCompileOutcome(result1, compileTasks, TaskOutcome.SUCCESS)
|
||||
|
||||
@@ -484,4 +485,72 @@ class ExperimentalPluginTests {
|
||||
assertEquals("test_framework_project", frameworkTask.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