[gradle-plugin] Support basic cinterop

This commit is contained in:
Ilya Matveev
2018-08-28 11:40:30 +07:00
committed by Ilya Matveev
parent 8092abc2b9
commit c012aa5d32
18 changed files with 552 additions and 32 deletions
@@ -0,0 +1,69 @@
/*
* 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
import groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.Named
import org.gradle.api.file.FileCollection
import org.jetbrains.kotlin.konan.target.KonanTarget
interface CInteropSettings {
interface IncludeDirectories {
fun allHeaders(vararg includeDirs: Any)
fun allHeaders(includeDirs: Collection<Any>)
fun headerFilterOnly(vararg includeDirs: Any)
fun headerFilterOnly(includeDirs: Collection<Any>)
}
fun defFile(file: Any)
fun packageName(value: String)
fun header(file: Any) = headers(file)
fun headers(vararg files: Any)
fun headers(files: FileCollection)
fun includeDirs(vararg values: Any)
fun includeDirs(closure: Closure<Unit>)
fun includeDirs(action: Action<IncludeDirectories>)
fun includeDirs(configure: IncludeDirectories.() -> Unit)
fun compilerOpts(vararg values: String)
fun compilerOpts(values: List<String>)
fun linkerOpts(vararg values: String)
fun linkerOpts(values: List<String>)
fun extraOpts(vararg values: Any)
fun extraOpts(values: List<Any>)
}
interface CInterop : Named, CInteropSettings {
fun target(target: String): CInteropSettings
fun target(target: KonanTarget): CInteropSettings
fun target(target: String, action: CInteropSettings.() -> Unit)
fun target(target: String, action: Closure<Unit>)
fun target(target: String, action: Action<CInteropSettings>)
fun target(target: KonanTarget, action: CInteropSettings.() -> Unit)
fun target(target: KonanTarget, action: Closure<Unit>)
fun target(target: KonanTarget, action: Action<CInteropSettings>)
}
@@ -16,22 +16,15 @@
package org.jetbrains.kotlin.gradle.plugin.experimental package org.jetbrains.kotlin.gradle.plugin.experimental
import org.gradle.api.artifacts.Configuration
import org.gradle.api.attributes.Attribute import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.AttributeContainer
import org.gradle.api.component.BuildableComponent import org.gradle.api.component.BuildableComponent
import org.gradle.api.component.PublishableComponent import org.gradle.api.component.PublishableComponent
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.file.RegularFile
import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.language.ComponentWithDependencies import org.gradle.language.ComponentWithDependencies
import org.gradle.language.ComponentWithOutputs import org.gradle.language.ComponentWithOutputs
import org.gradle.language.nativeplatform.ComponentWithLinkUsage
import org.gradle.language.nativeplatform.internal.ComponentWithNames
import org.gradle.language.nativeplatform.internal.ConfigurableComponentWithLinkUsage import org.gradle.language.nativeplatform.internal.ConfigurableComponentWithLinkUsage
import org.gradle.language.nativeplatform.internal.ConfigurableComponentWithRuntimeUsage import org.gradle.language.nativeplatform.internal.ConfigurableComponentWithRuntimeUsage
import org.gradle.nativeplatform.Linkage
import org.gradle.nativeplatform.test.TestComponent import org.gradle.nativeplatform.test.TestComponent
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.KotlinNativePlatform import org.jetbrains.kotlin.gradle.plugin.experimental.internal.KotlinNativePlatform
import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile
@@ -16,18 +16,27 @@
package org.jetbrains.kotlin.gradle.plugin.experimental package org.jetbrains.kotlin.gradle.plugin.experimental
import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.api.provider.SetProperty import org.gradle.api.provider.SetProperty
import org.gradle.api.publish.maven.MavenPom import org.gradle.api.publish.maven.MavenPom
import org.gradle.language.BinaryCollection import org.gradle.language.BinaryCollection
import org.gradle.language.ComponentDependencies
import org.gradle.language.ComponentWithBinaries import org.gradle.language.ComponentWithBinaries
import org.gradle.language.ComponentWithDependencies import org.gradle.language.ComponentWithDependencies
import org.gradle.nativeplatform.test.TestSuiteComponent import org.gradle.nativeplatform.test.TestSuiteComponent
import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSet import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSet
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
interface KotlinNativeDependencies: ComponentDependencies {
fun cinterop(name: String): CInterop
fun cinterop(name: String, action: CInterop.() -> Unit)
fun cinterop(name: String, action: Closure<Unit>)
fun cinterop(name: String, action: Action<CInterop>)
}
/** /**
* Class representing a Kotlin/Native component: application or library (both klib and dynamic) * Class representing a Kotlin/Native component: application or library (both klib and dynamic)
* built for different targets. * built for different targets.
@@ -52,6 +61,13 @@ interface KotlinNativeComponent: ComponentWithBinaries, ComponentWithDependencie
// region DSL // region DSL
/** Provides an access to component's dependencies including cinterop and jsinterop DSL */
override fun getDependencies(): KotlinNativeDependencies
fun dependencies(action: KotlinNativeDependencies.() -> Unit)
fun dependencies(action: Closure<Unit>)
fun dependencies(action: Action<KotlinNativeDependencies>)
/** Set native targets for this component. */ /** Set native targets for this component. */
fun target(vararg targets: String) fun target(vararg targets: String)
@@ -37,7 +37,6 @@ import org.gradle.nativeplatform.OperatingSystemFamily
import org.gradle.nativeplatform.toolchain.NativeToolChain import org.gradle.nativeplatform.toolchain.NativeToolChain
import org.jetbrains.kotlin.gradle.plugin.experimental.ComponentWithBaseName import org.jetbrains.kotlin.gradle.plugin.experimental.ComponentWithBaseName
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeBinary import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeBinary
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeComponent
import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSet import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSet
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.CompilerOutputKind
@@ -94,8 +93,8 @@ abstract class AbstractKotlinNativeBinary(
get() = sourceSet.getAllSources(konanTarget) get() = sourceSet.getAllSources(konanTarget)
private val dependencies = objects.newInstance<DefaultComponentDependencies>( private val dependencies = objects.newInstance<DefaultComponentDependencies>(
DefaultComponentDependencies::class.java, DefaultComponentDependencies::class.java,
name + "Implementation" name + "Implementation"
).apply { ).apply {
implementationDependencies.extendsFrom(componentImplementation) implementationDependencies.extendsFrom(componentImplementation)
} }
@@ -16,7 +16,9 @@
package org.jetbrains.kotlin.gradle.plugin.experimental.internal package org.jetbrains.kotlin.gradle.plugin.experimental.internal
import groovy.lang.Closure
import org.gradle.api.Action import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.artifacts.Configuration import org.gradle.api.artifacts.Configuration
import org.gradle.api.internal.file.FileOperations import org.gradle.api.internal.file.FileOperations
import org.gradle.api.internal.provider.LockableSetProperty import org.gradle.api.internal.provider.LockableSetProperty
@@ -24,20 +26,23 @@ import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.publish.maven.MavenPom import org.gradle.api.publish.maven.MavenPom
import org.gradle.language.internal.DefaultBinaryCollection import org.gradle.language.internal.DefaultBinaryCollection
import org.gradle.language.internal.DefaultComponentDependencies
import org.gradle.language.nativeplatform.internal.ComponentWithNames import org.gradle.language.nativeplatform.internal.ComponentWithNames
import org.gradle.language.nativeplatform.internal.DefaultNativeComponent import org.gradle.language.nativeplatform.internal.DefaultNativeComponent
import org.gradle.language.nativeplatform.internal.Names import org.gradle.language.nativeplatform.internal.Names
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeBinary import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeBinary
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeComponent import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeComponent
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeDependencies
import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSetImpl import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSetImpl
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.jetbrains.kotlin.utils.addToStdlib.assertedCast
import javax.inject.Inject import javax.inject.Inject
abstract class AbstractKotlinNativeComponent @Inject constructor( abstract class AbstractKotlinNativeComponent @Inject constructor(
private val name: String, private val name: String,
override val sources: KotlinNativeSourceSetImpl, override val sources: KotlinNativeSourceSetImpl,
val project: Project,
val objectFactory: ObjectFactory, val objectFactory: ObjectFactory,
fileOperations: FileOperations fileOperations: FileOperations
) : DefaultNativeComponent(fileOperations), ) : DefaultNativeComponent(fileOperations),
@@ -62,9 +67,10 @@ abstract class AbstractKotlinNativeComponent @Inject constructor(
private val names = Names.of(name) private val names = Names.of(name)
override fun getNames(): Names = names override fun getNames(): Names = names
private val dependencies: DefaultComponentDependencies = objectFactory.newInstance( private val dependencies: KotlinNativeDependenciesImpl = objectFactory.newInstance(
DefaultComponentDependencies::class.java, KotlinNativeDependenciesImpl::class.java,
names.withSuffix("implementation")) project,
names.withSuffix("implementation"))
internal val poms = mutableListOf<Action<MavenPom>>() internal val poms = mutableListOf<Action<MavenPom>>()
override fun getDependencies() = dependencies override fun getDependencies() = dependencies
@@ -92,5 +98,16 @@ abstract class AbstractKotlinNativeComponent @Inject constructor(
override var publishJavadoc: Boolean = true override var publishJavadoc: Boolean = true
override var publishSources: Boolean = true override var publishSources: Boolean = true
override fun dependencies(action: KotlinNativeDependencies.() -> Unit) {
dependencies.action()
}
override fun dependencies(action: Closure<Unit>) =
dependencies(ConfigureUtil.configureUsing(action))
override fun dependencies(action: Action<KotlinNativeDependencies>) {
action.execute(dependencies)
}
// endregion // endregion
} }
@@ -0,0 +1,54 @@
/*
* 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 groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.Project
import org.gradle.api.artifacts.ConfigurationContainer
import org.gradle.language.internal.DefaultComponentDependencies
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.experimental.CInterop
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeDependencies
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.cinterop.CInteropImpl
import javax.inject.Inject
open class KotlinNativeDependenciesImpl @Inject constructor(
private val project: Project,
configurations: ConfigurationContainer,
implementationName: String
) : DefaultComponentDependencies(configurations, implementationName),
KotlinNativeDependencies {
internal val cinterops = project.container(CInteropImpl::class.java) { name ->
CInteropImpl(project, name)
}
override fun cinterop(name: String) = cinterops.maybeCreate(name)
override fun cinterop(name: String, action: CInterop.() -> Unit) {
cinterop(name).apply { action() }
}
override fun cinterop(name: String, action: Closure<Unit>) {
cinterop(name, ConfigureUtil.configureUsing(action))
}
override fun cinterop(name: String, action: Action<CInterop>) {
cinterop(name).apply { action.execute(this) }
}
}
@@ -32,7 +32,6 @@ import org.gradle.api.provider.Provider
import org.gradle.language.cpp.internal.DefaultUsageContext import org.gradle.language.cpp.internal.DefaultUsageContext
import org.gradle.nativeplatform.Linkage import org.gradle.nativeplatform.Linkage
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeExecutable import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeExecutable
import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSet
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import javax.inject.Inject import javax.inject.Inject
@@ -31,7 +31,6 @@ import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.gradle.language.cpp.internal.DefaultUsageContext import org.gradle.language.cpp.internal.DefaultUsageContext
import org.gradle.nativeplatform.Linkage import org.gradle.nativeplatform.Linkage
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeFramework
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeLibrary import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeLibrary
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import javax.inject.Inject import javax.inject.Inject
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.gradle.plugin.experimental.internal package org.jetbrains.kotlin.gradle.plugin.experimental.internal
import org.gradle.api.Project
import org.gradle.api.component.ComponentWithVariants import org.gradle.api.component.ComponentWithVariants
import org.gradle.api.component.SoftwareComponent import org.gradle.api.component.SoftwareComponent
import org.gradle.api.internal.component.SoftwareComponentInternal import org.gradle.api.internal.component.SoftwareComponentInternal
@@ -36,9 +37,10 @@ import javax.inject.Inject
open class KotlinNativeMainComponent @Inject constructor( open class KotlinNativeMainComponent @Inject constructor(
name: String, name: String,
sources: KotlinNativeSourceSetImpl, sources: KotlinNativeSourceSetImpl,
project: Project,
objectFactory: ObjectFactory, objectFactory: ObjectFactory,
fileOperations: FileOperations fileOperations: FileOperations
) : AbstractKotlinNativeComponent(name, sources, objectFactory, fileOperations), ) : AbstractKotlinNativeComponent(name, sources, project, objectFactory, fileOperations),
PublicationAwareComponent, PublicationAwareComponent,
ProductionComponent { ProductionComponent {
@@ -25,7 +25,6 @@ import org.gradle.api.internal.file.FileOperations
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
import org.gradle.api.provider.Provider import org.gradle.api.provider.Provider
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeTestComponent
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeTestExecutable import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeTestExecutable
import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSet import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSourceSet
import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.CompilerOutputKind
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.gradle.plugin.experimental.internal package org.jetbrains.kotlin.gradle.plugin.experimental.internal
import org.gradle.api.Project
import org.gradle.api.internal.file.FileOperations import org.gradle.api.internal.file.FileOperations
import org.gradle.api.model.ObjectFactory import org.gradle.api.model.ObjectFactory
import org.gradle.api.provider.Property import org.gradle.api.provider.Property
@@ -29,12 +30,13 @@ import org.jetbrains.kotlin.gradle.plugin.experimental.sourcesets.KotlinNativeSo
import javax.inject.Inject import javax.inject.Inject
open class KotlinNativeTestSuite @Inject constructor( open class KotlinNativeTestSuite @Inject constructor(
name: String, name: String,
sources: KotlinNativeSourceSetImpl, sources: KotlinNativeSourceSetImpl,
override val testedComponent: KotlinNativeComponent, override val testedComponent: KotlinNativeComponent,
objectFactory: ObjectFactory, project: Project,
fileOperations: FileOperations objectFactory: ObjectFactory,
) : AbstractKotlinNativeComponent(name, sources, objectFactory, fileOperations), fileOperations: FileOperations
) : AbstractKotlinNativeComponent(name, sources, project, objectFactory, fileOperations),
KotlinNativeTestComponent { KotlinNativeTestComponent {
init { init {
@@ -0,0 +1,96 @@
/*
* 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.cinterop
import groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.DomainObjectCollection
import org.gradle.api.NamedDomainObjectContainer
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.experimental.CInterop
import org.jetbrains.kotlin.gradle.plugin.experimental.CInteropSettings
import org.jetbrains.kotlin.gradle.plugin.experimental.CInteropSettings.IncludeDirectories
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
import javax.inject.Inject
open class CInteropImpl @Inject constructor(
private val project: Project,
private val name: String
): CInterop {
private val String.konanTarget: KonanTarget
get() = HostManager().targetByName(this)
override fun getName(): String = name
private val platformSettings: DomainObjectCollection<CInteropSettingsImpl> =
project.container(CInteropSettingsImpl::class.java)
private val targetToSettings: MutableMap<KonanTarget, CInteropSettingsImpl> = mutableMapOf()
// DSL.
override fun target(target: String): CInteropSettings = target(target.konanTarget)
override fun target(target: KonanTarget): CInteropSettings =
targetToSettings.getOrPut(target) {
CInteropSettingsImpl(project, name, target).also {
platformSettings.add(it)
}
}
override fun target(target: String, action: CInteropSettings.() -> Unit) = target(target.konanTarget, action)
override fun target(target: String, action: Closure<Unit>) = target(target.konanTarget, action)
override fun target(target: String, action: Action<CInteropSettings>) = target(target.konanTarget, action)
override fun target(target: KonanTarget, action: CInteropSettings.() -> Unit) =
target(target).action()
override fun target(target: KonanTarget, action: Closure<Unit>) =
target(target, ConfigureUtil.configureUsing(action))
override fun target(target: KonanTarget, action: Action<CInteropSettings>) {
action.execute(target(target))
}
override fun defFile(file: Any) = platformSettings.all { it.defFile(file) }
override fun packageName(value: String) = platformSettings.all { it.packageName(value) }
override fun headers(vararg files: Any) = platformSettings.all { it.headers(*files) }
override fun headers(files: FileCollection) = platformSettings.all { it.headers(files) }
override fun includeDirs(vararg values: Any) =
platformSettings.all {it.includeDirs(*values) }
override fun includeDirs(closure: Closure<Unit>) =
platformSettings.all { it.includeDirs(closure) }
override fun includeDirs(action: Action<IncludeDirectories>) =
platformSettings.all { it.includeDirs(action) }
override fun includeDirs(configure: IncludeDirectories.() -> Unit) =
platformSettings.all { it.includeDirs(configure) }
override fun compilerOpts(vararg values: String) = platformSettings.all { it.compilerOpts(*values) }
override fun compilerOpts(values: List<String>) = platformSettings.all { it.compilerOpts(values) }
override fun linkerOpts(vararg values: String) = platformSettings.all { it.linkerOpts(*values) }
override fun linkerOpts(values: List<String>) = platformSettings.all { it.linkerOpts(values) }
override fun extraOpts(vararg values: Any) = platformSettings.all { it.extraOpts(*values) }
override fun extraOpts(values: List<Any>) = platformSettings.all { it.extraOpts(values) }
}
@@ -0,0 +1,100 @@
/*
* 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.cinterop
import groovy.lang.Closure
import org.gradle.api.Action
import org.gradle.api.Named
import org.gradle.api.Project
import org.gradle.api.file.FileCollection
import org.gradle.util.ConfigureUtil
import org.jetbrains.kotlin.gradle.plugin.experimental.CInteropSettings
import org.jetbrains.kotlin.gradle.plugin.experimental.CInteropSettings.IncludeDirectories
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
import javax.inject.Inject
open class CInteropSettingsImpl @Inject constructor(
private val project: Project,
val baseName: String,
val konanTarget: KonanTarget
) : CInteropSettings,
Named
{
inner class IncludeDirectoriesSpecImpl: IncludeDirectories {
var allHeadersDirs: FileCollection = project.files()
var headerFilterDirs: FileCollection = project.files()
override fun allHeaders(vararg includeDirs: Any) = allHeaders(includeDirs.toList())
override fun allHeaders(includeDirs: Collection<Any>) {
allHeadersDirs += project.files(*includeDirs.toTypedArray())
}
override fun headerFilterOnly(vararg includeDirs: Any) = headerFilterOnly(includeDirs.toList())
override fun headerFilterOnly(includeDirs: Collection<Any>) {
headerFilterDirs += project.files(*includeDirs.toTypedArray())
}
}
override fun getName(): String = "$baseName${konanTarget.name.capitalize()}"
var defFile: File = project.projectDir.resolve("src/main/c_interop/$baseName.def")
var packageName: String? = null
val compilerOpts = mutableListOf<String>()
val linkerOpts = mutableListOf<String>()
val extraOpts = mutableListOf<String>()
val includeDirs = IncludeDirectoriesSpecImpl()
var headers: FileCollection = project.files()
// DSL methods.
override fun defFile(file: Any) {
defFile = project.file(file)
}
override fun packageName(value: String) {
packageName = value
}
override fun header(file: Any) = headers(file)
override fun headers(vararg files: Any) = headers(project.files(files))
override fun headers(files: FileCollection) {
headers += files
}
override fun includeDirs(vararg values: Any) = includeDirs.allHeaders(values.toList())
override fun includeDirs(closure: Closure<Unit>) = includeDirs(ConfigureUtil.configureUsing(closure))
override fun includeDirs(action: Action<IncludeDirectories>) = includeDirs { action.execute(this) }
override fun includeDirs(configure: IncludeDirectories.() -> Unit) = includeDirs.configure()
override fun compilerOpts(vararg values: String) = compilerOpts(values.toList())
override fun compilerOpts(values: List<String>) {
compilerOpts.addAll(values)
}
override fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
override fun linkerOpts(values: List<String>) {
linkerOpts.addAll(values)
}
override fun extraOpts(vararg values: Any) = extraOpts(values.toList())
override fun extraOpts(values: List<Any>) {
extraOpts.addAll(values.map { it.toString() })
}
}
@@ -20,23 +20,21 @@ import org.gradle.api.DefaultTask
import org.gradle.api.Plugin import org.gradle.api.Plugin
import org.gradle.api.Project import org.gradle.api.Project
import org.gradle.api.Task import org.gradle.api.Task
import org.gradle.api.component.SoftwareComponentContainer
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.file.RegularFile
import org.gradle.api.file.RegularFileProperty import org.gradle.api.file.RegularFileProperty
import org.gradle.api.internal.FeaturePreviews import org.gradle.api.internal.FeaturePreviews
import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.internal.project.ProjectInternal
import org.gradle.api.plugins.BasePlugin import org.gradle.api.plugins.BasePlugin
import org.gradle.api.plugins.HelpTasksPlugin import org.gradle.api.plugins.HelpTasksPlugin
import org.gradle.api.provider.Provider
import org.gradle.api.provider.ProviderFactory
import org.gradle.api.tasks.TaskContainer import org.gradle.api.tasks.TaskContainer
import org.gradle.language.base.plugins.LifecycleBasePlugin import org.gradle.language.base.plugins.LifecycleBasePlugin
import org.gradle.language.plugins.NativeBasePlugin import org.gradle.language.plugins.NativeBasePlugin
import org.gradle.nativeplatform.test.tasks.RunTestExecutable import org.gradle.nativeplatform.test.tasks.RunTestExecutable
import org.gradle.util.GradleVersion import org.gradle.util.GradleVersion
import org.jetbrains.kotlin.gradle.plugin.KonanPlugin import org.jetbrains.kotlin.gradle.plugin.KonanPlugin
import org.jetbrains.kotlin.gradle.plugin.experimental.CInteropSettings
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.* import org.jetbrains.kotlin.gradle.plugin.experimental.internal.*
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.cinterop.CInteropSettingsImpl
import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.CInteropTask
import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile import org.jetbrains.kotlin.gradle.plugin.experimental.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.gradle.plugin.hasProperty import org.jetbrains.kotlin.gradle.plugin.hasProperty
import org.jetbrains.kotlin.gradle.plugin.konanCompilerDownloadDir import org.jetbrains.kotlin.gradle.plugin.konanCompilerDownloadDir
@@ -45,7 +43,6 @@ import org.jetbrains.kotlin.gradle.plugin.tasks.KonanCompilerDownloadTask
import org.jetbrains.kotlin.konan.target.CompilerOutputKind 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
class KotlinNativeBasePlugin: Plugin<ProjectInternal> { class KotlinNativeBasePlugin: Plugin<ProjectInternal> {
@@ -83,6 +80,18 @@ class KotlinNativeBasePlugin: Plugin<ProjectInternal> {
private val KonanTarget.canRunOnHost: Boolean private val KonanTarget.canRunOnHost: Boolean
get() = this == HostManager.host get() = this == HostManager.host
private fun lowerCamelCase(vararg components: String) =
if (components.isEmpty()) {
""
} else {
buildString {
append(components[0].decapitalize())
for (i in 1 until components.size) {
append(components[i].capitalize())
}
}
}
private fun Project.addTargetInfoTask() = tasks.create("targets").apply { private fun Project.addTargetInfoTask() = tasks.create("targets").apply {
group = HelpTasksPlugin.HELP_GROUP group = HelpTasksPlugin.HELP_GROUP
description = "Prints Kotlin/Native targets available for this project" description = "Prints Kotlin/Native targets available for this project"
@@ -174,6 +183,31 @@ class KotlinNativeBasePlugin: Plugin<ProjectInternal> {
} }
} }
private fun Project.addInteropTasks() {
val settingsToTask = mutableMapOf<CInteropSettings, CInteropTask>()
components.withType(AbstractKotlinNativeBinary::class.java) { binary ->
binary.component.dependencies.cinterops.all { cinterop ->
val konanTarget = binary.konanTarget
val settings = cinterop.target(konanTarget)
val interopTask = settingsToTask.getOrPut(settings) {
tasks.create(
lowerCamelCase("cinterop", cinterop.name, konanTarget.name),
CInteropTask::class.java,
settings
).apply {
group = INTEROP_GROUP
description = "Generates Kotlin/Native interop library '${cinterop.name}' for target '${konanTarget.name}'"
}
}
binary.klibraries.dependencies.add(dependencies.create(files(interopTask.outputFileProvider)))
}
}
}
private fun ProjectInternal.checkGradleMetadataFeature() { private fun ProjectInternal.checkGradleMetadataFeature() {
val metadataEnabled = gradle.services val metadataEnabled = gradle.services
.get(FeaturePreviews::class.java) .get(FeaturePreviews::class.java)
@@ -213,12 +247,15 @@ class KotlinNativeBasePlugin: Plugin<ProjectInternal> {
addCompilerDownloadingTask() addCompilerDownloadingTask()
addCompilationTasks() addCompilationTasks()
addInteropTasks()
addTargetInfoTask() addTargetInfoTask()
} }
companion object { companion object {
const val LANGUAGE_NAME = "KotlinNative" const val LANGUAGE_NAME = "KotlinNative"
const val SOURCE_SETS_EXTENSION = "sourceSets" const val SOURCE_SETS_EXTENSION = "sourceSets"
const val INTEROP_GROUP = "interop"
} }
} }
@@ -265,7 +265,7 @@ class KotlinNativePlugin @Inject constructor(val attributesFactory: ImmutableAtt
val mainSourceSet = sourceSets.create(MAIN_SOURCE_SET_NAME).apply { val mainSourceSet = sourceSets.create(MAIN_SOURCE_SET_NAME).apply {
kotlin.srcDir("src/$MAIN_SOURCE_SET_NAME/kotlin") kotlin.srcDir("src/$MAIN_SOURCE_SET_NAME/kotlin")
component = objectFactory component = objectFactory
.newInstance(KotlinNativeMainComponent::class.java, name, this) .newInstance(KotlinNativeMainComponent::class.java, name, this, project)
.apply { .apply {
// Override the default component base name. // Override the default component base name.
baseName.set(project.name) baseName.set(project.name)
@@ -276,7 +276,7 @@ class KotlinNativePlugin @Inject constructor(val attributesFactory: ImmutableAtt
sourceSets.create(TEST_SOURCE_SET_NAME).apply { sourceSets.create(TEST_SOURCE_SET_NAME).apply {
kotlin.srcDir("src/$TEST_SOURCE_SET_NAME/kotlin") kotlin.srcDir("src/$TEST_SOURCE_SET_NAME/kotlin")
component = objectFactory component = objectFactory
.newInstance(KotlinNativeTestSuite::class.java, name, this, mainSourceSet.component) .newInstance(KotlinNativeTestSuite::class.java, name, this, mainSourceSet.component, project)
.apply { .apply {
project.components.add(this) project.components.add(this)
} }
@@ -22,6 +22,7 @@ import org.gradle.api.Named
import org.gradle.api.file.FileCollection import org.gradle.api.file.FileCollection
import org.gradle.api.file.SourceDirectorySet import org.gradle.api.file.SourceDirectorySet
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeComponent import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeComponent
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeDependencies
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeComponent import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeComponent
import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -59,4 +60,10 @@ interface KotlinNativeSourceSet: Named {
fun target(targets: Iterable<String>, configureClosure: Closure<*>): KotlinNativeSourceSet fun target(targets: Iterable<String>, configureClosure: Closure<*>): KotlinNativeSourceSet
fun target(targets: Iterable<String>, configureAction: Action<in SourceDirectorySet>): KotlinNativeSourceSet fun target(targets: Iterable<String>, configureAction: Action<in SourceDirectorySet>): KotlinNativeSourceSet
fun target(targets: Iterable<String>, configureLambda: SourceDirectorySet.() -> Unit): KotlinNativeSourceSet fun target(targets: Iterable<String>, configureLambda: SourceDirectorySet.() -> Unit): KotlinNativeSourceSet
val dependencies: KotlinNativeDependencies
fun dependencies(action: KotlinNativeDependencies.() -> Unit)
fun dependencies(action: Closure<Unit>)
fun dependencies(action: Action<KotlinNativeDependencies>)
} }
@@ -24,6 +24,7 @@ import org.gradle.api.file.SourceDirectorySet
import org.gradle.api.internal.file.SourceDirectorySetFactory import org.gradle.api.internal.file.SourceDirectorySetFactory
import org.gradle.api.internal.project.ProjectInternal import org.gradle.api.internal.project.ProjectInternal
import org.gradle.util.ConfigureUtil.configure import org.gradle.util.ConfigureUtil.configure
import org.jetbrains.kotlin.gradle.plugin.experimental.KotlinNativeDependencies
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeComponent import org.jetbrains.kotlin.gradle.plugin.experimental.internal.AbstractKotlinNativeComponent
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
@@ -105,5 +106,13 @@ open class KotlinNativeSourceSetImpl @Inject constructor(
override fun target(vararg targets: String, configureAction: Action<in SourceDirectorySet>) = override fun target(vararg targets: String, configureAction: Action<in SourceDirectorySet>) =
target(targets.toList(), configureAction) target(targets.toList(), configureAction)
override val dependencies: KotlinNativeDependencies
get() = component.dependencies
override fun dependencies(action: KotlinNativeDependencies.() -> Unit) = component.dependencies(action)
override fun dependencies(action: Closure<Unit>) = component.dependencies(action)
override fun dependencies(action: Action<KotlinNativeDependencies>) = component.dependencies(action)
// endregion // endregion
} }
@@ -0,0 +1,122 @@
/*
* 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.tasks
import org.gradle.api.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.*
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.cinterop.CInteropSettingsImpl
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
import javax.inject.Inject
open class CInteropTask @Inject constructor(val settings: CInteropSettingsImpl): DefaultTask() {
val konanTarget: KonanTarget
@Internal get() = settings.konanTarget
val outputFileName: String
@Internal get() = with(CompilerOutputKind.LIBRARY) {
val prefix = prefix(konanTarget)
val suffix = suffix(konanTarget)
return "$prefix$baseName$suffix"
}
val outputFile: File
get() = outputFileProvider.get().asFile
// Inputs and outputs.
@OutputFile
val outputFileProvider = newOutputFile().apply {
set { project.buildDir.resolve("cinterop/$baseName/$targetName/$outputFileName") }
}
val baseName: String
@Input get() = settings.baseName
val targetName: String
@Input get() = konanTarget.name
val defFile: File
@InputFile get() = settings.defFile
val packageName: String?
@Optional @Input get() = settings.packageName
val compilerOpts: List<String>
@Input get() = settings.compilerOpts
val linkerOpts: List<String>
@Input get() = settings.linkerOpts
val headers: FileCollection
@InputFiles get() = settings.headers
val allHeadersDirs: Set<File>
@Input get() = settings.includeDirs.allHeadersDirs.files
val headerFilterDirs: Set<File>
@Input get() = settings.includeDirs.headerFilterDirs.files
val extraOpts: List<String>
@Input get() = settings.extraOpts
// Task action.
@TaskAction
fun processInterop() {
val args = mutableListOf<String>().apply {
addArg("-o", outputFile.absolutePath)
addArgIfNotNull("-target", konanTarget.visibleName)
addArgIfNotNull("-def", defFile.canonicalPath)
addArgIfNotNull("-pkg", packageName)
addFileArgs("-h", headers)
compilerOpts.forEach {
addArg("-copt", it)
}
linkerOpts.forEach {
addArg("-lopt", it)
}
addArgs("-copt", allHeadersDirs.map { "-I${it.absolutePath}" })
addArgs("-headerFilterAdditionalSearchPrefix", headerFilterDirs.map { it.absolutePath })
/* TODO: Support dependencies
addArgs("-repo", libraries.repos.map { it.canonicalPath })
addFileArgs("-library", libraries.files)
addArgs("-library", libraries.namedKlibs)
addArgs("-library", libraries.artifacts.map { it.artifact.canonicalPath })
addKey("-nodefaultlibs", noDefaultLibs)
*/
addAll(extraOpts)
}
outputFile.parentFile.mkdirs()
KonanInteropRunner(project).run(args)
}
}