[K/N][build] Move old Konan plugin to native-build-tools
This commit is contained in:
committed by
Space Team
parent
04c5ac0eb6
commit
b1a85d45c6
@@ -1,196 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.
|
||||
*/
|
||||
|
||||
import org.jetbrains.kotlin.konan.*
|
||||
|
||||
buildscript {
|
||||
ext.rootBuildDirectory = file('../../')
|
||||
|
||||
apply from: "$rootBuildDirectory/gradle/loadRootProperties.gradle"
|
||||
apply from: "$rootBuildDirectory/gradle/kotlinGradlePlugin.gradle"
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
maven {
|
||||
url "https://cache-redirector.jetbrains.com/plugins.gradle.org/m2/"
|
||||
}
|
||||
gradlePluginPortal()
|
||||
}
|
||||
|
||||
dependencies {
|
||||
classpath 'com.github.johnrengelman:shadow:8.1.1'
|
||||
classpath "org.jetbrains.kotlin:kotlin-native-shared:$kotlinVersion"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'java-gradle-plugin'
|
||||
apply plugin: 'kotlin'
|
||||
apply plugin: 'groovy'
|
||||
apply plugin: 'com.github.johnrengelman.shadow'
|
||||
|
||||
group = 'org.jetbrains.kotlin'
|
||||
version = CompilerVersionGeneratedKt.getCurrentCompilerVersion()
|
||||
|
||||
repositories {
|
||||
mavenCentral()
|
||||
}
|
||||
|
||||
configurations {
|
||||
bundleDependencies {
|
||||
transitive = false
|
||||
}
|
||||
|
||||
implementation.extendsFrom shadow
|
||||
compileOnly.extendsFrom bundleDependencies
|
||||
testImplementation.extendsFrom bundleDependencies
|
||||
}
|
||||
|
||||
tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile).configureEach {
|
||||
kotlinOptions.freeCompilerArgs = ["-Xskip-prerelease-check"]
|
||||
}
|
||||
|
||||
dependencies {
|
||||
shadow "org.jetbrains.kotlin:kotlin-stdlib:1.3.0"
|
||||
|
||||
// Bundle the serialization plugin into the final jar because we shade classes of the kotlin plugin
|
||||
// while the serialization one extends them.
|
||||
bundleDependencies "org.jetbrains.kotlin:kotlin-serialization:$kotlinVersion"
|
||||
bundleDependencies "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlinVersion"
|
||||
bundleDependencies "org.jetbrains.kotlin:kotlin-gradle-plugin-api:$kotlinVersion"
|
||||
bundleDependencies "org.jetbrains.kotlin:kotlin-native-utils:$kotlinVersion"
|
||||
bundleDependencies "org.jetbrains.kotlin:kotlin-native-shared:$kotlinVersion"
|
||||
bundleDependencies "org.jetbrains.kotlin:kotlin-util-io:$kotlinVersion"
|
||||
bundleDependencies "org.jetbrains.kotlin:kotlin-util-klib:$kotlinVersion"
|
||||
|
||||
testImplementation DependenciesKt.commonDependency(project, "junit")
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-test:${project.bootstrapKotlinVersion}"
|
||||
testImplementation "org.jetbrains.kotlin:kotlin-test-junit:${project.bootstrapKotlinVersion}"
|
||||
testImplementation "org.tools4j:tools4j-spockito:1.6"
|
||||
testImplementation('org.spockframework:spock-core:1.1-groovy-2.4') {
|
||||
exclude module: 'groovy-all'
|
||||
}
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
from sourceSets.main.output
|
||||
configurations = [project.configurations.bundleDependencies]
|
||||
archiveClassifier.set(null)
|
||||
relocate('org.jetbrains.kotlinx', 'shadow.org.jetbrains.kotlinx')
|
||||
relocate('org.jetbrains.kotlin.compilerRunner', 'shadow.org.jetbrains.kotlin.compilerRunner')
|
||||
relocate('org.jetbrains.kotlin.konan', 'shadow.org.jetbrains.kotlin.konan')
|
||||
relocate('org.jetbrains.kotlin.gradle', 'shadow.org.jetbrains.kotlin.gradle') {
|
||||
exclude('org.jetbrains.kotlin.gradle.plugin.experimental.**')
|
||||
exclude('org.jetbrains.kotlin.gradle.plugin.konan.**')
|
||||
exclude('org.jetbrains.kotlin.gradle.plugin.model.**')
|
||||
}
|
||||
|
||||
exclude {
|
||||
def path = it.relativePath.pathString
|
||||
if (path.startsWith("META-INF/gradle-plugins") && path.endsWith(".properties")) {
|
||||
def fileName = it.name
|
||||
def id = fileName.take(fileName.lastIndexOf('.'))
|
||||
return project.gradlePlugin.plugins.findByName(id) == null
|
||||
}
|
||||
return false
|
||||
}
|
||||
exclude('META-INF/services/org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar')
|
||||
exclude('META-INF/services/org.jetbrains.kotlin.gradle.plugin.KotlinGradleSubplugin')
|
||||
}
|
||||
|
||||
jar {
|
||||
dependsOn shadowJar
|
||||
enabled = false
|
||||
}
|
||||
|
||||
pluginUnderTestMetadata {
|
||||
dependsOn shadowJar
|
||||
doLast {
|
||||
// Since Gradle 4.10 it isn't possible to edit the pluginUnderTest classpath.
|
||||
// So we have to manually set the implementation-classpath to get the output fat-jar.
|
||||
def pluginMetadata = outputDirectory.get().file(PluginUnderTestMetadata.METADATA_FILE_NAME).getAsFile()
|
||||
def classpath = files(shadowJar.archivePath) + configurations.shadow
|
||||
new Properties().with { properties ->
|
||||
pluginMetadata.withInputStream {
|
||||
properties.load(it)
|
||||
}
|
||||
properties.setProperty(PluginUnderTestMetadata.IMPLEMENTATION_CLASSPATH_PROP_KEY , classpath.asPath)
|
||||
pluginMetadata.withOutputStream {
|
||||
properties.store(it, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
test {
|
||||
dependsOn shadowJar
|
||||
systemProperty("kotlin.version", kotlinVersion)
|
||||
systemProperty("kotlin.repo", project.bootstrapKotlinRepo)
|
||||
if (project.hasProperty("konan.home")) {
|
||||
systemProperty("konan.home", project.property("konan.home"))
|
||||
systemProperty("org.jetbrains.kotlin.native.home", project.property("konan.home"))
|
||||
} else if (project.hasProperty("org.jetbrains.kotlin.native.home")) {
|
||||
systemProperty("org.jetbrains.kotlin.native.home", project.property("org.jetbrains.kotlin.native.home"))
|
||||
} else {
|
||||
// The Koltin/Native compiler must be built before test execution.
|
||||
systemProperty("konan.home", distDir.absolutePath)
|
||||
systemProperty("org.jetbrains.kotlin.native.home", distDir.absolutePath)
|
||||
}
|
||||
if (project.hasProperty("konan.jvmArgs")) {
|
||||
systemProperty("konan.jvmArgs", project.property("konan.jvmArgs"))
|
||||
}
|
||||
// Uncomment for debugging.
|
||||
//testLogging.showStandardStreams = true
|
||||
if (project.hasProperty("maxParallelForks")) {
|
||||
maxParallelForks=project.property("maxParallelForks")
|
||||
}
|
||||
if (project.hasProperty("filter")) {
|
||||
filter.includeTestsMatching project.property("filter")
|
||||
}
|
||||
if (project.hasProperty("gradleVersion")) {
|
||||
systemProperty("gradleVersion", project.property("gradleVersion"))
|
||||
}
|
||||
}
|
||||
|
||||
processResources {
|
||||
from(file("$rootBuildDirectory/utilities/env_blacklist"))
|
||||
}
|
||||
|
||||
tasks.named('compileTestGroovy') {
|
||||
classpath = sourceSets.test.compileClasspath
|
||||
}
|
||||
|
||||
tasks.named('compileTestKotlin') {
|
||||
classpath += files(sourceSets.test.groovy.classesDirectory)
|
||||
}
|
||||
|
||||
gradlePlugin {
|
||||
plugins {
|
||||
create('konan') {
|
||||
id = 'konan'
|
||||
implementationClass = 'org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin'
|
||||
}
|
||||
// We bundle a shaded version of kotlinx-serialization plugin
|
||||
create('kotlinx-serialization-native') {
|
||||
id = 'kotlinx-serialization-native'
|
||||
implementationClass = 'shadow.org.jetbrains.kotlinx.serialization.gradle.SerializationGradleSubplugin'
|
||||
}
|
||||
|
||||
create('org.jetbrains.kotlin.konan') {
|
||||
id = 'org.jetbrains.kotlin.konan'
|
||||
implementationClass = 'org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin'
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,2 +0,0 @@
|
||||
rootProject.name = "kotlin-native-gradle-plugin"
|
||||
includeBuild '../../shared'
|
||||
-95
@@ -1,95 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2023 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.plugin.experimental.internal
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.internal.component.UsageContext
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.internal.os.OperatingSystem
|
||||
import org.gradle.language.cpp.internal.NativeVariantIdentity
|
||||
import org.gradle.nativeplatform.MachineArchitecture
|
||||
import org.gradle.nativeplatform.OperatingSystemFamily
|
||||
import org.gradle.nativeplatform.TargetMachine
|
||||
import org.gradle.nativeplatform.TargetMachineFactory
|
||||
import org.gradle.nativeplatform.platform.NativePlatform
|
||||
import org.gradle.nativeplatform.platform.internal.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.util.visibleName
|
||||
|
||||
interface KotlinNativePlatform : NativePlatform {
|
||||
val target: KonanTarget
|
||||
}
|
||||
|
||||
fun KonanTarget.getGradleOS(): OperatingSystemInternal = family.visibleName.let {
|
||||
DefaultOperatingSystem(it, OperatingSystem.forName(it))
|
||||
}
|
||||
|
||||
fun KonanTarget.getGradleOSFamily(objectFactory: ObjectFactory): OperatingSystemFamily {
|
||||
return objectFactory.named(OperatingSystemFamily::class.java, family.visibleName)
|
||||
}
|
||||
|
||||
fun KonanTarget.getGradleCPU(): ArchitectureInternal = architecture.visibleName.let {
|
||||
Architectures.forInput(it)
|
||||
}
|
||||
|
||||
fun KonanTarget.toTargetMachine(objectFactory: ObjectFactory): TargetMachine = object : TargetMachine {
|
||||
override fun getOperatingSystemFamily(): OperatingSystemFamily =
|
||||
getGradleOSFamily(objectFactory)
|
||||
|
||||
override fun getArchitecture(): MachineArchitecture =
|
||||
objectFactory.named(MachineArchitecture::class.java, this@toTargetMachine.architecture.visibleName)
|
||||
}
|
||||
|
||||
class DefaultKotlinNativePlatform(name: String, override val target: KonanTarget) :
|
||||
DefaultNativePlatform(name, target.getGradleOS(), target.getGradleCPU()),
|
||||
KotlinNativePlatform {
|
||||
constructor(target: KonanTarget) : this(target.visibleName, target)
|
||||
|
||||
// TODO: Extend ImmutableDefaultNativePlatform and get rid of these methods after switch to Gradle 4.8
|
||||
private fun notImplemented(): Nothing = throw NotImplementedError("Not Implemented in Kotlin/Native plugin")
|
||||
override fun operatingSystem(name: String?) = notImplemented()
|
||||
override fun withArchitecture(architecture: ArchitectureInternal?) = notImplemented()
|
||||
override fun architecture(name: String?) = notImplemented()
|
||||
}
|
||||
|
||||
// NativeVariantIdentity constructor was changed in Gradle 5.1
|
||||
// So we have to use reflection to create instance of this class in earlier versions.
|
||||
internal fun compatibleVariantIdentity(
|
||||
project: Project,
|
||||
name: String,
|
||||
baseName: Provider<String>,
|
||||
group: Provider<String>,
|
||||
version: Provider<String>,
|
||||
debuggable: Boolean,
|
||||
optimized: Boolean,
|
||||
target: KonanTarget,
|
||||
linkUsage: UsageContext?,
|
||||
runtimeUsage: UsageContext?
|
||||
): NativeVariantIdentity =
|
||||
NativeVariantIdentity::class.java.getConstructor(
|
||||
String::class.java,
|
||||
Provider::class.java,
|
||||
Provider::class.java,
|
||||
Provider::class.java,
|
||||
Boolean::class.javaPrimitiveType,
|
||||
Boolean::class.javaPrimitiveType,
|
||||
OperatingSystemFamily::class.java,
|
||||
UsageContext::class.java,
|
||||
UsageContext::class.java
|
||||
).newInstance(
|
||||
name,
|
||||
baseName,
|
||||
group,
|
||||
version,
|
||||
debuggable,
|
||||
optimized,
|
||||
target.getGradleOSFamily(project.objects),
|
||||
linkUsage,
|
||||
runtimeUsage
|
||||
)
|
||||
|
||||
-110
@@ -1,110 +0,0 @@
|
||||
/*
|
||||
* 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.konan
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin.ProjectProperty
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
/**
|
||||
* The plugin allows an IDE to specify some building parameters. These parameters
|
||||
* are passed to the plugin via environment variables. Two variables are supported:
|
||||
* - CONFIGURATION_BUILD_DIR - A path to a destination directory for all compilation tasks.
|
||||
* The IDE should take care about specifying different directories
|
||||
* for different targets. This setting has less priority than
|
||||
* an explicitly specified destination directory in the build script.
|
||||
*
|
||||
* - DEBUGGING_SYMBOLS - If YES, the debug support will be enabled for all artifacts. This option has less
|
||||
* priority than explicitly specified enableDebug option in the build script and
|
||||
* enableDebug project property.
|
||||
*
|
||||
* - KONAN_ENABLE_OPTIMIZATIONS - If YES, optimizations will be enabled for all artifacts by default. This option
|
||||
* has less priority than explicitly specified enableOptimizations option in the
|
||||
* build script.
|
||||
*
|
||||
* Support for environment variables should be explicitly enabled by setting a project property:
|
||||
* konan.useEnvironmentVariables = true.
|
||||
*/
|
||||
|
||||
internal interface EnvironmentVariables {
|
||||
val configurationBuildDir: File?
|
||||
val debuggingSymbols: Boolean
|
||||
val enableOptimizations: Boolean
|
||||
}
|
||||
|
||||
internal class EnvironmentVariablesUnused: EnvironmentVariables {
|
||||
override val configurationBuildDir: File?
|
||||
get() = null
|
||||
|
||||
override val debuggingSymbols: Boolean
|
||||
get() = false
|
||||
|
||||
override val enableOptimizations: Boolean
|
||||
get() = false
|
||||
}
|
||||
|
||||
internal class EnvironmentVariablesImpl(val project: Project): EnvironmentVariables {
|
||||
override val configurationBuildDir: File?
|
||||
get() = System.getenv("CONFIGURATION_BUILD_DIR")?.let {
|
||||
project.file(it)
|
||||
}
|
||||
|
||||
override val debuggingSymbols: Boolean
|
||||
get() = System.getenv("DEBUGGING_SYMBOLS")?.uppercase() == "YES"
|
||||
|
||||
override val enableOptimizations: Boolean
|
||||
get() = System.getenv("KONAN_ENABLE_OPTIMIZATIONS")?.uppercase() == "YES"
|
||||
}
|
||||
|
||||
/**
|
||||
* Due to https://github.com/gradle/gradle/issues/3468 we cannot use environment
|
||||
* variables in Java 9. Until Gradle API for environment variables is provided
|
||||
* we use project properties instead of them. TODO: Return to using env vars when the issue is fixed.
|
||||
*/
|
||||
internal class EnvironmentVariablesFromProperties(val project: Project): EnvironmentVariables {
|
||||
override val configurationBuildDir: File?
|
||||
get() = project.findProperty(ProjectProperty.KONAN_CONFIGURATION_BUILD_DIR)?.let {
|
||||
project.file(it)
|
||||
}
|
||||
|
||||
override val debuggingSymbols: Boolean
|
||||
get() = project.findProperty(ProjectProperty.KONAN_DEBUGGING_SYMBOLS)?.toString()?.uppercase(Locale.getDefault()).let {
|
||||
it == "YES" || it == "TRUE"
|
||||
}
|
||||
|
||||
override val enableOptimizations: Boolean
|
||||
get() = project.findProperty(ProjectProperty.KONAN_OPTIMIZATIONS_ENABLE)?.toString()?.uppercase(Locale.getDefault()).let {
|
||||
it == "YES" || it == "TRUE"
|
||||
}
|
||||
}
|
||||
|
||||
internal val Project.useEnvironmentVariables: Boolean
|
||||
get() = findProperty(ProjectProperty.KONAN_USE_ENVIRONMENT_VARIABLES)?.toString()?.toBoolean() ?: false
|
||||
|
||||
/*
|
||||
TODO: Return to using env vars when the issue is fixed.
|
||||
Take into account the useEnvironmentVariables property (and may be rename it) in the following way:
|
||||
|
||||
if (useEnvironmentVariables) {
|
||||
EnvironmentVariablesImpl(project)
|
||||
} else {
|
||||
EnvironmentVariablesUnused()
|
||||
}
|
||||
*/
|
||||
internal val Project.environmentVariables: EnvironmentVariables
|
||||
get() = EnvironmentVariablesFromProperties(project)
|
||||
-170
@@ -1,170 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.NamedDomainObjectFactory
|
||||
import org.gradle.api.internal.CollectionCallbackActionDecorator
|
||||
import org.gradle.api.internal.DefaultPolymorphicDomainObjectContainer
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.internal.reflect.Instantiator
|
||||
import kotlin.reflect.KClass
|
||||
|
||||
open class KonanArtifactContainer(val project: ProjectInternal) : DefaultPolymorphicDomainObjectContainer<KonanBuildingConfig<*>>(
|
||||
KonanBuildingConfig::class.java,
|
||||
project.services.get(Instantiator::class.java),
|
||||
CollectionCallbackActionDecorator.NOOP
|
||||
) {
|
||||
private inner class KonanBuildingConfigFactory<T: KonanBuildingConfig<*>>(val configClass: KClass<T>)
|
||||
: NamedDomainObjectFactory<T> {
|
||||
|
||||
var targets: Iterable<String> = emptyList()
|
||||
|
||||
override fun create(name: String): T =
|
||||
instantiator.newInstance(configClass.java, name, project, targets)
|
||||
}
|
||||
|
||||
private val factories = mutableMapOf<KClass<out KonanBuildingConfig<*>>, KonanBuildingConfigFactory<*>>()
|
||||
|
||||
private fun <T: KonanBuildingConfig<*>> createFactory(configClass: KClass<T>) {
|
||||
val factory = KonanBuildingConfigFactory(configClass)
|
||||
super.registerFactory(configClass.java, factory)
|
||||
factories.put(configClass, factory)
|
||||
}
|
||||
|
||||
init {
|
||||
createFactory(KonanProgram::class)
|
||||
createFactory(KonanDynamic::class)
|
||||
createFactory(KonanFramework::class)
|
||||
createFactory(KonanLibrary::class)
|
||||
createFactory(KonanBitcode::class)
|
||||
createFactory(KonanInteropLibrary::class)
|
||||
}
|
||||
|
||||
private fun determineTargets(configClass: KClass<out KonanBuildingConfig<*>>, args: Map<String, Any?>) {
|
||||
val targetsArg = args["targets"]
|
||||
val targets = when {
|
||||
targetsArg == null -> project.konanExtension.targets
|
||||
targetsArg is Iterable<*> -> targetsArg.map { it.toString() }
|
||||
else -> listOf(targetsArg.toString())
|
||||
}
|
||||
factories[configClass]?.targets = targets
|
||||
}
|
||||
|
||||
private fun <T: KonanBuildingConfig<*>> create(name: String,
|
||||
configClass: KClass<T>,
|
||||
args: Map<String, Any?>,
|
||||
configureAction: Action<T>) {
|
||||
determineTargets(configClass, args)
|
||||
super.create(name, configClass.java, configureAction)
|
||||
}
|
||||
|
||||
private fun <T: KonanBuildingConfig<*>> create(name: String,
|
||||
configClass: KClass<T>,
|
||||
args: Map<String, Any?>,
|
||||
configureAction: T.() -> Unit) {
|
||||
determineTargets(configClass, args)
|
||||
super.create(name, configClass.java, configureAction)
|
||||
}
|
||||
|
||||
private fun <T: KonanBuildingConfig<*>> create(name: String,
|
||||
configClass: KClass<T>,
|
||||
args: Map<String, Any?>) {
|
||||
determineTargets(configClass, args)
|
||||
super.create(name, configClass.java)
|
||||
}
|
||||
|
||||
fun program(args: Map<String, Any?>, name: String) = create(name, KonanProgram::class, args)
|
||||
fun program(args: Map<String, Any?>, name: String, configureAction: Action<KonanProgram>) =
|
||||
create(name, KonanProgram::class, args, configureAction)
|
||||
fun program(args: Map<String, Any?>, name: String, configureAction: KonanProgram.() -> Unit) =
|
||||
create(name, KonanProgram::class, args, configureAction)
|
||||
fun program(args: Map<String, Any?>, name: String, configureAction: Closure<*>) =
|
||||
program(args, name) { project.configure(this, configureAction) }
|
||||
|
||||
fun dynamic(args: Map<String, Any?>, name: String) = create(name, KonanDynamic::class, args)
|
||||
fun dynamic(args: Map<String, Any?>, name: String, configureAction: Action<KonanDynamic>) =
|
||||
create(name, KonanDynamic::class, args, configureAction)
|
||||
fun dynamic(args: Map<String, Any?>, name: String, configureAction: KonanDynamic.() -> Unit) =
|
||||
create(name, KonanDynamic::class, args, configureAction)
|
||||
fun dynamic(args: Map<String, Any?>, name: String, configureAction: Closure<*>) =
|
||||
dynamic(args, name) { project.configure(this, configureAction) }
|
||||
|
||||
fun framework(args: Map<String, Any?>, name: String) = create(name, KonanFramework::class, args)
|
||||
fun framework(args: Map<String, Any?>, name: String, configureAction: Action<KonanFramework>) =
|
||||
create(name, KonanFramework::class, args, configureAction)
|
||||
fun framework(args: Map<String, Any?>, name: String, configureAction: KonanFramework.() -> Unit) =
|
||||
create(name, KonanFramework::class, args, configureAction)
|
||||
fun framework(args: Map<String, Any?>, name: String, configureAction: Closure<*>) =
|
||||
framework(args, name) { project.configure(this, configureAction) }
|
||||
|
||||
fun library(args: Map<String, Any?>, name: String) = create(name, KonanLibrary::class, args)
|
||||
fun library(args: Map<String, Any?>, name: String, configureAction: Action<KonanLibrary>) =
|
||||
create(name, KonanLibrary::class, args, configureAction)
|
||||
fun library(args: Map<String, Any?>, name: String, configureAction: KonanLibrary.() -> Unit) =
|
||||
create(name, KonanLibrary::class, args, configureAction)
|
||||
fun library(args: Map<String, Any?>, name: String, configureAction: Closure<*>) =
|
||||
library(args, name) { project.configure(this, configureAction) }
|
||||
|
||||
fun bitcode(args: Map<String, Any?>, name: String) = create(name, KonanBitcode::class, args)
|
||||
fun bitcode(args: Map<String, Any?>, name: String, configureAction: Action<KonanBitcode>) =
|
||||
create(name, KonanBitcode::class, args, configureAction)
|
||||
fun bitcode(args: Map<String, Any?>, name: String, configureAction: KonanBitcode.() -> Unit) =
|
||||
create(name, KonanBitcode::class, args, configureAction)
|
||||
fun bitcode(args: Map<String, Any?>, name: String, configureAction: Closure<*>) =
|
||||
bitcode(args, name) { project.configure(this, configureAction) }
|
||||
|
||||
fun interop(args: Map<String, Any?>, name: String) = create(name, KonanInteropLibrary::class, args)
|
||||
fun interop(args: Map<String, Any?>, name: String, configureAction: Action<KonanInteropLibrary>) =
|
||||
create(name, KonanInteropLibrary::class, args, configureAction)
|
||||
fun interop(args: Map<String, Any?>, name: String, configureAction: KonanInteropLibrary.() -> Unit) =
|
||||
create(name, KonanInteropLibrary::class, args, configureAction)
|
||||
fun interop(args: Map<String, Any?>, name: String, configureAction: Closure<*>) =
|
||||
interop(args, name) { project.configure(this, configureAction) }
|
||||
|
||||
fun program(name: String) = program(emptyMap(), name)
|
||||
fun program(name: String, configureAction: Action<KonanProgram>) = program(emptyMap(), name, configureAction)
|
||||
fun program(name: String, configureAction: KonanProgram.() -> Unit) = program(emptyMap(), name, configureAction)
|
||||
fun program(name: String, configureAction: Closure<*>) = program(emptyMap(), name, configureAction)
|
||||
|
||||
fun dynamic(name: String) = dynamic(emptyMap(), name)
|
||||
fun dynamic(name: String, configureAction: Action<KonanDynamic>) = dynamic(emptyMap(), name, configureAction)
|
||||
fun dynamic(name: String, configureAction: KonanDynamic.() -> Unit) = dynamic(emptyMap(), name, configureAction)
|
||||
fun dynamic(name: String, configureAction: Closure<*>) = dynamic(emptyMap(), name, configureAction)
|
||||
|
||||
fun framework(name: String) = framework(emptyMap(), name)
|
||||
fun framework(name: String, configureAction: Action<KonanFramework>) = framework(emptyMap(), name, configureAction)
|
||||
fun framework(name: String, configureAction: KonanFramework.() -> Unit) = framework(emptyMap(), name, configureAction)
|
||||
fun framework(name: String, configureAction: Closure<*>) = framework(emptyMap(), name, configureAction)
|
||||
|
||||
fun library(name: String) = library(emptyMap(), name)
|
||||
fun library(name: String, configureAction: Action<KonanLibrary>) = library(emptyMap(), name, configureAction)
|
||||
fun library(name: String, configureAction: KonanLibrary.() -> Unit) = library(emptyMap(), name, configureAction)
|
||||
fun library(name: String, configureAction: Closure<*>) = library(emptyMap(), name, configureAction)
|
||||
|
||||
fun bitcode(name: String) = bitcode(emptyMap(), name)
|
||||
fun bitcode(name: String, configureAction: Action<KonanBitcode>) = bitcode(emptyMap(), name, configureAction)
|
||||
fun bitcode(name: String, configureAction: KonanBitcode.() -> Unit) = bitcode(emptyMap(), name, configureAction)
|
||||
fun bitcode(name: String, configureAction: Closure<*>) = bitcode(emptyMap(), name, configureAction)
|
||||
|
||||
fun interop(name: String) = interop(emptyMap(), name)
|
||||
fun interop(name: String, configureAction: Action<KonanInteropLibrary>) = interop(emptyMap(), name, configureAction)
|
||||
fun interop(name: String, configureAction: KonanInteropLibrary.() -> Unit) = interop(emptyMap(), name, configureAction)
|
||||
fun interop(name: String, configureAction: Closure<*>) = interop(emptyMap(), name, configureAction)
|
||||
|
||||
}
|
||||
-222
@@ -1,222 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.InvalidUserDataException
|
||||
import org.gradle.api.Named
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.plugins.ExtensionAware
|
||||
import org.gradle.api.publish.maven.MavenPom
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanBuildingTask
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
import kotlin.NoSuchElementException
|
||||
|
||||
/** Base class for all Kotlin/Native artifacts. */
|
||||
abstract class KonanBuildingConfig<T : KonanBuildingTask>(
|
||||
private val name_: String,
|
||||
val type: Class<T>,
|
||||
val project: ProjectInternal,
|
||||
val targets: Iterable<String>
|
||||
) : KonanBuildingSpec, Named {
|
||||
|
||||
internal val mainVariant = KonanSoftwareComponent(project)
|
||||
override fun getName() = name_
|
||||
|
||||
protected val targetToTask = mutableMapOf<KonanTarget, TaskProvider<T>>()
|
||||
|
||||
fun tasks() = targetToTask.values
|
||||
|
||||
private val aggregateBuildTask: TaskProvider<Task>
|
||||
|
||||
internal var pomActions = mutableListOf<Action<MavenPom>>()
|
||||
|
||||
private val konanTargets: Iterable<KonanTarget>
|
||||
get() = project.hostManager.toKonanTargets(targets).distinct()
|
||||
|
||||
init {
|
||||
for (targetName in targets.distinct()) {
|
||||
val konanTarget = project.hostManager.targetByName(targetName)
|
||||
|
||||
if (!project.hostManager.isEnabled(konanTarget)) {
|
||||
project.logger.info("The target is not enabled on the current host: $targetName")
|
||||
continue
|
||||
}
|
||||
if (!targetIsSupported(konanTarget)) {
|
||||
project.logger.info("The target $targetName is not supported by the artifact $name")
|
||||
continue
|
||||
}
|
||||
if (this[konanTarget] == null) {
|
||||
val task = createTask(konanTarget)
|
||||
targetToTask[konanTarget] = task
|
||||
// Allow accessing targets just by their names in Groovy DSL.
|
||||
(this as? ExtensionAware)?.extensions?.add(konanTarget.visibleName, task)
|
||||
}
|
||||
|
||||
if (targetName != konanTarget.visibleName) {
|
||||
createTargetAliasTaskIfDeclared(targetName)
|
||||
}
|
||||
}
|
||||
aggregateBuildTask = createAggregateTask()
|
||||
}
|
||||
|
||||
protected open fun generateTaskName(target: KonanTarget) =
|
||||
"compileKonan${name.replaceFirstChar { it.uppercase() }}${target.visibleName.replaceFirstChar { it.uppercase() }}"
|
||||
|
||||
protected open fun generateAggregateTaskName() =
|
||||
"compileKonan${name.replaceFirstChar { if (it.isLowerCase()) it.titlecase(Locale.getDefault()) else it.toString() }}"
|
||||
|
||||
protected open fun generateTargetAliasTaskName(targetName: String) =
|
||||
"compileKonan${name.replaceFirstChar { it.uppercase() }}${targetName.replaceFirstChar { it.uppercase() }}"
|
||||
|
||||
protected abstract fun generateTaskDescription(task: T): String
|
||||
protected abstract fun generateAggregateTaskDescription(task: Task): String
|
||||
protected abstract fun generateTargetAliasTaskDescription(task: Task, targetName: String): String
|
||||
|
||||
protected abstract val defaultBaseDir: File
|
||||
|
||||
protected open fun targetIsSupported(target: KonanTarget): Boolean = true
|
||||
|
||||
data class OutputPlacement(val destinationDir: File, val artifactName: String)
|
||||
|
||||
// There are two options for output placement.
|
||||
// 1. Gradle's build directory. We use it by default, e.g. if user runs Gradle from command line.
|
||||
// In this case all produced files has the same name but are placed in different directories
|
||||
// depending on their targets (e.g. linux/foo.kexe and macbook/foo.kexe).
|
||||
// 2. Custom path provided by IDE. In this case CONFIGURATION_BUILD_DIR environment variable should
|
||||
// contain a path to a destination directory. All produced files are placed in this directory so IDE
|
||||
// should take care about setting different CONFIGURATION_BUILD_DIR for different targets.
|
||||
protected fun determineOutputPlacement(target: KonanTarget): OutputPlacement {
|
||||
val configurationBuildDir = project.environmentVariables.configurationBuildDir
|
||||
return if (configurationBuildDir != null) {
|
||||
OutputPlacement(configurationBuildDir, name)
|
||||
} else {
|
||||
OutputPlacement(defaultBaseDir.targetSubdir(target), name)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createTask(target: KonanTarget): TaskProvider<T> =
|
||||
project.tasks.register(generateTaskName(target), type) {
|
||||
val outputDescription = determineOutputPlacement(target)
|
||||
init(this@KonanBuildingConfig, outputDescription.destinationDir, outputDescription.artifactName, target)
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
description = generateTaskDescription(this)
|
||||
}
|
||||
|
||||
private fun createAggregateTask(): TaskProvider<Task> =
|
||||
project.tasks.register(generateAggregateTaskName()) {
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
description = generateAggregateTaskDescription(this)
|
||||
|
||||
targetToTask.filter {
|
||||
project.targetIsRequested(it.key)
|
||||
}.forEach {
|
||||
dependsOn(it.value)
|
||||
}
|
||||
}.also {
|
||||
project.compileAllTask.configure { dependsOn(it) }
|
||||
}
|
||||
|
||||
protected fun createTargetAliasTaskIfDeclared(targetName: String): TaskProvider<Task>? {
|
||||
val canonicalTarget = project.hostManager.targetByName(targetName)
|
||||
|
||||
return this[canonicalTarget]?.let { canonicalBuild ->
|
||||
project.tasks.register(generateTargetAliasTaskName(targetName)) {
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
description = generateTargetAliasTaskDescription(this, targetName)
|
||||
dependsOn(canonicalBuild)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal operator fun get(target: KonanTarget) = targetToTask[target]
|
||||
|
||||
fun getByTarget(target: String) =
|
||||
findByTarget(target) ?: throw NoSuchElementException("No such target for artifact $name: $target")
|
||||
|
||||
fun findByTarget(target: String) = this[project.hostManager.targetByName(target)]
|
||||
|
||||
fun getArtifactByTarget(target: String) = getByTarget(target).get().artifact
|
||||
fun findArtifactByTarget(target: String) = findByTarget(target)?.get()?.artifact
|
||||
|
||||
// Common building DSL.
|
||||
|
||||
override fun artifactName(name: String) = tasks().forEach { it.configure { artifactName(name) } }
|
||||
|
||||
fun baseDir(dir: Any) =
|
||||
tasks().forEach {
|
||||
it.configure {
|
||||
destinationDir(
|
||||
project.file(dir).targetSubdir(konanTarget)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun libraries(closure: Closure<Unit>) =
|
||||
tasks().forEach { it.configure { libraries(closure) } }
|
||||
|
||||
override fun libraries(action: Action<KonanLibrariesSpec>) =
|
||||
tasks().forEach { it.configure { libraries(action) } }
|
||||
|
||||
override fun libraries(configure: KonanLibrariesSpec.() -> Unit) =
|
||||
tasks().forEach { it.configure { libraries(configure) } }
|
||||
|
||||
override fun noDefaultLibs(flag: Boolean) =
|
||||
tasks().forEach { it.configure { noDefaultLibs(flag) } }
|
||||
|
||||
override fun noEndorsedLibs(flag: Boolean) =
|
||||
tasks().forEach { it.configure { noEndorsedLibs(flag) } }
|
||||
|
||||
override fun dumpParameters(flag: Boolean) =
|
||||
tasks().forEach { it.configure { dumpParameters(flag) } }
|
||||
|
||||
override fun extraOpts(vararg values: Any) =
|
||||
tasks().forEach { it.configure { extraOpts(*values) } }
|
||||
|
||||
override fun extraOpts(values: List<Any>) =
|
||||
tasks().forEach { it.configure { extraOpts(values) } }
|
||||
|
||||
fun dependsOn(vararg dependencies: Any?) =
|
||||
tasks().forEach { it.configure { dependsOn(*dependencies) } }
|
||||
|
||||
fun target(targetString: String, configureAction: T.() -> Unit) {
|
||||
val target = project.hostManager.targetByName(targetString)
|
||||
|
||||
if (!project.hostManager.isEnabled(target)) {
|
||||
project.logger.info("Target '$targetString' of artifact '$name' is not supported on the current host")
|
||||
return
|
||||
}
|
||||
|
||||
val task = this[target]
|
||||
?: throw InvalidUserDataException("Target '$targetString' is not declared. Please add it into project.konanTasks list")
|
||||
task.configure(configureAction)
|
||||
}
|
||||
|
||||
fun target(targetString: String, configureAction: Action<T>) =
|
||||
target(targetString) { configureAction.execute(this) }
|
||||
|
||||
fun target(targetString: String, configureAction: Closure<Unit>) =
|
||||
target(targetString) { project.configure(this, configureAction) }
|
||||
|
||||
fun pom(action: Action<MavenPom>) = pomActions + action
|
||||
}
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.jetbrains.kotlin.gradle.plugin.tasks.*
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget.WASM32
|
||||
import java.io.File
|
||||
|
||||
abstract class KonanCompileConfig<T: KonanCompileTask>(name: String,
|
||||
type: Class<T>,
|
||||
project: ProjectInternal,
|
||||
targets: Iterable<String>)
|
||||
: KonanBuildingConfig<T>(name, type, project, targets), KonanCompileSpec {
|
||||
|
||||
protected abstract val typeForDescription: String
|
||||
|
||||
override fun generateTaskDescription(task: T) =
|
||||
"Build the Kotlin/Native $typeForDescription '${task.name}' for target '${task.konanTarget}'"
|
||||
|
||||
override fun generateAggregateTaskDescription(task: Task) =
|
||||
"Build the Kotlin/Native $typeForDescription '${task.name}' for all supported and declared targets"
|
||||
|
||||
override fun generateTargetAliasTaskDescription(task: Task, targetName: String) =
|
||||
"Build the Kotlin/Native $typeForDescription '${task.name}' for target '$targetName'"
|
||||
|
||||
override fun srcDir(dir: Any) = tasks().forEach { it.configure { srcDir(dir) } }
|
||||
override fun srcFiles(vararg files: Any) = tasks().forEach { it.configure { srcFiles(*files) } }
|
||||
override fun srcFiles(files: Collection<Any>) = tasks().forEach { it.configure { srcFiles(files) } }
|
||||
|
||||
override fun nativeLibrary(lib: Any) = tasks().forEach { it.configure { nativeLibrary(lib) } }
|
||||
override fun nativeLibraries(vararg libs: Any) = tasks().forEach { it.configure { nativeLibraries(*libs) } }
|
||||
override fun nativeLibraries(libs: FileCollection) = tasks().forEach { it.configure { nativeLibraries(libs) } }
|
||||
|
||||
@Deprecated("Use commonSourceSets instead", ReplaceWith("commonSourceSets(sourceSetName)"))
|
||||
override fun commonSourceSet(sourceSetName: String) = tasks().forEach { it.configure { commonSourceSets(sourceSetName) } }
|
||||
override fun commonSourceSets(vararg sourceSetNames: String) = tasks().forEach { it.configure { commonSourceSets(*sourceSetNames) } }
|
||||
override fun enableMultiplatform(flag: Boolean) = tasks().forEach { it.configure { enableMultiplatform(flag) } }
|
||||
|
||||
override fun commonSrcDir(dir: Any) = tasks().forEach { it.configure { commonSrcDir(dir) } }
|
||||
override fun commonSrcFiles(vararg files: Any) = tasks().forEach { it.configure { commonSrcFiles(*files) } }
|
||||
override fun commonSrcFiles(files: Collection<Any>) = tasks().forEach { it.configure { commonSrcFiles(files) } }
|
||||
|
||||
override fun linkerOpts(values: List<String>) = tasks().forEach { it.configure { linkerOpts(values) } }
|
||||
override fun linkerOpts(vararg values: String) = tasks().forEach { it.configure { linkerOpts(*values) } }
|
||||
|
||||
override fun enableDebug(flag: Boolean) = tasks().forEach { it.configure { enableDebug(flag) } }
|
||||
override fun noStdLib(flag: Boolean) = tasks().forEach { it.configure { noStdLib(flag) } }
|
||||
override fun noMain(flag: Boolean) = tasks().forEach { it.configure { noMain(flag) } }
|
||||
override fun noPack(flag: Boolean) = tasks().forEach { it.configure { noPack(flag) } }
|
||||
override fun enableOptimizations(flag: Boolean) = tasks().forEach { it.configure { enableOptimizations(flag) } }
|
||||
override fun enableAssertions(flag: Boolean) = tasks().forEach { it.configure { enableAssertions(flag) } }
|
||||
|
||||
override fun entryPoint(entryPoint: String) = tasks().forEach { it.configure { entryPoint(entryPoint) } }
|
||||
|
||||
override fun measureTime(flag: Boolean) = tasks().forEach { it.configure { measureTime(flag) } }
|
||||
|
||||
override fun dependencies(closure: Closure<Unit>) = tasks().forEach { it.configure { dependencies(closure) } }
|
||||
}
|
||||
|
||||
open class KonanProgram(name: String,
|
||||
project: ProjectInternal,
|
||||
targets: Iterable<String> = project.konanExtension.targets
|
||||
) : KonanCompileConfig<KonanCompileProgramTask>(name,
|
||||
KonanCompileProgramTask::class.java,
|
||||
project,
|
||||
targets
|
||||
) {
|
||||
override val typeForDescription: String
|
||||
get() = "executable"
|
||||
|
||||
override val defaultBaseDir: File
|
||||
get() = project.konanBinBaseDir
|
||||
}
|
||||
|
||||
open class KonanDynamic(name: String,
|
||||
project: ProjectInternal,
|
||||
targets: Iterable<String> = project.konanExtension.targets)
|
||||
: KonanCompileConfig<KonanCompileDynamicTask>(name,
|
||||
KonanCompileDynamicTask::class.java,
|
||||
project,
|
||||
targets
|
||||
) {
|
||||
override val typeForDescription: String
|
||||
get() = "dynamic library"
|
||||
|
||||
override val defaultBaseDir: File
|
||||
get() = project.konanBinBaseDir
|
||||
|
||||
override fun targetIsSupported(target: KonanTarget): Boolean = target != WASM32
|
||||
}
|
||||
|
||||
open class KonanFramework(name: String,
|
||||
project: ProjectInternal,
|
||||
targets: Iterable<String> = project.konanExtension.targets)
|
||||
: KonanCompileConfig<KonanCompileFrameworkTask>(name,
|
||||
KonanCompileFrameworkTask::class.java,
|
||||
project,
|
||||
targets
|
||||
) {
|
||||
override val typeForDescription: String
|
||||
get() = "framework"
|
||||
|
||||
override val defaultBaseDir: File
|
||||
get() = project.konanBinBaseDir
|
||||
|
||||
override fun targetIsSupported(target: KonanTarget): Boolean =
|
||||
target.family.isAppleFamily
|
||||
}
|
||||
|
||||
open class KonanLibrary(name: String,
|
||||
project: ProjectInternal,
|
||||
targets: Iterable<String> = project.konanExtension.targets)
|
||||
: KonanCompileConfig<KonanCompileLibraryTask>(name,
|
||||
KonanCompileLibraryTask::class.java,
|
||||
project,
|
||||
targets
|
||||
) {
|
||||
override val typeForDescription: String
|
||||
get() = "library"
|
||||
|
||||
override val defaultBaseDir: File
|
||||
get() = project.konanLibsBaseDir
|
||||
}
|
||||
|
||||
open class KonanBitcode(name: String,
|
||||
project: ProjectInternal,
|
||||
targets: Iterable<String> = project.konanExtension.targets)
|
||||
: KonanCompileConfig<KonanCompileBitcodeTask>(name,
|
||||
KonanCompileBitcodeTask::class.java,
|
||||
project,
|
||||
targets
|
||||
) {
|
||||
override val typeForDescription: String
|
||||
get() = "bitcode"
|
||||
|
||||
override fun generateTaskDescription(task: KonanCompileBitcodeTask) =
|
||||
"Generates bitcode for the artifact '${task.name}' and target '${task.konanTarget}'"
|
||||
|
||||
override fun generateAggregateTaskDescription(task: Task) =
|
||||
"Generates bitcode for the artifact '${task.name}' for all supported and declared targets'"
|
||||
|
||||
override fun generateTargetAliasTaskDescription(task: Task, targetName: String) =
|
||||
"Generates bitcode for the artifact '${task.name}' for '$targetName'"
|
||||
|
||||
override val defaultBaseDir: File
|
||||
get() = project.konanBitcodeBaseDir
|
||||
}
|
||||
-84
@@ -1,84 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.KonanInteropSpec.IncludeDirectoriesSpec
|
||||
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanInteropTask
|
||||
import java.io.File
|
||||
|
||||
open class KonanInteropLibrary(name: String,
|
||||
project: ProjectInternal,
|
||||
targets: Iterable<String> = project.konanExtension.targets
|
||||
) : KonanBuildingConfig<KonanInteropTask>(name, KonanInteropTask::class.java, project, targets),
|
||||
KonanInteropSpec
|
||||
{
|
||||
|
||||
override fun generateTaskDescription(task: KonanInteropTask) =
|
||||
"Build the Kotlin/Native interop library '${task.name}' for target '${task.konanTarget}'"
|
||||
|
||||
override fun generateAggregateTaskDescription(task: Task) =
|
||||
"Build the Kotlin/Native interop library '${task.name}' for all supported and declared targets'"
|
||||
|
||||
override fun generateTargetAliasTaskDescription(task: Task, targetName: String) =
|
||||
"Build the Kotlin/Native interop library '${task.name}' for '$targetName'"
|
||||
|
||||
override val defaultBaseDir: File
|
||||
get() = project.konanLibsBaseDir
|
||||
|
||||
// DSL
|
||||
|
||||
inner class IncludeDirectoriesSpecImpl: IncludeDirectoriesSpec {
|
||||
override fun allHeaders(vararg includeDirs: Any) = allHeaders(includeDirs.toList())
|
||||
override fun allHeaders(includeDirs: Collection<Any>) = tasks().forEach {
|
||||
it.configure { this@configure.includeDirs.allHeaders(includeDirs) }
|
||||
}
|
||||
|
||||
override fun headerFilterOnly(vararg includeDirs: Any) = headerFilterOnly(includeDirs.toList())
|
||||
override fun headerFilterOnly(includeDirs: Collection<Any>) = tasks().forEach {
|
||||
it.configure { this@configure.includeDirs.headerFilterOnly(includeDirs) }
|
||||
}
|
||||
}
|
||||
|
||||
val includeDirs = IncludeDirectoriesSpecImpl()
|
||||
|
||||
override fun defFile(file: Any) = tasks().forEach { it.configure { defFile(file) } }
|
||||
|
||||
override fun packageName(value: String) = tasks().forEach { it.configure { packageName(value) } }
|
||||
|
||||
override fun compilerOpts(vararg values: String) = tasks().forEach { it.configure { compilerOpts(*values) } }
|
||||
|
||||
override fun headers(vararg files: Any) = tasks().forEach { it.configure { headers(*files) } }
|
||||
|
||||
override fun headers(files: FileCollection) = tasks().forEach { it.configure { headers(files) } }
|
||||
|
||||
override fun includeDirs(vararg values: Any) = tasks().forEach { it.configure { includeDirs(*values) } }
|
||||
override fun includeDirs(closure: Closure<Unit>) = includeDirs { project.configure(this, closure) }
|
||||
override fun includeDirs(action: Action<IncludeDirectoriesSpec>) = includeDirs { action.execute(this) }
|
||||
override fun includeDirs(configure: IncludeDirectoriesSpec.() -> Unit) = includeDirs.configure()
|
||||
|
||||
override fun linkerOpts(values: List<String>) = tasks().forEach { it.configure { linkerOpts(values) } }
|
||||
override fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
|
||||
|
||||
override fun link(vararg files: Any) = tasks().forEach { it.configure { link(*files) } }
|
||||
override fun link(files: FileCollection) = tasks().forEach { it.configure { link(files) } }
|
||||
override fun dependencies(closure: Closure<Unit>) = tasks().forEach { it.configure { dependencies(closure) }}
|
||||
}
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import org.gradle.api.InvalidUserDataException
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.InputFiles
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanArtifactWithLibrariesTask
|
||||
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanBuildingTask
|
||||
import org.jetbrains.kotlin.konan.*
|
||||
import org.jetbrains.kotlin.konan.library.defaultResolver
|
||||
import org.jetbrains.kotlin.konan.library.impl.KonanLibraryImpl
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.library.SearchPathResolver
|
||||
import java.io.File
|
||||
|
||||
open class KonanLibrariesSpec(
|
||||
@Internal val task: KonanArtifactWithLibrariesTask,
|
||||
@Internal val project: Project
|
||||
) {
|
||||
|
||||
@InputFiles val files = mutableSetOf<FileCollection>()
|
||||
|
||||
@Input val namedKlibs = mutableSetOf<String>()
|
||||
|
||||
@Internal val artifacts = mutableListOf<KonanBuildingTask>()
|
||||
|
||||
val artifactFiles: List<File>
|
||||
@InputFiles get() = artifacts.map { it.artifact }
|
||||
|
||||
@Internal val explicitRepos = mutableSetOf<File>()
|
||||
|
||||
val repos: Set<File>
|
||||
@Input get() = mutableSetOf<File>().apply {
|
||||
addAll(explicitRepos)
|
||||
add(task.destinationDir) // TODO: Check if task is a library - create a Library interface
|
||||
add(task.destinationDir) // TODO: Check if task is a library - create a Library interface
|
||||
add(task.project.konanLibsBaseDir.targetSubdir(target))
|
||||
addAll(artifacts.flatMap { it.libraries.repos })
|
||||
addAll(task.platformConfiguration.files.map { it.parentFile })
|
||||
}
|
||||
|
||||
val target: KonanTarget
|
||||
@Internal get() = task.konanTarget
|
||||
|
||||
private val friendsTasks = mutableSetOf<KonanBuildingTask>()
|
||||
|
||||
@get:Internal // Taken into account by tasks's dependOn.
|
||||
val friends: Set<File> get() = mutableSetOf<File>().apply {
|
||||
addAll(friendsTasks.map { it.artifact })
|
||||
}
|
||||
|
||||
// DSL Methods
|
||||
|
||||
/** Absolute path */
|
||||
fun file(file: Any) = files.add(project.files(file))
|
||||
fun files(vararg files: Any) = this.files.addAll(files.map { project.files(it) })
|
||||
fun files(collection: FileCollection) = this.files.add(collection)
|
||||
|
||||
/** The compiler with search the library in repos */
|
||||
fun klib(lib: String) = namedKlibs.add(lib)
|
||||
fun klibs(vararg libs: String) = namedKlibs.addAll(libs)
|
||||
fun klibs(libs: Iterable<String>) = namedKlibs.addAll(libs)
|
||||
|
||||
private fun klibInternal(lib: KonanBuildingConfig<*>, friend: Boolean) {
|
||||
if (!(lib is KonanLibrary || lib is KonanInteropLibrary)) {
|
||||
throw InvalidUserDataException("Config ${lib.name} is not a library")
|
||||
}
|
||||
|
||||
val libraryTask = lib[target]?.get() ?:
|
||||
throw InvalidUserDataException("Library ${lib.name} has no target ${target.visibleName}")
|
||||
|
||||
if (libraryTask == task) {
|
||||
throw InvalidUserDataException("Attempt to use a library as its own dependency: " +
|
||||
"${task.name} (in project: ${project.path})")
|
||||
}
|
||||
artifacts.add(libraryTask)
|
||||
task.dependsOn(libraryTask)
|
||||
if (friend) friendsTasks.add(libraryTask)
|
||||
}
|
||||
|
||||
/** Direct link to a config */
|
||||
fun klib(lib: KonanLibrary) = klibInternal(lib, false)
|
||||
/** Direct link to a config */
|
||||
fun klib(lib: KonanInteropLibrary) = klibInternal(lib, false)
|
||||
|
||||
/** Artifact in the specified project by name */
|
||||
fun artifact(libraryProject: Project, name: String, friend: Boolean) {
|
||||
project.evaluationDependsOn(libraryProject)
|
||||
klibInternal(libraryProject.konanArtifactsContainer.getByName(name), friend)
|
||||
}
|
||||
|
||||
fun artifact(libraryProject: Project, name: String) = artifact(libraryProject, name, false)
|
||||
/** Artifact in the current project by name */
|
||||
fun artifact(name: String, friend: Boolean) = artifact(project, name, friend)
|
||||
|
||||
fun artifact(name: String) = artifact(project, name, false)
|
||||
|
||||
/** Artifact by direct link */
|
||||
fun artifact(artifact: KonanLibrary) = klib(artifact)
|
||||
/** Direct link to a config */
|
||||
fun artifact(artifact: KonanInteropLibrary) = klib(artifact)
|
||||
|
||||
private fun allArtifactsFromInternal(libraryProjects: Array<out Project>,
|
||||
filter: (KonanBuildingConfig<*>) -> Boolean) {
|
||||
libraryProjects.forEach { prj ->
|
||||
project.evaluationDependsOn(prj)
|
||||
prj.konanArtifactsContainer.filter(filter).forEach {
|
||||
klibInternal(it, false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/** All libraries (both interop and non-interop ones) from the projects by direct references */
|
||||
fun allLibrariesFrom(vararg libraryProjects: Project) = allArtifactsFromInternal(libraryProjects) {
|
||||
it is KonanLibrary || it is KonanInteropLibrary
|
||||
}
|
||||
|
||||
/** All interop libraries from the projects by direct references */
|
||||
fun allInteropLibrariesFrom(vararg libraryProjects: Project) = allArtifactsFromInternal(libraryProjects) {
|
||||
it is KonanInteropLibrary
|
||||
}
|
||||
|
||||
/** Add repo for library search */
|
||||
fun useRepo(directory: Any) = explicitRepos.add(project.file(directory))
|
||||
/** Add repos for library search */
|
||||
fun useRepos(vararg directories: Any) = directories.forEach { useRepo(it) }
|
||||
/** Add repos for library search */
|
||||
fun useRepos(directories: Iterable<Any>) = directories.forEach { useRepo(it) }
|
||||
|
||||
private fun Project.evaluationDependsOn(another: Project) {
|
||||
if (this != another) { evaluationDependsOn(another.path) }
|
||||
}
|
||||
|
||||
fun asFiles(): List<File> = asFiles(
|
||||
defaultResolver(
|
||||
repos.map { it.absolutePath },
|
||||
task.konanTarget,
|
||||
Distribution(project.konanHome)
|
||||
)
|
||||
)
|
||||
|
||||
fun asFiles(resolver: SearchPathResolver<*>): List<File> = mutableListOf<File>().apply {
|
||||
files.flatMapTo(this) { it.files }
|
||||
addAll(artifactFiles)
|
||||
addAll(task.platformConfiguration.files)
|
||||
namedKlibs.mapTo(this) { project.file(resolver.resolve(it).libraryFile.absolutePath) }
|
||||
}
|
||||
}
|
||||
-456
@@ -1,456 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.codehaus.groovy.runtime.GStringImpl
|
||||
import org.gradle.api.*
|
||||
import org.gradle.api.component.ComponentWithVariants
|
||||
import org.gradle.api.component.SoftwareComponent
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.internal.component.SoftwareComponentInternal
|
||||
import org.gradle.api.internal.component.UsageContext
|
||||
import org.gradle.api.internal.project.ProjectInternal
|
||||
import org.gradle.api.plugins.BasePlugin
|
||||
import org.gradle.api.plugins.JavaPluginExtension
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.publish.PublishingExtension
|
||||
import org.gradle.api.publish.maven.MavenPublication
|
||||
import org.gradle.api.publish.maven.internal.publication.MavenPublicationInternal
|
||||
import org.gradle.api.tasks.Exec
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.jvm.toolchain.JavaLanguageVersion
|
||||
import org.gradle.jvm.toolchain.JavaLauncher
|
||||
import org.gradle.jvm.toolchain.JavaToolchainService
|
||||
import org.gradle.jvm.toolchain.JavaToolchainSpec
|
||||
import org.gradle.language.cpp.internal.NativeVariantIdentity
|
||||
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin.Companion.COMPILE_ALL_TASK_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.tasks.*
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.buildDistribution
|
||||
import org.jetbrains.kotlin.konan.target.customerDistribution
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.konan.util.DependencyDirectories
|
||||
import java.io.File
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* We use the following properties:
|
||||
* org.jetbrains.kotlin.native.home - directory where compiler is located (aka dist in konan project output).
|
||||
* org.jetbrains.kotlin.native.version - a konan compiler version for downloading.
|
||||
* konan.build.targets - list of targets to build (by default all the declared targets are built).
|
||||
* konan.jvmArgs - additional args to be passed to a JVM executing the compiler/cinterop tool.
|
||||
*/
|
||||
|
||||
internal fun Project.warnAboutDeprecatedProperty(property: KonanPlugin.ProjectProperty) =
|
||||
property.deprecatedPropertyName?.let { deprecated ->
|
||||
if (project.hasProperty(deprecated)) {
|
||||
logger.warn("Project property '$deprecated' is deprecated. Use '${property.propertyName}' instead.")
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Project.hasProperty(property: KonanPlugin.ProjectProperty) = with(property) {
|
||||
when {
|
||||
hasProperty(propertyName) -> true
|
||||
deprecatedPropertyName != null && hasProperty(deprecatedPropertyName) -> true
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
|
||||
internal fun Project.findProperty(property: KonanPlugin.ProjectProperty): Any? = with(property) {
|
||||
return findProperty(propertyName) ?: deprecatedPropertyName?.let { findProperty(it) }
|
||||
}
|
||||
|
||||
internal fun Project.getProperty(property: KonanPlugin.ProjectProperty) = findProperty(property)
|
||||
?: throw IllegalArgumentException("No such property in the project: ${property.propertyName}")
|
||||
|
||||
internal fun Project.getProperty(property: KonanPlugin.ProjectProperty, defaultValue: Any) =
|
||||
findProperty(property) ?: defaultValue
|
||||
|
||||
internal fun Project.setProperty(property: KonanPlugin.ProjectProperty, value: Any) {
|
||||
extensions.extraProperties.set(property.propertyName, value)
|
||||
}
|
||||
|
||||
// konanHome extension is set by downloadKonanCompiler task.
|
||||
internal val Project.konanHome: String
|
||||
get() {
|
||||
return project.kotlinNativeDist.absolutePath
|
||||
}
|
||||
|
||||
// Used only for distribution downloading that is not used in the project and should be removed
|
||||
internal val Project.konanVersion: String
|
||||
get() = project.findProperty(KonanPlugin.ProjectProperty.KONAN_VERSION)
|
||||
?.toString()
|
||||
?: project.version.toString()
|
||||
|
||||
internal val Project.konanBuildRoot get() = buildDir.resolve("konan")
|
||||
internal val Project.konanBinBaseDir get() = konanBuildRoot.resolve("bin")
|
||||
internal val Project.konanLibsBaseDir get() = konanBuildRoot.resolve("libs")
|
||||
internal val Project.konanBitcodeBaseDir get() = konanBuildRoot.resolve("bitcode")
|
||||
|
||||
internal fun File.targetSubdir(target: KonanTarget) = resolve(target.visibleName)
|
||||
|
||||
internal val Project.konanDefaultSrcFiles get() = fileTree("${projectDir.canonicalPath}/src/main/kotlin")
|
||||
internal fun Project.konanDefaultDefFile(libName: String)
|
||||
= file("${projectDir.canonicalPath}/src/main/c_interop/$libName.def")
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal val Project.konanArtifactsContainer: KonanArtifactContainer
|
||||
get() = extensions.getByName(KonanPlugin.ARTIFACTS_CONTAINER_NAME) as KonanArtifactContainer
|
||||
|
||||
// TODO: The Kotlin/Native compiler is downloaded manually by a special task so the compilation tasks
|
||||
// are configured without the compile distribution. After target management refactoring
|
||||
// we need .properties files from the distribution to configure targets. This is worked around here
|
||||
// by using HostManager instead of PlatformManager. But we need to download the compiler at the configuration
|
||||
// stage (e.g. by getting it from maven as a plugin dependency) and bring back the PlatformManager here.
|
||||
internal val Project.hostManager: HostManager
|
||||
get() = findProperty("hostManager") as HostManager? ?:
|
||||
if (hasProperty("org.jetbrains.kotlin.native.experimentalTargets"))
|
||||
HostManager(buildDistribution(rootProject.rootDir.absolutePath), true)
|
||||
else
|
||||
HostManager(customerDistribution(konanHome))
|
||||
|
||||
internal val Project.konanTargets: List<KonanTarget>
|
||||
get() = hostManager.toKonanTargets(konanExtension.targets)
|
||||
.filter{ hostManager.isEnabled(it) }
|
||||
.distinct()
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
internal val Project.konanExtension: KonanExtension
|
||||
get() = extensions.getByName(KonanPlugin.KONAN_EXTENSION_NAME) as KonanExtension
|
||||
|
||||
internal val Project.requestedTargets
|
||||
get() = findProperty(KonanPlugin.ProjectProperty.KONAN_BUILD_TARGETS)?.let {
|
||||
it.toString().trim().split("\\s+".toRegex())
|
||||
}.orEmpty()
|
||||
|
||||
internal val Project.jvmArgs
|
||||
get() = (findProperty(KonanPlugin.ProjectProperty.KONAN_JVM_ARGS) as String?)?.split("\\s+".toRegex()).orEmpty()
|
||||
|
||||
internal val Project.compileAllTask
|
||||
get() = getOrRegisterTask(COMPILE_ALL_TASK_NAME)
|
||||
|
||||
internal fun Project.targetIsRequested(target: KonanTarget): Boolean {
|
||||
val targets = requestedTargets
|
||||
return (targets.isEmpty() || targets.contains(target.visibleName) || targets.contains("all"))
|
||||
}
|
||||
|
||||
/**
|
||||
* Looks for task with given name in the given project.
|
||||
* If such task isn't found, will register it. Returns registered/found task.
|
||||
*/
|
||||
private fun Project.getOrRegisterTask(name: String): TaskProvider<out Task> = if (tasks.names.contains(name)) {
|
||||
tasks.named(name)
|
||||
} else {
|
||||
tasks.register(name, DefaultTask::class.java)
|
||||
}
|
||||
|
||||
internal fun Project.konanCompilerName(): String =
|
||||
"kotlin-native-${project.simpleOsName}-${project.konanVersion}"
|
||||
|
||||
internal fun Project.konanCompilerDownloadDir(): String =
|
||||
DependencyDirectories.localKonanDir.resolve(project.konanCompilerName()).absolutePath
|
||||
|
||||
// region Useful extensions and functions ---------------------------------------
|
||||
|
||||
internal fun MutableList<String>.addArg(parameter: String, value: String) {
|
||||
add(parameter)
|
||||
add(value)
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addArgs(parameter: String, values: Iterable<String>) {
|
||||
values.forEach {
|
||||
addArg(parameter, it)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addArgIfNotNull(parameter: String, value: String?) {
|
||||
if (value != null) {
|
||||
addArg(parameter, value)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addKey(key: String, enabled: Boolean) {
|
||||
if (enabled) {
|
||||
add(key)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addFileArgs(parameter: String, values: FileCollection) {
|
||||
values.files.forEach {
|
||||
addArg(parameter, it.canonicalPath)
|
||||
}
|
||||
}
|
||||
|
||||
internal fun MutableList<String>.addFileArgs(parameter: String, values: Collection<FileCollection>) {
|
||||
values.forEach {
|
||||
addFileArgs(parameter, it)
|
||||
}
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
internal fun dumpProperties(task: Task) {
|
||||
fun Iterable<String>.dump() = joinToString(prefix = "[", separator = ",\n${" ".repeat(22)}", postfix = "]")
|
||||
fun Collection<FileCollection>.dump() = flatMap { it.files }.map { it.canonicalPath }.dump()
|
||||
when (task) {
|
||||
is KonanCompileTask -> with(task) {
|
||||
println()
|
||||
println("Compilation task: $name")
|
||||
println("destinationDir : $destinationDir")
|
||||
println("artifact : ${artifact.canonicalPath}")
|
||||
println("srcFiles : ${srcFiles.dump()}")
|
||||
println("produce : $produce")
|
||||
println("libraries : ${libraries.files.dump()}")
|
||||
println(" : ${libraries.artifacts.map {
|
||||
it.artifact.canonicalPath
|
||||
}.dump()}")
|
||||
println(" : ${libraries.namedKlibs.dump()}")
|
||||
println("nativeLibraries : ${nativeLibraries.dump()}")
|
||||
println("linkerOpts : $linkerOpts")
|
||||
println("enableDebug : $enableDebug")
|
||||
println("noStdLib : $noStdLib")
|
||||
println("noMain : $noMain")
|
||||
println("enableOptimization : $enableOptimizations")
|
||||
println("enableAssertions : $enableAssertions")
|
||||
println("noDefaultLibs : $noDefaultLibs")
|
||||
println("noEndorsedLibs : $noEndorsedLibs")
|
||||
println("target : $target")
|
||||
println("languageVersion : $languageVersion")
|
||||
println("apiVersion : $apiVersion")
|
||||
println("konanVersion : ${KotlinVersion.CURRENT}")
|
||||
println("konanHome : $konanHome")
|
||||
println()
|
||||
}
|
||||
is KonanInteropTask -> with(task) {
|
||||
println()
|
||||
println("Stub generation task: $name")
|
||||
println("destinationDir : $destinationDir")
|
||||
println("artifact : $artifact")
|
||||
println("libraries : ${libraries.files.dump()}")
|
||||
println(" : ${libraries.artifacts.map {
|
||||
it.artifact.canonicalPath
|
||||
}.dump()}")
|
||||
println(" : ${libraries.namedKlibs.dump()}")
|
||||
println("defFile : $defFile")
|
||||
println("target : $target")
|
||||
println("packageName : $packageName")
|
||||
println("compilerOpts : $compilerOpts")
|
||||
println("linkerOpts : $linkerOpts")
|
||||
println("headers : ${headers.dump()}")
|
||||
println("linkFiles : ${linkFiles.dump()}")
|
||||
println("konanVersion : ${KotlinVersion.CURRENT}")
|
||||
println("konanHome : $konanHome")
|
||||
println()
|
||||
}
|
||||
else -> {
|
||||
println("Unsupported task.")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class KonanExtension {
|
||||
var targets = mutableListOf("host")
|
||||
var languageVersion: String? = null
|
||||
var apiVersion: String? = null
|
||||
var jvmArgs = mutableListOf<String>()
|
||||
}
|
||||
|
||||
open class KonanSoftwareComponent(val project: ProjectInternal?): SoftwareComponentInternal, ComponentWithVariants {
|
||||
private val usages = mutableSetOf<UsageContext>()
|
||||
override fun getUsages(): MutableSet<out UsageContext> = usages
|
||||
|
||||
private val variants = mutableSetOf<SoftwareComponent>()
|
||||
override fun getName() = "main"
|
||||
|
||||
override fun getVariants(): Set<SoftwareComponent> = variants
|
||||
|
||||
fun addVariant(component: SoftwareComponent) = variants.add(component)
|
||||
}
|
||||
|
||||
class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderRegistry)
|
||||
: Plugin<ProjectInternal> {
|
||||
|
||||
enum class ProjectProperty(val propertyName: String, val deprecatedPropertyName: String? = null) {
|
||||
KONAN_HOME ("org.jetbrains.kotlin.native.home", "konan.home"),
|
||||
KONAN_VERSION ("org.jetbrains.kotlin.native.version"),
|
||||
KONAN_BUILD_TARGETS ("konan.build.targets"),
|
||||
KONAN_JVM_ARGS ("konan.jvmArgs"),
|
||||
KONAN_JVM_LAUNCHER ("konan.javaLauncher"),
|
||||
KONAN_USE_ENVIRONMENT_VARIABLES("konan.useEnvironmentVariables"),
|
||||
DOWNLOAD_COMPILER ("download.compiler"),
|
||||
|
||||
// Properties used instead of env vars until https://github.com/gradle/gradle/issues/3468 is fixed.
|
||||
// TODO: Remove them when an API for env vars is provided.
|
||||
KONAN_CONFIGURATION_BUILD_DIR ("konan.configuration.build.dir"),
|
||||
KONAN_DEBUGGING_SYMBOLS ("konan.debugging.symbols"),
|
||||
KONAN_OPTIMIZATIONS_ENABLE ("konan.optimizations.enable"),
|
||||
}
|
||||
|
||||
companion object {
|
||||
internal const val ARTIFACTS_CONTAINER_NAME = "konanArtifacts"
|
||||
internal const val COMPILE_ALL_TASK_NAME = "compileKonan"
|
||||
|
||||
internal const val KONAN_EXTENSION_NAME = "konan"
|
||||
|
||||
internal val REQUIRED_GRADLE_VERSION = GradleVersion.version("6.7")
|
||||
}
|
||||
|
||||
private fun Project.cleanKonan() = project.tasks.withType(KonanBuildingTask::class.java).forEach {
|
||||
project.delete(it.artifact)
|
||||
}
|
||||
|
||||
private fun checkGradleVersion() = GradleVersion.current().let { current ->
|
||||
check(current >= REQUIRED_GRADLE_VERSION) {
|
||||
"Kotlin/Native Gradle plugin is incompatible with this version of Gradle.\n" +
|
||||
"The minimal required version is $REQUIRED_GRADLE_VERSION\n" +
|
||||
"Current version is ${current}"
|
||||
}
|
||||
}
|
||||
|
||||
private lateinit var konanJvmLauncher: JavaLauncher
|
||||
|
||||
private fun getJavaLauncher(project: Project): Provider<JavaLauncher> = project.providers.provider {
|
||||
if (!::konanJvmLauncher.isInitialized) {
|
||||
val toolchain = project.extensions.getByType(JavaPluginExtension::class.java).toolchain
|
||||
val service = project.extensions.getByType(JavaToolchainService::class.java)
|
||||
konanJvmLauncher = try {
|
||||
service.launcherFor(toolchain).get()
|
||||
} catch (ex: GradleException) {
|
||||
// If the JDK that was set is not available get the JDK 11 as a default
|
||||
service.launcherFor(object : Action<JavaToolchainSpec> {
|
||||
override fun execute(toolchainSpec: JavaToolchainSpec) {
|
||||
toolchainSpec.languageVersion.set(JavaLanguageVersion.of(11)) // FIXME: not resolved from buildSrc JdkMajorVersion.JDK_11_0.majorVersion))
|
||||
}
|
||||
}).get()
|
||||
}
|
||||
}
|
||||
konanJvmLauncher
|
||||
}
|
||||
|
||||
override fun apply(project: ProjectInternal) {
|
||||
checkGradleVersion()
|
||||
project.plugins.apply("base")
|
||||
project.plugins.apply("java")
|
||||
// Create necessary tasks and extensions.
|
||||
project.extensions.create(KONAN_EXTENSION_NAME, KonanExtension::class.java)
|
||||
val container = project.extensions.create(
|
||||
KonanArtifactContainer::class.java,
|
||||
ARTIFACTS_CONTAINER_NAME,
|
||||
KonanArtifactContainer::class.java,
|
||||
project
|
||||
)
|
||||
project.setProperty(ProjectProperty.KONAN_JVM_LAUNCHER, getJavaLauncher(project))
|
||||
|
||||
project.warnAboutDeprecatedProperty(ProjectProperty.KONAN_HOME)
|
||||
|
||||
// Set additional project properties like org.jetbrains.kotlin.native.home, konan.build.targets etc.
|
||||
if (!project.useCustomDist) {
|
||||
project.setProperty(ProjectProperty.KONAN_HOME, project.konanCompilerDownloadDir())
|
||||
project.setProperty(ProjectProperty.DOWNLOAD_COMPILER, true)
|
||||
}
|
||||
|
||||
// Register and set up aggregate building tasks.
|
||||
val compileKonanTask = project.getOrRegisterTask(COMPILE_ALL_TASK_NAME).configure {
|
||||
group = BasePlugin.BUILD_GROUP
|
||||
description = "Compiles all the Kotlin/Native artifacts"
|
||||
}
|
||||
project.tasks.named("build").configure {
|
||||
dependsOn(compileKonanTask)
|
||||
}
|
||||
project.tasks.named("clean").configure {
|
||||
doLast { project.cleanKonan() }
|
||||
}
|
||||
|
||||
project.afterEvaluate {
|
||||
project.tasks
|
||||
.withType(KonanCompileProgramTask::class.java)
|
||||
.forEach { task ->
|
||||
val isCrossCompile = (task.target != HostManager.host.visibleName)
|
||||
if (!isCrossCompile && !project.hasProperty("konanNoRun"))
|
||||
task.runTask = project.tasks.register(
|
||||
"run${task.artifactName.replaceFirstChar { it.uppercase() }}", Exec::class.java) {
|
||||
group = "run"
|
||||
dependsOn(task)
|
||||
val artifactPathClosure = object : Closure<String>(this) {
|
||||
override fun call() = task.artifactPath
|
||||
}
|
||||
// Use GString to evaluate a path to the artifact lazily thus allow changing it at configuration phase.
|
||||
val lazyArtifactPath = GStringImpl(arrayOf(artifactPathClosure), arrayOf(""))
|
||||
executable(lazyArtifactPath)
|
||||
// Add values passed in the runArgs project property as arguments.
|
||||
argumentProviders.add(task.RunArgumentProvider())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val runTask = project.getOrRegisterTask("run")
|
||||
project.afterEvaluate {
|
||||
project.konanArtifactsContainer
|
||||
.filterIsInstance(KonanProgram::class.java)
|
||||
.forEach { program ->
|
||||
program.tasks().forEach { compile ->
|
||||
compile.configure { this@configure.runTask?.let { runTask.configure { dependsOn(it) } } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Enable multiplatform support
|
||||
project.pluginManager.apply(KotlinNativePlatformPlugin::class.java)
|
||||
project.afterEvaluate {
|
||||
project.pluginManager.withPlugin("maven-publish") {
|
||||
container.all { buildingConfig ->
|
||||
val konanSoftwareComponent = buildingConfig.mainVariant
|
||||
project.extensions.configure(PublishingExtension::class.java) {
|
||||
val builtArtifact = buildingConfig.name
|
||||
val mavenPublication = publications.maybeCreate(builtArtifact, MavenPublication::class.java)
|
||||
mavenPublication.apply {
|
||||
artifactId = builtArtifact
|
||||
groupId = project.group.toString()
|
||||
from(konanSoftwareComponent)
|
||||
}
|
||||
(mavenPublication as MavenPublicationInternal).publishWithOriginalFileName()
|
||||
buildingConfig.pomActions.forEach {
|
||||
mavenPublication.pom(it)
|
||||
}
|
||||
}
|
||||
|
||||
project.extensions.configure(PublishingExtension::class.java) {
|
||||
for (v in konanSoftwareComponent.variants) {
|
||||
this@configure.publications.create(v.name, MavenPublication::class.java) {
|
||||
val coordinates = (v as NativeVariantIdentity).coordinates
|
||||
project.logger.info("variant with coordinates($coordinates) and module: ${coordinates.module}")
|
||||
artifactId = coordinates.module.name
|
||||
groupId = coordinates.group
|
||||
version = coordinates.version
|
||||
from(v)
|
||||
(this as MavenPublicationInternal).publishWithOriginalFileName()
|
||||
buildingConfig.pomActions.forEach {
|
||||
pom(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
-117
@@ -1,117 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.file.FileCollection
|
||||
|
||||
interface KonanArtifactSpec {
|
||||
fun artifactName(name: String)
|
||||
}
|
||||
|
||||
interface KonanArtifactWithLibrariesSpec: KonanArtifactSpec {
|
||||
fun libraries(closure: Closure<Unit>)
|
||||
fun libraries(action: Action<KonanLibrariesSpec>)
|
||||
fun libraries(configure: KonanLibrariesSpec.() -> Unit)
|
||||
|
||||
fun noDefaultLibs(flag: Boolean)
|
||||
fun noEndorsedLibs(flag: Boolean)
|
||||
fun dependencies(closure: Closure<Unit>)
|
||||
}
|
||||
|
||||
interface KonanBuildingSpec: KonanArtifactWithLibrariesSpec {
|
||||
fun dumpParameters(flag: Boolean)
|
||||
|
||||
fun extraOpts(vararg values: Any)
|
||||
fun extraOpts(values: List<Any>)
|
||||
}
|
||||
|
||||
interface KonanCompileSpec: KonanBuildingSpec {
|
||||
fun srcDir(dir: Any)
|
||||
|
||||
fun srcFiles(vararg files: Any)
|
||||
fun srcFiles(files: Collection<Any>)
|
||||
|
||||
// DSL. Native libraries.
|
||||
|
||||
fun nativeLibrary(lib: Any)
|
||||
fun nativeLibraries(vararg libs: Any)
|
||||
fun nativeLibraries(libs: FileCollection)
|
||||
|
||||
// DSL. Multiplatform projects
|
||||
fun enableMultiplatform(flag: Boolean)
|
||||
|
||||
// TODO: Get rid of commonSourceSet in 0.7
|
||||
@Deprecated("Use commonSourceSets instead", ReplaceWith("commonSourceSets(sourceSetName)"))
|
||||
fun commonSourceSet(sourceSetName: String)
|
||||
fun commonSourceSets(vararg sourceSetNames: String)
|
||||
|
||||
fun commonSrcDir(dir: Any)
|
||||
|
||||
fun commonSrcFiles(vararg files: Any)
|
||||
fun commonSrcFiles(files: Collection<Any>)
|
||||
|
||||
// DSL. Other parameters.
|
||||
|
||||
fun linkerOpts(vararg values: String)
|
||||
fun linkerOpts(values: List<String>)
|
||||
|
||||
fun enableDebug(flag: Boolean)
|
||||
fun noStdLib(flag: Boolean)
|
||||
fun noMain(flag: Boolean)
|
||||
fun noPack(flag: Boolean)
|
||||
fun enableOptimizations(flag: Boolean)
|
||||
fun enableAssertions(flag: Boolean)
|
||||
|
||||
fun entryPoint(entryPoint: String)
|
||||
|
||||
fun measureTime(flag: Boolean)
|
||||
}
|
||||
|
||||
interface KonanInteropSpec: KonanBuildingSpec {
|
||||
|
||||
interface IncludeDirectoriesSpec {
|
||||
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 compilerOpts(vararg values: 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<IncludeDirectoriesSpec>)
|
||||
fun includeDirs(configure: IncludeDirectoriesSpec.() -> Unit)
|
||||
|
||||
fun linkerOpts(vararg values: String)
|
||||
fun linkerOpts(values: List<String>)
|
||||
|
||||
fun link(vararg files: Any)
|
||||
fun link(files: FileCollection)
|
||||
}
|
||||
-192
@@ -1,192 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.konan
|
||||
|
||||
import kotlinBuildProperties
|
||||
import org.gradle.api.Project
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.KonanPlugin.ProjectProperty.KONAN_HOME
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.nio.file.Files
|
||||
import org.jetbrains.kotlin.*
|
||||
import org.jetbrains.kotlin.konan.properties.resolvablePropertyString
|
||||
import org.jetbrains.kotlin.konan.util.DependencyDirectories
|
||||
import java.io.File
|
||||
import java.util.Properties
|
||||
import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner
|
||||
import org.jetbrains.kotlin.konan.target.AbstractToolConfig
|
||||
import java.net.URLClassLoader
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
internal interface KonanToolRunner {
|
||||
fun run(args: List<String>)
|
||||
}
|
||||
|
||||
internal fun KonanToolRunner.run(vararg args: String) = run(args.toList())
|
||||
|
||||
private const val runFromDaemonPropertyName = "kotlin.native.tool.runFromDaemon"
|
||||
|
||||
@Suppress("DEPRECATION") // calling KotlinToolRunner(project) constructor is deprecated
|
||||
internal abstract class KonanCliRunner(
|
||||
protected val toolName: String,
|
||||
project: Project,
|
||||
val additionalJvmArgs: List<String> = emptyList(),
|
||||
val konanHome: String = project.konanHome
|
||||
) : KotlinToolRunner(project), KonanToolRunner {
|
||||
final override val displayName get() = toolName
|
||||
|
||||
final override val mainClass get() = "org.jetbrains.kotlin.cli.utilities.MainKt"
|
||||
final override val daemonEntryPoint get() = "daemonMain"
|
||||
|
||||
override val mustRunViaExec get() = false.also { System.setProperty(runFromDaemonPropertyName, "true") }
|
||||
|
||||
final override val execSystemPropertiesBlacklist: Set<String>
|
||||
get() = super.execSystemPropertiesBlacklist + runFromDaemonPropertyName
|
||||
|
||||
// We need to unset some environment variables which are set by XCode and may potentially affect the tool executed.
|
||||
final override val execEnvironmentBlacklist: Set<String> by lazy {
|
||||
HashSet<String>().also { collector ->
|
||||
KonanPlugin::class.java.getResourceAsStream("/env_blacklist")?.let { stream ->
|
||||
stream.reader().use { r -> r.forEachLine { collector.add(it) } }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
final override val execSystemProperties by lazy { mapOf("konan.home" to konanHome) }
|
||||
|
||||
final override val classpath by lazy {
|
||||
project.fileTree("$konanHome/konan/lib/").apply {
|
||||
include("trove4j.jar")
|
||||
include("kotlin-native-compiler-embeddable.jar")
|
||||
}.files
|
||||
}
|
||||
|
||||
final override fun checkClasspath() =
|
||||
check(classpath.isNotEmpty()) {
|
||||
"""
|
||||
Classpath of the tool is empty: $toolName
|
||||
Probably the '${KONAN_HOME.propertyName}' project property contains an incorrect path.
|
||||
Please change it to the compiler root directory and rerun the build.
|
||||
""".trimIndent()
|
||||
}
|
||||
|
||||
data class IsolatedClassLoaderCacheKey(val classpath: Set<File>)
|
||||
|
||||
// TODO: can't we use this for other implementations too?
|
||||
final override val isolatedClassLoaderCacheKey get() = IsolatedClassLoaderCacheKey(classpath)
|
||||
|
||||
// A separate map for each build for automatic cleaning the daemon after the build have finished.
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
final override val isolatedClassLoaders = project.project(":kotlin-native").ext["toolClassLoadersMap"] as ConcurrentHashMap<Any, URLClassLoader>
|
||||
|
||||
override fun transformArgs(args: List<String>) = listOf(toolName) + args
|
||||
|
||||
final override fun getCustomJvmArgs() = additionalJvmArgs
|
||||
}
|
||||
|
||||
/** Kotlin/Native compiler runner */
|
||||
internal class KonanCliCompilerRunner(
|
||||
project: Project,
|
||||
additionalJvmArgs: List<String> = emptyList(),
|
||||
val useArgFile: Boolean = true,
|
||||
konanHome: String = project.konanHome
|
||||
) : KonanCliRunner("konanc", project, additionalJvmArgs, konanHome) {
|
||||
override fun transformArgs(args: List<String>): List<String> {
|
||||
if (!useArgFile) return super.transformArgs(args)
|
||||
|
||||
val argFile = Files.createTempFile(/* prefix = */ "konancArgs", /* suffix = */ ".lst").toFile().apply { deleteOnExit() }
|
||||
argFile.printWriter().use { w ->
|
||||
for (arg in args) {
|
||||
val escapedArg = arg
|
||||
.replace("\\", "\\\\")
|
||||
.replace("\"", "\\\"")
|
||||
w.println("\"$escapedArg\"")
|
||||
}
|
||||
}
|
||||
|
||||
return listOf(toolName, "@${argFile.absolutePath}")
|
||||
}
|
||||
}
|
||||
|
||||
private val load0 = Runtime::class.java.getDeclaredMethod("load0", Class::class.java, String::class.java).also {
|
||||
it.isAccessible = true
|
||||
}
|
||||
|
||||
internal class CliToolConfig(konanHome: String, target: String) : AbstractToolConfig(konanHome, target, emptyMap()) {
|
||||
override fun loadLibclang() {
|
||||
// Load libclang into the system class loader. This is needed to allow developers to make changes
|
||||
// in the tooling infrastructure without having to stop the daemon (otherwise libclang might end up
|
||||
// loaded in two different class loaders which is not allowed by the JVM).
|
||||
load0.invoke(Runtime.getRuntime(), String::class.java, libclang)
|
||||
}
|
||||
}
|
||||
|
||||
/** Kotlin/Native C-interop tool runner */
|
||||
internal class KonanCliInteropRunner(
|
||||
private val project: Project,
|
||||
additionalJvmArgs: List<String> = emptyList(),
|
||||
konanHome: String = project.konanHome
|
||||
) : KonanCliRunner("cinterop", project, additionalJvmArgs, konanHome) {
|
||||
private val projectDir = project.projectDir.toString()
|
||||
|
||||
override val mustRunViaExec: Boolean
|
||||
get() = if (project.kotlinBuildProperties.getBoolean("kotlin.native.allowRunningCinteropInProcess")) {
|
||||
super.mustRunViaExec
|
||||
} else {
|
||||
true
|
||||
}
|
||||
|
||||
override fun transformArgs(args: List<String>): List<String> {
|
||||
return super.transformArgs(args) + listOf("-Xproject-dir", projectDir)
|
||||
}
|
||||
|
||||
override val execEnvironment by lazy {
|
||||
val result = mutableMapOf<String, String>()
|
||||
result.putAll(super.execEnvironment)
|
||||
result["LIBCLANG_DISABLE_CRASH_RECOVERY"] = "1"
|
||||
llvmExecutablesPath?.let {
|
||||
result["PATH"] = "$it;${System.getenv("PATH")}"
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
fun init(target: String) {
|
||||
CliToolConfig(konanHome, target).prepare()
|
||||
}
|
||||
|
||||
private val llvmExecutablesPath: String? by lazy {
|
||||
if (HostManager.host == KonanTarget.MINGW_X64) {
|
||||
// TODO: Read it from Platform properties when it is accessible.
|
||||
val konanProperties = Properties().apply {
|
||||
project.file("$konanHome/konan/konan.properties").inputStream().use(::load)
|
||||
}
|
||||
|
||||
konanProperties.resolvablePropertyString("llvmHome.mingw_x64")?.let { toolchainDir ->
|
||||
DependencyDirectories.defaultDependenciesRoot
|
||||
.resolve("$toolchainDir/bin")
|
||||
.absolutePath
|
||||
}
|
||||
} else
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
internal class KonanKlibRunner(
|
||||
project: Project,
|
||||
additionalJvmArgs: List<String> = emptyList(),
|
||||
konanHome: String = project.konanHome
|
||||
) : KonanCliRunner("klib", project, additionalJvmArgs, konanHome)
|
||||
-38
@@ -1,38 +0,0 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.konan
|
||||
|
||||
import org.gradle.api.Named
|
||||
import org.gradle.api.NamedDomainObjectContainer
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformImplementationPluginBase
|
||||
import org.jetbrains.kotlin.gradle.plugin.tasks.KonanCompileTask
|
||||
import javax.inject.Inject
|
||||
|
||||
open class KotlinNativePlatformPlugin: KotlinPlatformImplementationPluginBase("native") {
|
||||
|
||||
private val Project.konanMultiplatformTasks: Collection<KonanCompileTask>
|
||||
get() = tasks.withType(KonanCompileTask::class.java).filter { it.enableMultiplatform }
|
||||
|
||||
open class RequestedCommonSourceSet @Inject constructor(private val name: String): Named {
|
||||
override fun getName() = name
|
||||
}
|
||||
|
||||
override fun addCommonSourceSetToPlatformSourceSet(commonSourceSet: Named, platformProject: Project) {
|
||||
val commonSourceSetName = commonSourceSet.name
|
||||
|
||||
platformProject.konanMultiplatformTasks
|
||||
.filter { it.commonSourceSets.contains(commonSourceSetName) }
|
||||
.forEach { task: KonanCompileTask ->
|
||||
getKotlinSourceDirectorySetSafe(commonSourceSet)!!.srcDirs.forEach {
|
||||
task.commonSrcDir(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun namedSourceSetsContainer(project: Project): NamedDomainObjectContainer<*> =
|
||||
project.container(RequestedCommonSourceSet::class.java).apply {
|
||||
project.konanMultiplatformTasks.forEach { task ->
|
||||
task.commonSourceSets.forEach { maybeCreate(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
-187
@@ -1,187 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.tasks
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.*
|
||||
import org.gradle.api.attributes.Attribute
|
||||
import org.gradle.api.attributes.AttributeContainer
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.capabilities.Capability
|
||||
import org.gradle.api.internal.component.DefaultSoftwareComponentVariant
|
||||
import org.gradle.api.internal.component.UsageContext
|
||||
import org.gradle.api.internal.tasks.DefaultTaskDependency
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.language.cpp.CppBinary
|
||||
import org.gradle.nativeplatform.Linkage
|
||||
import org.jetbrains.kotlin.gradle.plugin.experimental.internal.compatibleVariantIdentity
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.*
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
||||
internal val Project.host
|
||||
get() = HostManager.host.visibleName
|
||||
|
||||
internal val Project.simpleOsName
|
||||
get() = HostManager.platformName()
|
||||
|
||||
/** A task with a KonanTarget specified. */
|
||||
abstract class KonanTargetableTask: DefaultTask() {
|
||||
|
||||
@get:Input
|
||||
val konanTargetName: String
|
||||
get() = konanTarget.name
|
||||
|
||||
@get:Internal
|
||||
internal lateinit var konanTarget: KonanTarget
|
||||
|
||||
internal open fun init(target: KonanTarget) {
|
||||
this.konanTarget = target
|
||||
}
|
||||
|
||||
val isCrossCompile: Boolean
|
||||
@Internal get() = (konanTarget != HostManager.host)
|
||||
|
||||
val target: String
|
||||
@Internal get() = konanTarget.visibleName
|
||||
}
|
||||
|
||||
/** A task building an artifact. */
|
||||
abstract class KonanArtifactTask: KonanTargetableTask(), KonanArtifactSpec {
|
||||
|
||||
open val artifact: File
|
||||
@OutputFile get() = destinationDir.resolve(artifactFullName)
|
||||
|
||||
@Internal lateinit var destinationDir: File
|
||||
@Internal lateinit var artifactName: String
|
||||
@Internal lateinit var platformConfiguration: Configuration
|
||||
@Internal lateinit var configuration: Configuration
|
||||
|
||||
protected val artifactFullName: String
|
||||
@Internal get() = "$artifactPrefix$artifactName$artifactSuffix"
|
||||
|
||||
val artifactPath: String
|
||||
@Internal get() = artifact.canonicalPath
|
||||
|
||||
protected abstract val artifactSuffix: String
|
||||
@Internal get
|
||||
|
||||
protected abstract val artifactPrefix: String
|
||||
@Internal get
|
||||
|
||||
internal open fun init(config: KonanBuildingConfig<*>, destinationDir: File, artifactName: String, target: KonanTarget) {
|
||||
super.init(target)
|
||||
this.destinationDir = destinationDir
|
||||
this.artifactName = artifactName
|
||||
configuration = project.configurations.maybeCreate("artifact$artifactName")
|
||||
platformConfiguration = project.configurations.create("artifact${artifactName}_${target.name}")
|
||||
platformConfiguration.extendsFrom(configuration)
|
||||
platformConfiguration.attributes{
|
||||
attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.NATIVE_LINK))
|
||||
attribute(CppBinary.LINKAGE_ATTRIBUTE, Linkage.STATIC)
|
||||
attribute(CppBinary.OPTIMIZED_ATTRIBUTE, false)
|
||||
attribute(CppBinary.DEBUGGABLE_ATTRIBUTE, false)
|
||||
attribute(Attribute.of("org.gradle.native.kotlin.platform", String::class.java), target.name)
|
||||
}
|
||||
|
||||
val artifactNameWithoutSuffix = artifact.name.removeSuffix("$artifactSuffix")
|
||||
project.pluginManager.withPlugin("maven-publish") {
|
||||
platformConfiguration.artifacts.add(object: PublishArtifact {
|
||||
override fun getName(): String = artifactNameWithoutSuffix
|
||||
override fun getExtension() = if (artifactSuffix.startsWith('.')) artifactSuffix.substring(1) else artifactSuffix
|
||||
override fun getType() = artifactSuffix
|
||||
override fun getClassifier():String? = target.name
|
||||
override fun getFile() = artifact
|
||||
override fun getDate() = Date(artifact.lastModified())
|
||||
override fun getBuildDependencies(): TaskDependency =
|
||||
DefaultTaskDependency().apply { add(this@KonanArtifactTask) }
|
||||
})
|
||||
val objectFactory = project.objects
|
||||
val linkUsage = objectFactory.named(Usage::class.java, Usage.NATIVE_LINK)
|
||||
val konanSoftwareComponent = config.mainVariant
|
||||
val variantName = "${artifactNameWithoutSuffix}_${target.name}"
|
||||
val context = DefaultSoftwareComponentVariant(
|
||||
"${variantName}Link",
|
||||
platformConfiguration.attributes,
|
||||
platformConfiguration.allArtifacts,
|
||||
mutableSetOf(),
|
||||
mutableSetOf(),
|
||||
mutableSetOf(),
|
||||
emptySet(),
|
||||
)
|
||||
konanSoftwareComponent.addVariant(
|
||||
compatibleVariantIdentity(
|
||||
project,
|
||||
variantName,
|
||||
project.provider{ artifactName },
|
||||
project.provider{ project.group.toString() },
|
||||
project.provider{ project.version.toString() },
|
||||
false,
|
||||
false,
|
||||
target,
|
||||
context,
|
||||
null
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fun dependencies(closure: Closure<Unit>) {
|
||||
if (konanTarget in project.konanTargets)
|
||||
project.dependencies(closure)
|
||||
}
|
||||
// DSL.
|
||||
|
||||
override fun artifactName(name: String) {
|
||||
artifactName = name
|
||||
}
|
||||
|
||||
fun destinationDir(dir: Any) {
|
||||
destinationDir = project.file(dir)
|
||||
}
|
||||
}
|
||||
|
||||
/** Task building an artifact with libraries */
|
||||
abstract class KonanArtifactWithLibrariesTask: KonanArtifactTask(), KonanArtifactWithLibrariesSpec {
|
||||
@Nested
|
||||
val libraries = KonanLibrariesSpec(this, project)
|
||||
|
||||
@Input
|
||||
var noDefaultLibs = false
|
||||
|
||||
@Input
|
||||
var noEndorsedLibs = false
|
||||
|
||||
// DSL
|
||||
|
||||
override fun libraries(closure: Closure<Unit>) = libraries { project.configure(this, closure) }
|
||||
override fun libraries(action: Action<KonanLibrariesSpec>) = libraries { action.execute(this) }
|
||||
override fun libraries(configure: KonanLibrariesSpec.() -> Unit) { libraries.configure() }
|
||||
|
||||
override fun noDefaultLibs(flag: Boolean) {
|
||||
noDefaultLibs = flag
|
||||
}
|
||||
|
||||
override fun noEndorsedLibs(flag: Boolean) {
|
||||
noEndorsedLibs = flag
|
||||
}
|
||||
}
|
||||
-60
@@ -1,60 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.tasks
|
||||
|
||||
import org.gradle.api.tasks.Console
|
||||
import org.gradle.api.tasks.Input
|
||||
import org.gradle.api.tasks.Internal
|
||||
import org.gradle.api.tasks.TaskAction
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
import org.jetbrains.kotlin.dependsOnDist
|
||||
|
||||
/** Base class for both interop and compiler tasks. */
|
||||
abstract class KonanBuildingTask: KonanArtifactWithLibrariesTask(), KonanBuildingSpec {
|
||||
|
||||
@get:Internal
|
||||
internal abstract val toolRunner: KonanToolRunner
|
||||
|
||||
override fun init(config: KonanBuildingConfig<*>, destinationDir: File, artifactName: String, target: KonanTarget) {
|
||||
super.init(config, destinationDir, artifactName, target)
|
||||
}
|
||||
|
||||
@Console
|
||||
var dumpParameters: Boolean = false
|
||||
|
||||
@Input
|
||||
val extraOpts = mutableListOf<String>()
|
||||
|
||||
val konanHome
|
||||
@Input get() = project.konanHome
|
||||
|
||||
@TaskAction
|
||||
abstract fun run()
|
||||
|
||||
// DSL.
|
||||
|
||||
override fun dumpParameters(flag: Boolean) {
|
||||
dumpParameters = flag
|
||||
}
|
||||
|
||||
override fun extraOpts(vararg values: Any) = extraOpts(values.toList())
|
||||
override fun extraOpts(values: List<Any>) {
|
||||
extraOpts.addAll(values.map { it.toString() })
|
||||
}
|
||||
}
|
||||
-106
@@ -1,106 +0,0 @@
|
||||
package org.jetbrains.kotlin.gradle.plugin.konan.tasks
|
||||
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.file.Directory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.KonanCliCompilerRunner
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.konanHome
|
||||
import org.jetbrains.kotlin.konan.library.defaultResolver
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.PlatformManager
|
||||
import org.jetbrains.kotlin.library.uniqueName
|
||||
import org.jetbrains.kotlin.*
|
||||
import java.io.File
|
||||
|
||||
enum class KonanCacheKind(val outputKind: CompilerOutputKind) {
|
||||
STATIC(CompilerOutputKind.STATIC_CACHE),
|
||||
DYNAMIC(CompilerOutputKind.DYNAMIC_CACHE)
|
||||
}
|
||||
|
||||
open class KonanCacheTask: DefaultTask() {
|
||||
@get:InputDirectory
|
||||
var originalKlib: File? = null
|
||||
|
||||
@get:Input
|
||||
lateinit var klibUniqName: String
|
||||
|
||||
@get:Input
|
||||
lateinit var cacheRoot: String
|
||||
|
||||
@get:Input
|
||||
lateinit var target: String
|
||||
|
||||
@get:Internal
|
||||
// TODO: Reuse NativeCacheKind from Big Kotlin plugin when it is available.
|
||||
val cacheDirectory: File
|
||||
get() = File("$cacheRoot/$target-g$cacheKind")
|
||||
|
||||
@get:OutputDirectory
|
||||
val cacheFile: File
|
||||
get() = cacheDirectory.resolve(if (makePerFileCache) "${klibUniqName}-per-file-cache" else "${klibUniqName}-cache")
|
||||
|
||||
/**
|
||||
* Note: we can't use this function instead of [klibUniqName] in [cacheFile],
|
||||
* because the latter is `@OutputDirectory`, so Gradle can call it even before
|
||||
* the task dependencies are finished, and [originalKlib] might be not build yet.
|
||||
*/
|
||||
private fun readKlibUniqNameFromManifest(): String {
|
||||
val konanHome = compilerDistributionPath.get().absolutePath
|
||||
val resolver = defaultResolver(
|
||||
emptyList(),
|
||||
PlatformManager(konanHome).targetByName(target),
|
||||
Distribution(konanHome)
|
||||
)
|
||||
return resolver.resolve(originalKlib!!.absolutePath).uniqueName
|
||||
}
|
||||
|
||||
@get:Input
|
||||
var cacheKind: KonanCacheKind = KonanCacheKind.STATIC
|
||||
|
||||
@get:Input
|
||||
var makePerFileCache: Boolean = false
|
||||
|
||||
@get:Input
|
||||
/** Path to a compiler distribution that is used to build this cache. */
|
||||
val compilerDistributionPath: Property<File> = project.objects.property(File::class.java).apply {
|
||||
set(project.provider { project.kotlinNativeDist })
|
||||
}
|
||||
|
||||
@get:Input
|
||||
var cachedLibraries: Map<File, File> = emptyMap()
|
||||
|
||||
@TaskAction
|
||||
fun compile() {
|
||||
// This code uses bootstrap version of util-klib and fails due to the older default ABI than library being used
|
||||
// A possible solution is to read it manually from manifest file or this check should be done by the compiler itself
|
||||
// check(klibUniqName == readKlibUniqNameFromManifest()) {
|
||||
// "klibUniqName mismatch: configured '$klibUniqName', resolved '${readKlibUniqNameFromManifest()}'"
|
||||
// }
|
||||
|
||||
// Compiler doesn't create a cache if the cacheFile already exists. So we need to remove it manually.
|
||||
if (cacheFile.exists()) {
|
||||
val deleted = cacheFile.deleteRecursively()
|
||||
check(deleted) { "Cannot delete stale cache: ${cacheFile.absolutePath}" }
|
||||
}
|
||||
cacheDirectory.mkdirs()
|
||||
val konanHome = compilerDistributionPath.get().absolutePath
|
||||
val additionalCacheFlags = PlatformManager(konanHome).let {
|
||||
it.targetByName(target).let(it::loader).additionalCacheFlags
|
||||
}
|
||||
requireNotNull(originalKlib)
|
||||
val args = mutableListOf(
|
||||
"-g",
|
||||
"-target", target,
|
||||
"-produce", cacheKind.outputKind.name.toLowerCase(),
|
||||
"-Xadd-cache=${originalKlib?.absolutePath}",
|
||||
"-Xcache-directory=${cacheDirectory.absolutePath}"
|
||||
)
|
||||
if (makePerFileCache)
|
||||
args += "-Xmake-per-file-cache"
|
||||
args += additionalCacheFlags
|
||||
args += cachedLibraries.map { "-Xcached-library=${it.key},${it.value}" }
|
||||
KonanCliCompilerRunner(project, konanHome = konanHome).run(args)
|
||||
}
|
||||
}
|
||||
-421
@@ -1,421 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2019 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.tasks
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.codehaus.groovy.runtime.GStringImpl
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.file.ConfigurableFileTree
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.process.CommandLineArgumentProvider
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.*
|
||||
import org.jetbrains.kotlin.konan.library.defaultResolver
|
||||
import org.jetbrains.kotlin.konan.target.CompilerOutputKind
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
|
||||
/**
|
||||
* A task compiling the target executable/library using Kotlin/Native compiler
|
||||
*/
|
||||
abstract class KonanCompileTask: KonanBuildingTask(), KonanCompileSpec {
|
||||
|
||||
@get:Internal
|
||||
override val toolRunner = KonanCliCompilerRunner(project, project.konanExtension.jvmArgs)
|
||||
|
||||
abstract val produce: CompilerOutputKind
|
||||
@Internal get
|
||||
|
||||
// Output artifact --------------------------------------------------------
|
||||
|
||||
override val artifactSuffix: String
|
||||
@Internal get() = produce.suffix(konanTarget)
|
||||
|
||||
override val artifactPrefix: String
|
||||
@Internal get() = produce.prefix(konanTarget)
|
||||
|
||||
// Multiplatform support --------------------------------------------------
|
||||
|
||||
@Input var commonSourceSets = listOf("main")
|
||||
|
||||
@Internal var enableMultiplatform = false
|
||||
|
||||
private val commonSrcFiles_ = mutableSetOf<FileCollection>()
|
||||
val commonSrcFiles: Collection<FileCollection>
|
||||
@Internal get() = if (enableMultiplatform) commonSrcFiles_ else emptyList()
|
||||
|
||||
// Other compilation parameters -------------------------------------------
|
||||
|
||||
private val srcFiles_ = mutableSetOf<FileCollection>()
|
||||
val srcFiles: Collection<FileCollection>
|
||||
@Internal get() = srcFiles_.takeIf { !it.isEmpty() } ?: listOf(project.konanDefaultSrcFiles)
|
||||
|
||||
val allSources: Collection<FileCollection>
|
||||
@InputFiles get() = listOf(srcFiles, commonSrcFiles).flatten()
|
||||
|
||||
private val allSourceFiles: List<File>
|
||||
get() = allSources
|
||||
.flatMap { it.files }
|
||||
.filter { it.name.endsWith(".kt") }
|
||||
|
||||
@InputFiles val nativeLibraries = mutableSetOf<FileCollection>()
|
||||
|
||||
@Input val linkerOpts = mutableListOf<String>()
|
||||
|
||||
@Input var enableDebug = project.findProperty("enableDebug")?.toString()?.toBoolean()
|
||||
?: project.environmentVariables.debuggingSymbols
|
||||
|
||||
@Input var noStdLib = false
|
||||
@Input var noMain = false
|
||||
@Input var noPack: Boolean = false
|
||||
@Input var enableOptimizations = project.environmentVariables.enableOptimizations
|
||||
@Input var enableAssertions = false
|
||||
|
||||
@Optional @Input var entryPoint: String? = null
|
||||
|
||||
@Console var measureTime = false
|
||||
|
||||
val languageVersion : String?
|
||||
@Optional @Input get() = project.konanExtension.languageVersion
|
||||
val apiVersion : String?
|
||||
@Optional @Input get() = project.konanExtension.apiVersion
|
||||
|
||||
/**
|
||||
* Is the two-stage compilation enabled.
|
||||
*
|
||||
* In regular (one-stage) compilation, sources are directly compiled into a final native binary.
|
||||
* In two-stage compilation, sources are compiled into a klib first and then a final native binary is produced from this klib.
|
||||
*/
|
||||
@get:Input
|
||||
abstract val enableTwoStageCompilation: Boolean
|
||||
|
||||
protected fun directoryToKt(dir: Any) = project.fileTree(dir).apply {
|
||||
include("**/*.kt")
|
||||
exclude { it.file.startsWith(project.buildDir) }
|
||||
}
|
||||
|
||||
// Command line ------------------------------------------------------------
|
||||
|
||||
// Exclude elements matching the predicate.
|
||||
private fun List<String>.excludeFlags(predicate: (String) -> Boolean) = filterNot(predicate)
|
||||
|
||||
// Exclude the listed elements.
|
||||
private fun List<String>.excludeFlags(vararg keys: String) = keys.toSet().let { keysToExclude ->
|
||||
excludeFlags { it in keysToExclude }
|
||||
}
|
||||
|
||||
// Exclude the arguments passed by the given keys.
|
||||
// E.g. if the list contains the following elements: ["-l", "foo", "-r", "bar"],
|
||||
// call exclude("-r") returns the following list: ["-l", "foo"].
|
||||
private fun List<String>.excludeArguments(vararg args: String): List<String> {
|
||||
val argsToExclude = args.toSet()
|
||||
val xPrefixesToExclude = argsToExclude.filter { it.startsWith("-X") }.map { "$it=" }
|
||||
val result = mutableListOf<String>()
|
||||
|
||||
var i = 0
|
||||
while (i < size) {
|
||||
val key = this[i]
|
||||
when {
|
||||
key in argsToExclude -> {
|
||||
// Skip the key and the following arg.
|
||||
i++
|
||||
}
|
||||
// Support args passed as -X<arg>=<value>.
|
||||
xPrefixesToExclude.any { key.startsWith(it) } -> { /* Skip the key. */ }
|
||||
else -> result += key
|
||||
}
|
||||
i++
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
// Don't include coverage flags into the first stage because they are not supported when compiling a klib.
|
||||
private fun firstStageExtraOpts() = extraOpts
|
||||
.excludeFlags("-Xcoverage")
|
||||
.excludeArguments("-Xcoverage-file", "-Xlibrary-to-cover", "-Xpartial-linkage", "-Xpartial-linkage-loglevel")
|
||||
|
||||
// Don't include the -Xemit-lazy-objc-header and -language-version flags into
|
||||
// the second stage because this stage have no sources.
|
||||
private fun secondStageExtraOpts() = extraOpts
|
||||
.excludeArguments("-Xemit-lazy-objc-header", "-language-version")
|
||||
|
||||
/** Args passed to the compiler at the first stage of two-stage compilation (klib building). */
|
||||
protected fun buildFirstStageArgs(klibPath: String) = mutableListOf<String>().apply {
|
||||
addArg("-output", klibPath)
|
||||
addArg("-produce", CompilerOutputKind.LIBRARY.name.toLowerCase())
|
||||
|
||||
addAll(buildCommonArgs())
|
||||
|
||||
addAll(firstStageExtraOpts())
|
||||
|
||||
allSourceFiles.mapTo(this) { it.absolutePath }
|
||||
commonSrcFiles
|
||||
.flatMap { it.files }
|
||||
.mapTo(this) { "-Xcommon-sources=${it.absolutePath}" }
|
||||
}
|
||||
|
||||
/** Args passed to the compiler at the second stage of two-stage compilation (producing a final binary from the klib). */
|
||||
protected fun buildSecondStageArgs(klibPath: String) = mutableListOf<String>().apply {
|
||||
addArg("-output", artifact.canonicalPath)
|
||||
addArg("-produce", produce.name.toLowerCase())
|
||||
addArgIfNotNull("-entry", entryPoint)
|
||||
|
||||
addAll(buildCommonArgs())
|
||||
|
||||
addFileArgs("-native-library", nativeLibraries)
|
||||
linkerOpts.forEach {
|
||||
addArg("-linker-option", it)
|
||||
}
|
||||
|
||||
addAll(secondStageExtraOpts())
|
||||
|
||||
add("-Xinclude=${klibPath}")
|
||||
}
|
||||
|
||||
/** Args passed to the compiler at both stages of the two-stage compilation and during the singe-stage compilation. */
|
||||
protected open fun buildCommonArgs() = mutableListOf<String>().apply {
|
||||
addArgs("-repo", libraries.repos.map { it.canonicalPath })
|
||||
|
||||
if (platformConfiguration.files.isNotEmpty()) {
|
||||
platformConfiguration.files.filter { it.name.endsWith(".klib") }.forEach {
|
||||
// The library's directory is added in libraries.repos.
|
||||
addArg("-library", it.nameWithoutExtension)
|
||||
}
|
||||
}
|
||||
addFileArgs("-library", libraries.files)
|
||||
addArgs("-library", libraries.namedKlibs)
|
||||
// The library's directory is added in libraries.repos.
|
||||
addArgs("-library", libraries.artifacts.map { it.artifact.nameWithoutExtension })
|
||||
|
||||
addArgIfNotNull("-target", konanTarget.visibleName)
|
||||
addArgIfNotNull("-language-version", languageVersion)
|
||||
addArgIfNotNull("-api-version", apiVersion)
|
||||
addArgIfNotNull("-entry", entryPoint)
|
||||
|
||||
addKey("-g", enableDebug)
|
||||
addKey("-nostdlib", noStdLib)
|
||||
addKey("-nomain", noMain)
|
||||
addKey("-opt", enableOptimizations)
|
||||
addKey("-ea", enableAssertions)
|
||||
addKey("-Xtime", measureTime)
|
||||
addKey("-Xprofile-phases", measureTime)
|
||||
addKey("-no-default-libs", noDefaultLibs)
|
||||
addKey("-no-endorsed-libs", noEndorsedLibs)
|
||||
addKey("-Xmulti-platform", enableMultiplatform)
|
||||
|
||||
if (libraries.friends.isNotEmpty())
|
||||
addArg("-friend-modules", libraries.friends.joinToString(File.pathSeparator))
|
||||
}
|
||||
|
||||
/** Args passed to the compiler if the two-stage compilation is disabled. */
|
||||
fun buildSingleStageArgs() = mutableListOf<String>().apply {
|
||||
addArg("-output", artifact.canonicalPath)
|
||||
addArg("-produce", produce.name.toLowerCase())
|
||||
addArgIfNotNull("-entry", entryPoint)
|
||||
|
||||
addAll(buildCommonArgs())
|
||||
|
||||
addFileArgs("-native-library", nativeLibraries)
|
||||
|
||||
linkerOpts.forEach {
|
||||
addArg("-linker-option", it)
|
||||
}
|
||||
|
||||
if (produce != CompilerOutputKind.LIBRARY) {
|
||||
add("-Xpartial-linkage=enable")
|
||||
add("-Xpartial-linkage-loglevel=error")
|
||||
}
|
||||
|
||||
addAll(extraOpts)
|
||||
|
||||
allSourceFiles.mapTo(this) { it.absolutePath }
|
||||
commonSrcFiles
|
||||
.flatMap { it.files }
|
||||
.mapTo(this) { "-Xcommon-sources=${it.absolutePath}" }
|
||||
}
|
||||
|
||||
// region DSL.
|
||||
|
||||
// DSL. Input/output files.
|
||||
|
||||
override fun srcDir(dir: Any) {
|
||||
srcFiles_.add(directoryToKt(dir))
|
||||
}
|
||||
override fun srcFiles(vararg files: Any) {
|
||||
srcFiles_.add(project.files(files))
|
||||
}
|
||||
override fun srcFiles(files: Collection<Any>) = srcFiles(*files.toTypedArray())
|
||||
|
||||
// DSL. Native libraries.
|
||||
|
||||
override fun nativeLibrary(lib: Any) = nativeLibraries(lib)
|
||||
override fun nativeLibraries(vararg libs: Any) {
|
||||
nativeLibraries.add(project.files(*libs))
|
||||
}
|
||||
override fun nativeLibraries(libs: FileCollection) {
|
||||
nativeLibraries.add(libs)
|
||||
}
|
||||
|
||||
// DSL. Multiplatform projects.
|
||||
|
||||
override fun enableMultiplatform(flag: Boolean) {
|
||||
enableMultiplatform = flag
|
||||
}
|
||||
|
||||
@Deprecated("Use commonSourceSets instead", ReplaceWith("commonSourceSets(sourceSetName)"))
|
||||
override fun commonSourceSet(sourceSetName: String) {
|
||||
commonSourceSets = listOf(sourceSetName)
|
||||
enableMultiplatform(true)
|
||||
}
|
||||
|
||||
override fun commonSourceSets(vararg sourceSetNames: String) {
|
||||
commonSourceSets = sourceSetNames.toList()
|
||||
enableMultiplatform(true)
|
||||
}
|
||||
|
||||
override fun commonSrcDir(dir: Any) {
|
||||
commonSrcFiles_.add(directoryToKt(dir))
|
||||
}
|
||||
|
||||
override fun commonSrcFiles(vararg files: Any) {
|
||||
commonSrcFiles_.add(project.files(files))
|
||||
}
|
||||
|
||||
override fun commonSrcFiles(files: Collection<Any>) = commonSrcFiles(*files.toTypedArray())
|
||||
|
||||
|
||||
// DSL. Other parameters.
|
||||
|
||||
override fun linkerOpts(values: List<String>) = linkerOpts(*values.toTypedArray())
|
||||
override fun linkerOpts(vararg values: String) {
|
||||
linkerOpts.addAll(values)
|
||||
}
|
||||
|
||||
override fun enableDebug(flag: Boolean) {
|
||||
enableDebug = flag
|
||||
}
|
||||
|
||||
override fun noStdLib(flag: Boolean) {
|
||||
noStdLib = flag
|
||||
}
|
||||
|
||||
override fun noMain(flag: Boolean) {
|
||||
noMain = flag
|
||||
}
|
||||
|
||||
override fun noPack(flag: Boolean) {
|
||||
noPack = flag
|
||||
}
|
||||
|
||||
override fun enableOptimizations(flag: Boolean) {
|
||||
enableOptimizations = flag
|
||||
}
|
||||
|
||||
override fun enableAssertions(flag: Boolean) {
|
||||
enableAssertions = flag
|
||||
}
|
||||
|
||||
override fun entryPoint(entryPoint: String) {
|
||||
this.entryPoint = entryPoint
|
||||
}
|
||||
|
||||
override fun measureTime(flag: Boolean) {
|
||||
measureTime = flag
|
||||
}
|
||||
// endregion
|
||||
|
||||
override fun run() {
|
||||
destinationDir.mkdirs()
|
||||
if (dumpParameters) {
|
||||
dumpProperties(this)
|
||||
}
|
||||
if (enableTwoStageCompilation) {
|
||||
logger.info("Start two-stage compilation")
|
||||
val intermediateDir = project.konanBuildRoot
|
||||
.resolve("intermediate")
|
||||
.targetSubdir(konanTarget)
|
||||
.apply { mkdirs() }
|
||||
val klibPrefix = CompilerOutputKind.LIBRARY.prefix(konanTarget)
|
||||
val klibSuffix = CompilerOutputKind.LIBRARY.suffix(konanTarget)
|
||||
val intermediateKlib = intermediateDir.resolve("$klibPrefix$artifactName$klibSuffix").absolutePath
|
||||
logger.info("Start first stage")
|
||||
toolRunner.run(buildFirstStageArgs(intermediateKlib))
|
||||
logger.info("Start second stage")
|
||||
toolRunner.run(buildSecondStageArgs(intermediateKlib))
|
||||
} else {
|
||||
toolRunner.run(buildSingleStageArgs())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
abstract class KonanCompileNativeBinary: KonanCompileTask() {
|
||||
@Input
|
||||
override var enableTwoStageCompilation: Boolean = false
|
||||
}
|
||||
|
||||
open class KonanCompileProgramTask: KonanCompileNativeBinary() {
|
||||
override val produce: CompilerOutputKind get() = CompilerOutputKind.PROGRAM
|
||||
|
||||
@Internal
|
||||
var runTask: TaskProvider<Exec>? = null
|
||||
|
||||
inner class RunArgumentProvider: CommandLineArgumentProvider {
|
||||
override fun asArguments() = project.findProperty("runArgs")?.let {
|
||||
it.toString().split(' ')
|
||||
} ?: emptyList()
|
||||
}
|
||||
}
|
||||
|
||||
open class KonanCompileDynamicTask: KonanCompileNativeBinary() {
|
||||
override val produce: CompilerOutputKind get() = CompilerOutputKind.DYNAMIC
|
||||
|
||||
val headerFile: File
|
||||
@OutputFile get() = destinationDir.resolve("$artifactPrefix${artifactName}_api.h")
|
||||
}
|
||||
|
||||
open class KonanCompileFrameworkTask: KonanCompileNativeBinary() {
|
||||
override val produce: CompilerOutputKind get() = CompilerOutputKind.FRAMEWORK
|
||||
|
||||
override val artifact
|
||||
@OutputDirectory get() = super.artifact
|
||||
}
|
||||
|
||||
open class KonanCompileLibraryTask: KonanCompileTask() {
|
||||
override val artifact: File
|
||||
@Internal get() = destinationDir.resolve(artifactFullName)
|
||||
|
||||
val artifactFile: File?
|
||||
@Optional @OutputFile get() = if (!noPack) artifact else null
|
||||
|
||||
val artifactDirectory: File?
|
||||
@Optional @OutputDirectory get() = if (noPack) artifact else null
|
||||
|
||||
override val artifactSuffix: String
|
||||
@Internal get() = if (!noPack) produce.suffix(konanTarget) else ""
|
||||
|
||||
override fun buildCommonArgs() = super.buildCommonArgs().apply {
|
||||
addKey("-nopack", noPack)
|
||||
}
|
||||
|
||||
override val produce: CompilerOutputKind get() = CompilerOutputKind.LIBRARY
|
||||
override val enableTwoStageCompilation: Boolean = false
|
||||
}
|
||||
|
||||
open class KonanCompileBitcodeTask: KonanCompileNativeBinary() {
|
||||
override val produce: CompilerOutputKind get() = CompilerOutputKind.BITCODE
|
||||
}
|
||||
-199
@@ -1,199 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 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.tasks
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Action
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.tasks.*
|
||||
import org.gradle.workers.WorkAction
|
||||
import org.gradle.workers.WorkParameters
|
||||
import org.gradle.workers.WorkerExecutor
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.*
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.KonanInteropSpec.IncludeDirectoriesSpec
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import java.io.File
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
import javax.inject.Inject
|
||||
|
||||
/**
|
||||
* A task executing cinterop tool with the given args and compiling the stubs produced by this tool.
|
||||
*/
|
||||
|
||||
open class KonanInteropTask @Inject constructor(@Internal val workerExecutor: WorkerExecutor) : KonanBuildingTask(), KonanInteropSpec {
|
||||
|
||||
private val interopRunner = KonanCliInteropRunner(project, project.konanExtension.jvmArgs)
|
||||
|
||||
@get:Internal
|
||||
override val toolRunner: KonanToolRunner = interopRunner
|
||||
|
||||
override fun init(config: KonanBuildingConfig<*>, destinationDir: File, artifactName: String, target: KonanTarget) {
|
||||
super.init(config, destinationDir, artifactName, target)
|
||||
this.defFile = project.konanDefaultDefFile(artifactName)
|
||||
}
|
||||
|
||||
// Output directories -----------------------------------------------------
|
||||
|
||||
override val artifactSuffix: String
|
||||
@Internal get() = ".klib"
|
||||
|
||||
override val artifactPrefix: String
|
||||
@Internal get() = ""
|
||||
|
||||
// Interop stub generator parameters -------------------------------------
|
||||
|
||||
@Internal var enableParallel: Boolean = false
|
||||
|
||||
@InputFile lateinit var defFile: File
|
||||
|
||||
@Optional @Input var packageName: String? = null
|
||||
|
||||
@Input val compilerOpts = mutableListOf<String>()
|
||||
@Input val linkerOpts = mutableListOf<String>()
|
||||
|
||||
@Nested val includeDirs = IncludeDirectoriesSpecImpl()
|
||||
|
||||
@InputFiles val headers = mutableSetOf<FileCollection>()
|
||||
@InputFiles val linkFiles = mutableSetOf<FileCollection>()
|
||||
|
||||
fun buildArgs() = mutableListOf<String>().apply {
|
||||
addArg("-o", artifact.canonicalPath)
|
||||
|
||||
addArgIfNotNull("-target", konanTarget.visibleName)
|
||||
addArgIfNotNull("-def", defFile.canonicalPath)
|
||||
addArgIfNotNull("-pkg", packageName)
|
||||
|
||||
addFileArgs("-header", headers)
|
||||
|
||||
compilerOpts.forEach {
|
||||
addArg("-compiler-option", it)
|
||||
}
|
||||
|
||||
val linkerOpts = mutableListOf<String>().apply { addAll(linkerOpts) }
|
||||
linkFiles.forEach {
|
||||
linkerOpts.addAll(it.files.map { it.canonicalPath })
|
||||
}
|
||||
linkerOpts.forEach {
|
||||
addArg("-linker-option", it)
|
||||
}
|
||||
|
||||
addArgs("-compiler-option", includeDirs.allHeadersDirs.map { "-I${it.absolutePath}" })
|
||||
addArgs("-headerFilterAdditionalSearchPrefix", includeDirs.headerFilterDirs.map { it.absolutePath })
|
||||
|
||||
addArgs("-repo", libraries.repos.map { it.canonicalPath })
|
||||
|
||||
addFileArgs("-library", libraries.files)
|
||||
addArgs("-library", libraries.namedKlibs)
|
||||
addArgs("-library", libraries.artifacts.map { it.artifact.canonicalPath })
|
||||
|
||||
addKey("-no-default-libs", noDefaultLibs)
|
||||
addKey("-no-endorsed-libs", noEndorsedLibs)
|
||||
|
||||
addAll(extraOpts)
|
||||
}
|
||||
|
||||
// region DSL.
|
||||
|
||||
inner class IncludeDirectoriesSpecImpl: IncludeDirectoriesSpec {
|
||||
@Input val allHeadersDirs = mutableSetOf<File>()
|
||||
@Input val headerFilterDirs = mutableSetOf<File>()
|
||||
|
||||
override fun allHeaders(vararg includeDirs: Any) = allHeaders(includeDirs.toList())
|
||||
override fun allHeaders(includeDirs: Collection<Any>) {
|
||||
allHeadersDirs.addAll(includeDirs.map { project.file(it) })
|
||||
}
|
||||
|
||||
override fun headerFilterOnly(vararg includeDirs: Any) = headerFilterOnly(includeDirs.toList())
|
||||
override fun headerFilterOnly(includeDirs: Collection<Any>) {
|
||||
headerFilterDirs.addAll(includeDirs.map { project.file(it) })
|
||||
}
|
||||
}
|
||||
|
||||
override fun defFile(file: Any) {
|
||||
defFile = project.file(file)
|
||||
}
|
||||
|
||||
override fun packageName(value: String) {
|
||||
packageName = value
|
||||
}
|
||||
|
||||
override fun compilerOpts(vararg values: String) {
|
||||
compilerOpts.addAll(values)
|
||||
}
|
||||
|
||||
override fun header(file: Any) = headers(file)
|
||||
override fun headers(vararg files: Any) {
|
||||
headers.add(project.files(files))
|
||||
}
|
||||
override fun headers(files: FileCollection) {
|
||||
headers.add(files)
|
||||
}
|
||||
|
||||
override fun includeDirs(vararg values: Any) = includeDirs.allHeaders(values.toList())
|
||||
|
||||
override fun includeDirs(closure: Closure<Unit>) = includeDirs { project.configure(this, closure) }
|
||||
override fun includeDirs(action: Action<IncludeDirectoriesSpec>) = includeDirs { action.execute(this) }
|
||||
override fun includeDirs(configure: IncludeDirectoriesSpec.() -> Unit) = includeDirs.configure()
|
||||
|
||||
override fun linkerOpts(vararg values: String) = linkerOpts(values.toList())
|
||||
override fun linkerOpts(values: List<String>) {
|
||||
linkerOpts.addAll(values)
|
||||
}
|
||||
|
||||
override fun link(vararg files: Any) {
|
||||
linkFiles.add(project.files(files))
|
||||
}
|
||||
override fun link(files: FileCollection) {
|
||||
linkFiles.add(files)
|
||||
}
|
||||
|
||||
// endregion
|
||||
|
||||
internal interface RunToolParameters: WorkParameters {
|
||||
var taskName: String
|
||||
var args: List<String>
|
||||
}
|
||||
|
||||
internal abstract class RunTool @Inject constructor() : WorkAction<RunToolParameters> {
|
||||
override fun execute() {
|
||||
val toolRunner = interchangeBox.remove(parameters.taskName) ?: error(":(")
|
||||
toolRunner.run(parameters.args)
|
||||
}
|
||||
}
|
||||
|
||||
override fun run() {
|
||||
interopRunner.init(target)
|
||||
|
||||
destinationDir.mkdirs()
|
||||
if (dumpParameters) {
|
||||
dumpProperties(this)
|
||||
}
|
||||
val args = buildArgs()
|
||||
if (enableParallel) {
|
||||
val workQueue = workerExecutor.noIsolation()
|
||||
interchangeBox[this.path] = toolRunner
|
||||
workQueue.submit(RunTool::class.java) {
|
||||
taskName = path
|
||||
this.args = args
|
||||
}
|
||||
} else {
|
||||
toolRunner.run(args)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal val interchangeBox = ConcurrentHashMap<String, KonanToolRunner>()
|
||||
-48
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin
|
||||
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.tasks.*
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.gradle.plugin.konan.KonanKlibRunner
|
||||
import java.io.File
|
||||
|
||||
open class KonanKlibInstallTask : DefaultTask() {
|
||||
@get:InputFile
|
||||
var klib: Provider<File> = project.provider { project.buildDir }
|
||||
|
||||
@get:Internal
|
||||
var repo: File = project.rootDir
|
||||
|
||||
@get:Input
|
||||
val repoPath
|
||||
get() = repo.absolutePath
|
||||
|
||||
val installDir: Provider<File>
|
||||
@OutputDirectory
|
||||
get() = project.provider {
|
||||
val klibName = klib.get().nameWithoutExtension
|
||||
project.file("${repo.absolutePath}/$klibName")
|
||||
}
|
||||
|
||||
@get:Input
|
||||
var target: String = HostManager.hostName
|
||||
|
||||
@TaskAction
|
||||
fun exec() {
|
||||
val args = listOf(
|
||||
"install", klib.get().absolutePath,
|
||||
"-target", target,
|
||||
"-repository", repo.absolutePath
|
||||
)
|
||||
KonanKlibRunner(project, konanHome = project.kotlinNativeDist.absolutePath).run(args)
|
||||
}
|
||||
}
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
#
|
||||
# Copyright 2010-2017 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.
|
||||
#
|
||||
|
||||
shadow.org.jetbrains.kotlinx.serialization.gradle.SerializationKotlinGradleSubplugin
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import spock.lang.Specification
|
||||
|
||||
class BaseKonanSpecification extends Specification {
|
||||
|
||||
@Rule
|
||||
TemporaryFolder tmpFolder = new TemporaryFolder()
|
||||
File getProjectDirectory() { return tmpFolder.root }
|
||||
|
||||
}
|
||||
-42
@@ -1,42 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
|
||||
class DefaultSpecification extends BaseKonanSpecification {
|
||||
|
||||
def 'Plugin should build a project without additional settings'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.buildFile.write("""
|
||||
plugins { id 'konan' }
|
||||
konanArtifacts {
|
||||
interop('stdio')
|
||||
library('main')
|
||||
}
|
||||
""".stripIndent())
|
||||
it.generateDefFile("stdio.def", "")
|
||||
it.generateSrcFile("main.kt")
|
||||
}
|
||||
def result = project.createRunner().withArguments('build').build()
|
||||
|
||||
|
||||
then:
|
||||
!result.tasks.collect { it.outcome }.contains(TaskOutcome.FAILED)
|
||||
}
|
||||
}
|
||||
-336
@@ -1,336 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.Family
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import spock.lang.Ignore
|
||||
import spock.lang.Unroll
|
||||
|
||||
import static org.jetbrains.kotlin.gradle.plugin.test.KonanProject.escapeBackSlashes
|
||||
|
||||
// TODO: Rewrite tests using Kotlin.
|
||||
|
||||
class EnvVariableSpecification extends BaseKonanSpecification {
|
||||
|
||||
class WrapperResult {
|
||||
|
||||
private int exitValue;
|
||||
private String stdout;
|
||||
private String stderr;
|
||||
|
||||
WrapperResult(Process process) {
|
||||
exitValue = process.exitValue()
|
||||
stdout = process.getInputStream().readLines().join("\n")
|
||||
stderr = process.getErrorStream().readLines().join("\n")
|
||||
}
|
||||
|
||||
int getExitValue() { return exitValue }
|
||||
String getStdout() { return stdout }
|
||||
String getStderr() { return stderr }
|
||||
|
||||
WrapperResult printStdout() { println(stdout); return this }
|
||||
WrapperResult printStderr() { println(stderr); return this }
|
||||
}
|
||||
|
||||
private KonanProject createProjectWithWrapper() {
|
||||
def project = KonanProject.createEmpty(projectDirectory)
|
||||
def runner = project.createRunner()
|
||||
|
||||
// Gradle TestKit doesn't support setting environment variables for runners.
|
||||
// So we use the following hack: we create a gradle wrapper, start it as a separate
|
||||
// process with custom environment variables and check its exit code and output.
|
||||
runner.withArguments("wrapper").build()
|
||||
|
||||
def classpath = runner.pluginClasspath.collect { "'${escapeBackSlashes(it.absolutePath)}'" }.join(", ")
|
||||
project.buildFile.write("""\
|
||||
buildscript {
|
||||
dependencies {
|
||||
classpath files($classpath)
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
return project
|
||||
}
|
||||
|
||||
private WrapperResult runWrapper(KonanProject project,
|
||||
List<String> tasks,
|
||||
Map<String, String> environment = [:],
|
||||
Map<String, String> properties = ["konan.useEnvironmentVariables": 'true']) {
|
||||
def wrapper = (HostManager.host.family == Family.MINGW) ? "gradlew.bat" : "gradlew"
|
||||
def command = ["$project.projectDir.absolutePath/$wrapper".toString()]
|
||||
command.addAll(tasks)
|
||||
command.addAll(properties.collect { "-P${it.key}=${it.value}".toString() })
|
||||
def projectBuilder = new ProcessBuilder()
|
||||
.directory(project.projectDir)
|
||||
.command(command)
|
||||
projectBuilder.environment().putAll(environment)
|
||||
def process = projectBuilder.start()
|
||||
process.waitFor()
|
||||
return new WrapperResult(process)
|
||||
}
|
||||
|
||||
private WrapperResult runWrapper(KonanProject project,
|
||||
String task,
|
||||
Map<String, String> environment = [:],
|
||||
Map<String, String> properties = ["konan.useEnvironmentVariables": 'true']) {
|
||||
return runWrapper(project, [task], environment, properties)
|
||||
}
|
||||
|
||||
private String artifactFileName(String baseName, ArtifactType type, KonanTarget target = HostManager.host) {
|
||||
String suffix = ""
|
||||
String prefix = ""
|
||||
switch (type) {
|
||||
case ArtifactType.PROGRAM:
|
||||
suffix = target.family.exeSuffix
|
||||
break
|
||||
case ArtifactType.INTEROP:
|
||||
case ArtifactType.LIBRARY:
|
||||
suffix = "klib"
|
||||
break
|
||||
case ArtifactType.BITCODE:
|
||||
suffix = "bc"
|
||||
break;
|
||||
case ArtifactType.DYNAMIC:
|
||||
prefix = target.family.dynamicPrefix
|
||||
suffix = target.family.dynamicSuffix
|
||||
break
|
||||
case ArtifactType.STATIC:
|
||||
prefix = target.family.staticPrefix
|
||||
suffix = target.family.staticSuffix
|
||||
break
|
||||
case ArtifactType.FRAMEWORK:
|
||||
suffix = "framework"
|
||||
}
|
||||
return "$prefix${baseName}.$suffix"
|
||||
}
|
||||
|
||||
@Ignore("The plugin doesn't use env vars until https://github.com/gradle/gradle/issues/3468 is fixed.")
|
||||
@Unroll("Plugin should support #action via an env variable")
|
||||
def 'Plugin should support enabling/disabling debug/opt via an env variable'() {
|
||||
when:
|
||||
def project = createProjectWithWrapper()
|
||||
project.buildFile.append("""\
|
||||
apply plugin: 'konan'
|
||||
konanArtifacts {
|
||||
library('main')
|
||||
}
|
||||
|
||||
task assertEnableDebug {
|
||||
doLast {
|
||||
konanArtifacts.main.forEach {
|
||||
if (!($assertion)) throw new AssertionError("$message for \${it.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
def result = runWrapper(project,"assertEnableDebug", [(variable): value])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
|
||||
then:
|
||||
result == 0
|
||||
|
||||
where:
|
||||
action |variable |value |assertion |message
|
||||
"enabling debug" |"DEBUGGING_SYMBOLS" |"YES" |"it.enableDebug" |"Debug should be enabled"
|
||||
"disabling debug" |"DEBUGGING_SYMBOLS" |"NO" |"!it.enableDebug" |"Debug should be disabled"
|
||||
"enabling opt" |"KONAN_ENABLE_OPTIMIZATIONS" |"YES" |"it.enableOptimizations" |"Opts should be enabled"
|
||||
"disabling opt" |"KONAN_ENABLE_OPTIMIZATIONS" |"NO" |"!it.enableOptimizations" |"Opts should be disabled"
|
||||
}
|
||||
|
||||
@Ignore("The plugin doesn't use env vars until https://github.com/gradle/gradle/issues/3468 is fixed.")
|
||||
def 'Plugin should support setting destination directory via an env variable'() {
|
||||
when:
|
||||
def project = createProjectWithWrapper()
|
||||
def newDestinationDir = project.createSubDir("newDestination")
|
||||
def newDestinationPath = newDestinationDir.absolutePath
|
||||
project.buildFile.append("""\
|
||||
apply plugin: 'konan'
|
||||
konanArtifacts {
|
||||
program('program')
|
||||
library('library')
|
||||
dynamic('dynamic')
|
||||
framework('framework')
|
||||
}
|
||||
|
||||
task assertDestinationDir {
|
||||
doLast {
|
||||
konanArtifacts.forEach { artifact ->
|
||||
artifact.forEach {
|
||||
if (it.destinationDir.absolutePath != '${escapeBackSlashes(newDestinationPath)}'){
|
||||
throw new AssertionError("Unexpected destination dir for \$it.name\\n" +
|
||||
"expected: ${escapeBackSlashes(newDestinationPath)}\\n" +
|
||||
"actual: \$it.destinationDir")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
project.generateSrcFile("main.kt")
|
||||
def assertResult = runWrapper(project, "assertDestinationDir", ["CONFIGURATION_BUILD_DIR": newDestinationPath])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
def buildResult = runWrapper(project, "build", ["CONFIGURATION_BUILD_DIR": newDestinationPath])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
def files = newDestinationDir.list()
|
||||
|
||||
then:
|
||||
assertResult == 0
|
||||
buildResult == 0
|
||||
files.contains(artifactFileName("program", ArtifactType.PROGRAM))
|
||||
files.contains(artifactFileName("library", ArtifactType.LIBRARY))
|
||||
files.contains(artifactFileName("dynamic", ArtifactType.DYNAMIC))
|
||||
files.contains(artifactFileName("static", ArtifactType.STATIC))
|
||||
if (HostManager.hostIsMac) {
|
||||
files.contains(artifactFileName("framework", ArtifactType.FRAMEWORK))
|
||||
}
|
||||
}
|
||||
|
||||
@Ignore("The plugin doesn't use env vars until https://github.com/gradle/gradle/issues/3468 is fixed.")
|
||||
def 'Plugin should rerun tasks if CONFIGURATION_BUILD_DIR has been changed'() {
|
||||
when:
|
||||
def project = createProjectWithWrapper()
|
||||
def destination1 = project.createSubDir("destination1", "subdir")
|
||||
def destination2 = project.createSubDir("destination2", "subdir")
|
||||
project.buildFile.append("""\
|
||||
apply plugin: 'konan'
|
||||
konanArtifacts {
|
||||
library('main')
|
||||
}
|
||||
""".stripIndent())
|
||||
project.generateSrcFile("main.kt")
|
||||
|
||||
def buildResult1 = runWrapper(project, "build", ["CONFIGURATION_BUILD_DIR": destination1.absolutePath])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
def buildResult2 = runWrapper(project, "build", ["CONFIGURATION_BUILD_DIR": destination2.absolutePath])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
def files1 = destination1.list()
|
||||
def files2 = destination2.list()
|
||||
|
||||
then:
|
||||
buildResult1 == 0
|
||||
buildResult2 == 0
|
||||
destination1.exists()
|
||||
destination2.exists()
|
||||
files1.contains(artifactFileName("main", ArtifactType.LIBRARY))
|
||||
files2.contains(artifactFileName("main", ArtifactType.LIBRARY))
|
||||
}
|
||||
|
||||
@Ignore("The plugin doesn't use env vars until https://github.com/gradle/gradle/issues/3468 is fixed.")
|
||||
def 'Plugin should ignore environmentVariables if konan.useEnvironmentVariables is false or is not set'() {
|
||||
when:
|
||||
def project = createProjectWithWrapper()
|
||||
def newDestinationDir = project.createSubDir("newDestination")
|
||||
def newDestinationPath = newDestinationDir.absolutePath
|
||||
project.buildFile.append("""\
|
||||
apply plugin: 'konan'
|
||||
konanArtifacts {
|
||||
program('program')
|
||||
library('library')
|
||||
dynamic('dynamic')
|
||||
framework('framework')
|
||||
}
|
||||
|
||||
task assertNoOverrides {
|
||||
doLast {
|
||||
konanArtifacts.forEach { artifact ->
|
||||
artifact.forEach {
|
||||
if (it.destinationDir.absolutePath == '${escapeBackSlashes(newDestinationPath)}'){
|
||||
throw new AssertionError("CONFIGURATION_BUILD_DIR overrides a default output path " +
|
||||
"when it shouldn't.\\n" +
|
||||
"Task: \${it.name}, Path: \${it.destinationDir}")
|
||||
}
|
||||
|
||||
if (it.enableDebug) {
|
||||
throw new AssertionError("DEBUGGING_SYMBOLS overrides a default value " +
|
||||
"when it shouldn't\\n" +
|
||||
"Task: \${it.name}")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
def resultNoProp = runWrapper(project,
|
||||
"assertNoOverrides",
|
||||
["DEBUGGING_SYMBOLS": "true", "CONFIGURATION_BUILD_DIR": newDestinationPath], [:])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
def resultFalseValue = runWrapper(project,
|
||||
"assertNoOverrides",
|
||||
["DEBUGGING_SYMBOLS": "true", "CONFIGURATION_BUILD_DIR": newDestinationPath],
|
||||
["konan.useEnvironmentVariables": "false"])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
|
||||
then:
|
||||
resultNoProp == 0
|
||||
resultFalseValue == 0
|
||||
}
|
||||
|
||||
@Ignore("The plugin doesn't use env vars until https://github.com/gradle/gradle/issues/3468 is fixed.")
|
||||
def 'Up-to-date checks should work with different directories for different targets'() {
|
||||
when:
|
||||
def project = createProjectWithWrapper()
|
||||
def fooDir = project.createSubDir("foo")
|
||||
def barDir = project.createSubDir("bar")
|
||||
project.buildFile.append("""\
|
||||
apply plugin: 'konan'
|
||||
|
||||
konanArtifacts {
|
||||
library('foo')
|
||||
library('bar')
|
||||
}
|
||||
|
||||
task assertUpToDate {
|
||||
dependsOn 'compileKonanFoo'
|
||||
doLast {
|
||||
if (!konanArtifacts.foo.getByTarget('host').state.upToDate) {
|
||||
throw new AssertionError("Compilation task is not up-to-date")
|
||||
}
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
project.generateSrcFile("main.kt")
|
||||
|
||||
def buildResult1 = runWrapper(project, "compileKonanFoo",
|
||||
["CONFIGURATION_BUILD_DIR": fooDir.absolutePath])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
def buildResult2 = runWrapper(project, "compileKonanBar",
|
||||
["CONFIGURATION_BUILD_DIR": barDir.absolutePath])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
def buildResult3 = runWrapper(project,
|
||||
"assertUpToDate",
|
||||
["CONFIGURATION_BUILD_DIR": fooDir.absolutePath])
|
||||
.printStderr()
|
||||
.getExitValue()
|
||||
|
||||
then:
|
||||
buildResult1 == 0
|
||||
buildResult2 == 0
|
||||
buildResult3 == 0
|
||||
}
|
||||
|
||||
}
|
||||
-312
@@ -1,312 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import spock.lang.Unroll
|
||||
|
||||
class IncrementalSpecification extends BaseKonanSpecification {
|
||||
|
||||
Tuple buildTwice(KonanProject project, String task = 'build', Closure change) {
|
||||
def runner = project.createRunner().withArguments(task)
|
||||
def firstResult = runner.build()
|
||||
change(project)
|
||||
def secondResult = runner.build()
|
||||
return new Tuple(project, firstResult, secondResult)
|
||||
}
|
||||
|
||||
Tuple buildTwice(ArtifactType mainArtifactType = ArtifactType.LIBRARY, String task = 'build', Closure change) {
|
||||
return buildTwice(KonanProject.createWithInterop(projectDirectory, mainArtifactType), change)
|
||||
}
|
||||
|
||||
Boolean noRecompilationHappened(KonanProject project, BuildResult firstResult, BuildResult secondResult) {
|
||||
return project.with {
|
||||
firstResult.tasks.collect { it.path }.containsAll(buildingTasks) &&
|
||||
firstResult.taskPaths(TaskOutcome.SUCCESS).containsAll(buildingTasks) &&
|
||||
secondResult.taskPaths(TaskOutcome.UP_TO_DATE).containsAll(buildingTasks) &&
|
||||
firstResult.task(downloadTask).outcome == TaskOutcome.SUCCESS &&
|
||||
secondResult.task(downloadTask).outcome == TaskOutcome.SUCCESS
|
||||
}
|
||||
}
|
||||
|
||||
Boolean onlyRecompilationHappened(KonanProject project, BuildResult firstResult, BuildResult secondResult) {
|
||||
return project.with {
|
||||
firstResult.taskPaths(TaskOutcome.SUCCESS).containsAll(buildingTasks) &&
|
||||
secondResult.taskPaths(TaskOutcome.SUCCESS).containsAll(compilationTasks) &&
|
||||
secondResult.taskPaths(TaskOutcome.UP_TO_DATE).containsAll(interopTasks)
|
||||
}
|
||||
}
|
||||
|
||||
Boolean recompilationAndInteropProcessingHappened(KonanProject project, BuildResult firstResult, BuildResult secondResult) {
|
||||
return project.with {
|
||||
firstResult.taskPaths(TaskOutcome.SUCCESS).containsAll(buildingTasks) &&
|
||||
secondResult.taskPaths(TaskOutcome.SUCCESS).containsAll(buildingTasks)
|
||||
}
|
||||
}
|
||||
|
||||
//region tests =====================================================================================================
|
||||
def 'Compilation is up-to-date if there is no changes'() {
|
||||
when:
|
||||
def results = buildTwice {}
|
||||
|
||||
then:
|
||||
noRecompilationHappened(*results)
|
||||
}
|
||||
|
||||
def 'Source change should cause only recompilation'() {
|
||||
when:
|
||||
def results = buildTwice { KonanProject project ->
|
||||
project.srcFiles[0].append("\n // Some change in the source file")
|
||||
}
|
||||
|
||||
then:
|
||||
onlyRecompilationHappened(*results)
|
||||
|
||||
}
|
||||
|
||||
def 'Def-file change should cause recompilation and interop reprocessing'() {
|
||||
when:
|
||||
def results = buildTwice { KonanProject project ->
|
||||
project.defFiles[0].append("\n # Some change in the def-file")
|
||||
}
|
||||
|
||||
then:
|
||||
recompilationAndInteropProcessingHappened(*results)
|
||||
}
|
||||
|
||||
@Unroll("#parameter change for a compilation task should cause only recompilation")
|
||||
def 'Parameter changes should cause only recompilaton'() {
|
||||
when:
|
||||
def results = buildTwice { KonanProject project ->
|
||||
project.addSetting("main", parameter, value)
|
||||
}
|
||||
|
||||
then:
|
||||
onlyRecompilationHappened(*results)
|
||||
|
||||
|
||||
where:
|
||||
parameter | value
|
||||
"baseDir" | "'build/new/outputDir'"
|
||||
"enableOptimizations" | "true"
|
||||
"linkerOpts" | "'--help'"
|
||||
"enableAssertions" | "true"
|
||||
"enableDebug" | "true"
|
||||
"artifactName" | "'foo'"
|
||||
"extraOpts" | "'-Xtime'"
|
||||
"noDefaultLibs" | "true"
|
||||
"noEndorsedLibs" | "true"
|
||||
}
|
||||
|
||||
def 'Plugin should support a custom entry point and recompile an artifact if it changes'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.addCompilerArtifact("main", """
|
||||
|fun main(args: Array<String>) { println("default main") }
|
||||
|
|
||||
""".stripMargin())
|
||||
}
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.srcFiles[0].write("""
|
||||
|package foo
|
||||
|
|
||||
|fun bar(args: Array<String>) { println("changed main") }
|
||||
|
|
||||
""".stripMargin())
|
||||
it.addSetting("main", "entryPoint", "'foo.bar'")
|
||||
}
|
||||
|
||||
then:
|
||||
onlyRecompilationHappened(*results)
|
||||
}
|
||||
|
||||
def 'srcFiles change for a compilation task should cause only recompilation'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
|
||||
it.generateSrcFile(["src", "foo", "kotlin"], 'bar.kt', """
|
||||
fun foo(args: Array<String>) { println("Hello!") }
|
||||
""".stripIndent())
|
||||
}
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.addSetting("main", "srcFiles", "project.fileTree('src/foo/kotlin')")
|
||||
}
|
||||
|
||||
then:
|
||||
onlyRecompilationHappened(*results)
|
||||
}
|
||||
|
||||
def 'Library change for a compilation task should cause only recompilation'() {
|
||||
when:
|
||||
def project = KonanProject.create(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
|
||||
it.generateSrcFile(["src", "lib", "kotlin"], "lib.kt", "fun bar() { println(\"Hello!\") }")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('lib') {
|
||||
srcFiles fileTree('src/lib/kotlin')
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.addLibraryToArtifact("main", 'lib')
|
||||
}
|
||||
|
||||
then:
|
||||
onlyRecompilationHappened(*results)
|
||||
}
|
||||
|
||||
def 'Native library change for a compilation task should cause only recompilaton'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
|
||||
it.generateSrcFile(["src", "lib", "kotlin"], "lib.kt", "fun bar() { println(\"Hello!\") }")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
bitcode('lib') {
|
||||
srcFiles fileTree('src/lib/kotlin')
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.addSetting("main", "nativeLibrary", "compileKonanLib${KonanProject.HOST.capitalize()}.artifact")
|
||||
}
|
||||
|
||||
then:
|
||||
onlyRecompilationHappened(*results)
|
||||
}
|
||||
|
||||
// TODO: Test library for incremental compilation.
|
||||
|
||||
@Unroll("#parameter change for an interop task should cause recompilation and interop reprocessing")
|
||||
def 'Parameter change for an interop task should cause recompilation and interop reprocessing'() {
|
||||
when:
|
||||
def results = buildTwice { KonanProject project ->
|
||||
project.addSetting("stdio", parameter, value)
|
||||
}
|
||||
|
||||
then:
|
||||
recompilationAndInteropProcessingHappened(*results)
|
||||
|
||||
where:
|
||||
parameter | value
|
||||
"packageName" | "'org.sample'"
|
||||
"compilerOpts" | "'-g'"
|
||||
"linkerOpts" | "'--help'"
|
||||
"includeDirs" | "'src'"
|
||||
"includeDirs.allHeaders" | "'src'"
|
||||
"extraOpts" | "'-verbose'"
|
||||
"noDefaultLibs" | "true"
|
||||
"noEndorsedLibs" | "true"
|
||||
}
|
||||
|
||||
def 'includeDirs.headerFilterOnly change should cause recompilation and interop reprocessing'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory) { KonanProject it ->
|
||||
it.defFiles.first().write("headers = stdio.h\nheaderFilter = stdio.h")
|
||||
}
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.addSetting(KonanProject.DEFAULT_INTEROP_NAME, "includeDirs.headerFilterOnly", "'.'")
|
||||
}
|
||||
|
||||
then:
|
||||
recompilationAndInteropProcessingHappened(*results)
|
||||
}
|
||||
|
||||
def 'defFile change for an interop task should cause recompilation and interop reprocessing'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY)
|
||||
def defFile = project.generateDefFile("foo.def", "#some content")
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.addSetting("stdio", "defFile", defFile)
|
||||
}
|
||||
|
||||
then:
|
||||
recompilationAndInteropProcessingHappened(*results)
|
||||
}
|
||||
|
||||
def 'header change for an interop task should cause recompilation and interop reprocessing'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY)
|
||||
def header = project.generateSrcFile('header.h', "#define CONST 1")
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.addSetting("stdio", "headers", header)
|
||||
}
|
||||
|
||||
then:
|
||||
recompilationAndInteropProcessingHappened(*results)
|
||||
}
|
||||
|
||||
def 'link change for an interop task should cause recompilation and interop reprocessing'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
|
||||
it.generateSrcFile(["src", "lib", "kotlin"], 'lib.kt', 'fun foo() { println(42) }')
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
bitcode('lib') {
|
||||
srcFiles fileTree('src/lib/kotlin')
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def results = buildTwice(project) { KonanProject it ->
|
||||
it.addSetting("stdio", "dependsOn", "konanArtifacts.lib.${KonanProject.HOST}")
|
||||
it.addSetting("stdio", "link", "files(konanArtifacts.lib.${KonanProject.HOST}.artifactPath)")
|
||||
}
|
||||
|
||||
then:
|
||||
recompilationAndInteropProcessingHappened(*results)
|
||||
}
|
||||
|
||||
def 'Common source change should cause recompilation'() {
|
||||
when:
|
||||
File commonSource
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = MultiplatformSpecification.createCommonProject(it)
|
||||
commonSource = MultiplatformSpecification.createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun foo(): Int")
|
||||
println(it.settingsFile.text)
|
||||
|
||||
it.generateSrcFile("actual.kt", "actual fun foo() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
it.buildingTasks.addAll([":compileKonanFoo", ":compileKonanFoo${KonanProject.HOST}}"])
|
||||
}
|
||||
|
||||
def results = buildTwice(project, ':build') { KonanProject ->
|
||||
commonSource.append("\nfun bar() = 43")
|
||||
}
|
||||
|
||||
then:
|
||||
onlyRecompilationHappened(*results)
|
||||
}
|
||||
|
||||
// TODO: Add incremental tests for the 'libraries' block.
|
||||
|
||||
//endregion
|
||||
}
|
||||
-377
@@ -1,377 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.gradle.testkit.runner.GradleRunner
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Path
|
||||
import java.nio.file.Paths
|
||||
|
||||
enum ArtifactType {
|
||||
PROGRAM("program"),
|
||||
LIBRARY("library"),
|
||||
BITCODE("bitcode"),
|
||||
INTEROP("interop"),
|
||||
DYNAMIC("dynamic"),
|
||||
STATIC("static"),
|
||||
FRAMEWORK("framework")
|
||||
|
||||
String type
|
||||
ArtifactType(String type) { this.type = type }
|
||||
String toString() { return type }
|
||||
}
|
||||
|
||||
class KonanProject {
|
||||
|
||||
static String DEFAULT_ARTIFACT_NAME = 'main'
|
||||
static String DEFAULT_INTEROP_NAME = "stdio"
|
||||
|
||||
static String HOST = HostManager.hostName
|
||||
|
||||
File projectDir
|
||||
Path projectPath
|
||||
File konanBuildDir
|
||||
|
||||
String konanHome
|
||||
String gradleVersion
|
||||
|
||||
File buildFile
|
||||
File propertiesFile
|
||||
File settingsFile
|
||||
|
||||
Set<File> srcFiles = []
|
||||
Set<File> defFiles = []
|
||||
|
||||
List<String> interopTasks = []
|
||||
List<String> compilationTasks = []
|
||||
String downloadTask = ":checkKonanCompiler"
|
||||
|
||||
List<String> targets
|
||||
|
||||
List<String> getBuildingTasks() { return compilationTasks + interopTasks }
|
||||
List<String> getKonanTasks() { return getBuildingTasks() + downloadTask }
|
||||
|
||||
static String DEFAULT_SRC_CONTENT = """
|
||||
fun main(args: Array<String>) {
|
||||
println(42)
|
||||
}
|
||||
"""
|
||||
|
||||
static String DEFAULT_DEF_CONTENT = """
|
||||
headers = stdio.h
|
||||
""".stripIndent()
|
||||
|
||||
protected KonanProject(File projectDir){
|
||||
this(projectDir, [HOST])
|
||||
}
|
||||
|
||||
protected KonanProject(File projectDir, List<String> targets) {
|
||||
this.projectDir = projectDir
|
||||
this.targets = targets
|
||||
projectPath = projectDir.toPath()
|
||||
konanBuildDir = projectPath.resolve('build/konan').toFile()
|
||||
def konanHomeDir = new File(getKonanHome())
|
||||
if (!konanHomeDir.exists() || !konanHomeDir.directory) {
|
||||
throw new IllegalStateException("konan.home doesn't exist or is not a directory: $konanHomeDir.canonicalPath")
|
||||
}
|
||||
// Escape windows path separator
|
||||
this.konanHome = escapeBackSlashes(konanHomeDir.canonicalPath)
|
||||
this.gradleVersion = System.getProperty("gradleVersion") ?: GradleVersion.current().version
|
||||
}
|
||||
|
||||
GradleRunner createRunner(boolean withDebug = true) {
|
||||
return GradleRunner.create()
|
||||
.withProjectDir(projectDir)
|
||||
.withPluginClasspath()
|
||||
.withDebug(withDebug)
|
||||
.withGradleVersion(gradleVersion)
|
||||
}
|
||||
|
||||
/** Creates a subdirectory specified by the given path. */
|
||||
File createSubDir(String ... path) {
|
||||
return createSubDir(Paths.get(*path))
|
||||
}
|
||||
|
||||
/** Creates a subdirectory specified by the given path. */
|
||||
File createSubDir(Path path) {
|
||||
return Files.createDirectories(projectPath.resolve(path)).toFile()
|
||||
}
|
||||
|
||||
/** Creates a file with the given content in project subdirectory specified by parentDirectory. */
|
||||
File createFile(Path parentDirectory = projectPath, String fileName, String content) {
|
||||
def parent = projectPath.resolve(parentDirectory)
|
||||
Files.createDirectories(parent)
|
||||
def result = parent.resolve(fileName).toFile()
|
||||
result.createNewFile()
|
||||
result.write(content)
|
||||
return result
|
||||
}
|
||||
|
||||
/** Creates a file with the given content in project subdirectory specified by parentPath. */
|
||||
File createFile(List<String> parentPath, String fileName, String content) {
|
||||
return createFile(Paths.get(*parentPath), fileName, content)
|
||||
}
|
||||
|
||||
/** Creates a folder for project source files (src/main/kotlin). */
|
||||
void generateFolders() {
|
||||
createSubDir("src", "main", "kotlin")
|
||||
createSubDir("src", "main", "c_interop")
|
||||
}
|
||||
|
||||
/** Generates a build.gradle file in the root project directory with the given content. */
|
||||
File generateBuildFile(String content) {
|
||||
buildFile = createFile(projectPath, "build.gradle", content)
|
||||
return buildFile
|
||||
}
|
||||
|
||||
/** Generates a settings.gradle file in the root project directory with the given content. */
|
||||
File generateSettingsFile(String content) {
|
||||
settingsFile = createFile(projectPath, "settings.gradle", content)
|
||||
return settingsFile
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a build.gradle file in root project directory with the default content (see below)
|
||||
* and fills the compilationTasks array.
|
||||
*
|
||||
* plugins { id 'konan' }
|
||||
*
|
||||
* konanArtifacts {
|
||||
* program('$DEFAULT_ARTIFACT_NAME')
|
||||
* }
|
||||
*/
|
||||
File generateBuildFile() {
|
||||
def result = generateBuildFile("""
|
||||
|plugins { id 'konan' }
|
||||
|
|
||||
|konan.targets = [${targets.collect { "'$it'" }.join(", ")}]
|
||||
|""".stripMargin()
|
||||
)
|
||||
compilationTasks = [":compileKonan", ":build"]
|
||||
return result
|
||||
}
|
||||
|
||||
/** Generates a source file with the given name and content in the given directory and adds it into srcFiles */
|
||||
File generateSrcFile(Path parentDirectory, String fileName, String content) {
|
||||
def result = createFile(parentDirectory, fileName, content)
|
||||
srcFiles.add(result)
|
||||
return result
|
||||
}
|
||||
|
||||
/** Generates a source file with the given name and content in the given directory and adds it into srcFiles */
|
||||
File generateSrcFile(List<String> parentPath, String fileName, String content) {
|
||||
return generateSrcFile(Paths.get(*parentPath), fileName, content)
|
||||
}
|
||||
|
||||
/** Generates a source file with the given name and content in 'src/main/kotlin' and adds it into srcFiles */
|
||||
File generateSrcFile(String fileName, String content) {
|
||||
return generateSrcFile(["src", "main", "kotlin"], fileName, content)
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a source file with the given name and default content (see below) in src/main/kotlin
|
||||
* and adds it into srcFiles.
|
||||
*
|
||||
* fun main(args: Array<String>) {
|
||||
* println(42)
|
||||
* }
|
||||
*/
|
||||
File generateSrcFile(String fileName) {
|
||||
return generateSrcFile(fileName, DEFAULT_SRC_CONTENT)
|
||||
}
|
||||
|
||||
/** Creates a def-file with the given name and content in src/main/c_interop directory and adds it to defFiles. */
|
||||
File generateDefFile(String fileName, String content) {
|
||||
def result = createFile(["src", "main", "c_interop"], fileName, content)
|
||||
defFiles.add(result)
|
||||
return result
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a def-file with the given name and the default content (see below) in src/main/c_interop directory
|
||||
* and adds it to defFiles.
|
||||
*
|
||||
* headers = stdio.h stdlib.h string.h
|
||||
*/
|
||||
File generateDefFile(String fileName = "${DEFAULT_INTEROP_NAME}.def") {
|
||||
return generateDefFile(fileName, DEFAULT_DEF_CONTENT)
|
||||
}
|
||||
|
||||
/** Generates gradle.properties file with the konan.home and konan.jvmArgs properties set. */
|
||||
File generatePropertiesFile(String konanHome, String konanJvmArgs = System.getProperty("konan.jvmArgs") ?: "") {
|
||||
propertiesFile = createFile(projectPath, "gradle.properties", """\
|
||||
org.jetbrains.kotlin.native.home=$konanHome
|
||||
${!konanJvmArgs.isEmpty() ? "konan.jvmArgs=$konanJvmArgs\n" : ""}
|
||||
""".stripIndent())
|
||||
return propertiesFile
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given setting of the given project extension.
|
||||
* In other words adds the following string in the build file:
|
||||
*
|
||||
* $container.$section.$parameter $value
|
||||
*/
|
||||
protected void addSetting(String container, String section, String parameter, String value) {
|
||||
buildFile.append("$container.$section.$parameter $value\n")
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the given setting of the given project extension using the path of the file as a value.
|
||||
* In other words adds the following string in the build file:
|
||||
*
|
||||
* $container.$section.$parameter ${value.canonicalPath.replace(\, \\)}
|
||||
*/
|
||||
protected void addSetting(String container, String section, String parameter, File value) {
|
||||
addSetting(container, section, parameter, "'${escapeBackSlashes(value.canonicalPath)}'")
|
||||
}
|
||||
|
||||
/** Sets the given setting of the given konanArtifact */
|
||||
void addSetting(String artifactName = DEFAULT_ARTIFACT_NAME, String parameter, String value) {
|
||||
addSetting("konanArtifacts", artifactName, parameter, value)
|
||||
}
|
||||
|
||||
/** Sets the given setting of the given konanArtifact using the path of the file as a value. */
|
||||
void addSetting(String artifactName = DEFAULT_ARTIFACT_NAME, String parameter, File value) {
|
||||
addSetting("konanArtifacts", artifactName, parameter, value)
|
||||
}
|
||||
|
||||
void addLibraryToArtifact(String artifactName = DEFAULT_ARTIFACT_NAME, String library = DEFAULT_INTEROP_NAME) {
|
||||
addLibraryToArtifactCustom(artifactName, "artifact '$library'")
|
||||
}
|
||||
|
||||
void addLibraryToArtifactCustom(String artifactName = DEFAULT_ARTIFACT_NAME, String closureContent) {
|
||||
buildFile.append("konanArtifacts.${artifactName}.libraries { $closureContent }\n")
|
||||
}
|
||||
|
||||
/** Returns the path of compileKonan... task for the default artifact. */
|
||||
static String defaultCompilationTask(String target = HOST) {
|
||||
return compilationTask(DEFAULT_ARTIFACT_NAME, target)
|
||||
}
|
||||
|
||||
static String defaultInteropTask(String target = HOST) {
|
||||
return compilationTask(DEFAULT_INTEROP_NAME, target)
|
||||
}
|
||||
|
||||
/** Returns the path of compileKonan... task for the artifact specified. */
|
||||
static String compilationTask(String artifactName, String target = HOST) {
|
||||
return ":compileKonan${artifactName.capitalize()}${target.capitalize()}"
|
||||
}
|
||||
|
||||
static String defaultCompilationConfig() {
|
||||
return artifactConfig(DEFAULT_ARTIFACT_NAME)
|
||||
}
|
||||
|
||||
static String defaultInteropConfig() {
|
||||
return artifactConfig(DEFAULT_INTEROP_NAME)
|
||||
}
|
||||
|
||||
static String artifactConfig(String artifactName) {
|
||||
return "konanArtifacts.$artifactName"
|
||||
}
|
||||
|
||||
static String outputAccessCode(String artifact, String target = HOST) {
|
||||
return "${artifactConfig(artifact)}.${target}.artifact"
|
||||
}
|
||||
|
||||
void addCompilerArtifact(String name, String content = "", ArtifactType type = ArtifactType.PROGRAM) {
|
||||
def newTasks = targets.collect { compilationTask(name, it) } + ":compileKonan${name.capitalize()}".toString()
|
||||
buildFile.append("konanArtifacts { $type('$name') }\n")
|
||||
if (type == ArtifactType.INTEROP) {
|
||||
defFiles += generateDefFile("${name}.def", content)
|
||||
interopTasks += newTasks
|
||||
} else {
|
||||
def src = generateSrcFile(projectPath.resolve("src/$name/kotlin"), "source.kt", content)
|
||||
addSetting(name, "srcFiles", src)
|
||||
srcFiles += src
|
||||
compilationTasks += newTasks
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/** Creates a project with default build and source files. */
|
||||
static KonanProject create(File projectDir,
|
||||
ArtifactType artifactType = ArtifactType.PROGRAM,
|
||||
List<String> targets = [HOST]) {
|
||||
return createEmpty(projectDir, targets) { KonanProject p ->
|
||||
p.addCompilerArtifact(DEFAULT_ARTIFACT_NAME, DEFAULT_SRC_CONTENT, artifactType)
|
||||
}
|
||||
}
|
||||
|
||||
/** Creates a project with default build and source files. */
|
||||
static KonanProject create(File projectDir,
|
||||
ArtifactType artifactType = ArtifactType.PROGRAM,
|
||||
List<String> targets = [HOST],
|
||||
Closure config) {
|
||||
def result = create(projectDir, artifactType, targets)
|
||||
config(result)
|
||||
return result
|
||||
}
|
||||
|
||||
static KonanProject createWithInterop(File projectDir,
|
||||
ArtifactType mainArtifactType = ArtifactType.PROGRAM,
|
||||
List<String> targets = [HOST]) {
|
||||
return create(projectDir, mainArtifactType, targets) { KonanProject p ->
|
||||
p.addCompilerArtifact(DEFAULT_INTEROP_NAME, DEFAULT_DEF_CONTENT, ArtifactType.INTEROP)
|
||||
p.addLibraryToArtifact()
|
||||
}
|
||||
}
|
||||
|
||||
static KonanProject createWithInterop(File projectDir,
|
||||
ArtifactType mainArtifactType = ArtifactType.PROGRAM,
|
||||
List<String> targets = [HOST],
|
||||
Closure config) {
|
||||
def result = createWithInterop(projectDir, mainArtifactType, targets)
|
||||
config(result)
|
||||
return result
|
||||
}
|
||||
|
||||
/** Creates a project with the default build file and without any source files. */
|
||||
static KonanProject createEmpty(File projectDir, List<String> targets = [HOST]) {
|
||||
def result = new KonanProject(projectDir, targets)
|
||||
result.with {
|
||||
generateFolders()
|
||||
generateBuildFile()
|
||||
generatePropertiesFile(konanHome)
|
||||
generateSettingsFile("")
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
/** Creates a project with the default build file and without any source files. */
|
||||
static KonanProject createEmpty(File projectDir, List<String> targets = [HOST], Closure config) {
|
||||
def result = createEmpty(projectDir, targets)
|
||||
config(result)
|
||||
return result
|
||||
}
|
||||
|
||||
static String escapeBackSlashes(String value) {
|
||||
return value.replace('\\', '\\\\')
|
||||
}
|
||||
|
||||
static String getKonanHome() {
|
||||
def konanHome = System.getProperty("konan.home") ?: System.getProperty("org.jetbrains.kotlin.native.home")
|
||||
if (konanHome == null) {
|
||||
throw new IllegalStateException("konan.home isn't specified")
|
||||
}
|
||||
return konanHome
|
||||
}
|
||||
|
||||
}
|
||||
-330
@@ -1,330 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
class LibrarySpecification extends BaseKonanSpecification {
|
||||
|
||||
def libraries = [
|
||||
[manualDependsOn: true , code: { l1, l2 ->
|
||||
"file ${KonanProject.outputAccessCode(l1)}\nfile ${KonanProject.outputAccessCode(l2)}"
|
||||
}],
|
||||
[manualDependsOn: true , code: { l1, l2 ->
|
||||
"files ${KonanProject.outputAccessCode(l1)}, ${KonanProject.outputAccessCode(l2)}"
|
||||
}],
|
||||
[manualDependsOn: true , code: { l1, l2 ->
|
||||
"files project.files(${KonanProject.outputAccessCode(l1)}, ${KonanProject.outputAccessCode(l2)})"
|
||||
}],
|
||||
[manualDependsOn: true , code: { l1, l2 -> "klib '$l1'\nklib '$l2'" }],
|
||||
[manualDependsOn: true , code: { l1, l2 -> "klibs '$l1', '$l2'" }],
|
||||
[manualDependsOn: false, code: { l1, l2 -> "artifact '$l1'\nartifact '$l2'" }],
|
||||
[manualDependsOn: false, code: { l1, l2 -> "artifact konanArtifacts.$l1\nartifact konanArtifacts.$l2" }],
|
||||
]
|
||||
|
||||
String createMainWithCalls(List<Tuple2<String, String>> functions, Closure<String> callBuilder) {
|
||||
def result = new StringBuilder("""
|
||||
|fun main(args: Array<String>) {\n
|
||||
""".stripMargin())
|
||||
|
||||
functions.forEach {
|
||||
result.append(callBuilder(it.first))
|
||||
result.append(callBuilder(it.second))
|
||||
}
|
||||
|
||||
result.append("}")
|
||||
return result.toString()
|
||||
}
|
||||
|
||||
void createLibraryWithFunction(KonanProject project, String name) {
|
||||
project.addCompilerArtifact(name, """
|
||||
|package $name
|
||||
|
|
||||
|fun $name() {
|
||||
| println("$name")
|
||||
|}
|
||||
""".stripMargin(), ArtifactType.LIBRARY)
|
||||
project.addSetting(name, "noDefaultLibs", "true")
|
||||
project.addSetting(name, "noEndorsedLibs", "true")
|
||||
}
|
||||
|
||||
void createInteropLibrary(KonanProject project, String name) {
|
||||
project.addCompilerArtifact(name, "headers = math.h", ArtifactType.INTEROP)
|
||||
project.addSetting(name, "noDefaultLibs", "true")
|
||||
project.addSetting(name, "noEndorsedLibs", "true")
|
||||
}
|
||||
|
||||
KonanProject createProjectWithLibraries(Closure createLibraryFunction, Closure callBuilder) {
|
||||
def result = KonanProject.createEmpty(projectDirectory)
|
||||
|
||||
def libraryNames = new ArrayList<Tuple2<String, String>>()
|
||||
for (int i = 0; i < libraries.size(); i++) {
|
||||
libraryNames.add(new Tuple2("foo$i", "bar$i"))
|
||||
}
|
||||
|
||||
libraryNames.forEach {
|
||||
createLibraryFunction(result, it.first)
|
||||
createLibraryFunction(result, it.second)
|
||||
}
|
||||
|
||||
result.addCompilerArtifact("main", createMainWithCalls(libraryNames, callBuilder))
|
||||
result.addSetting("main", "noDefaultLibs", "true")
|
||||
result.addSetting("main", "noEndorsedLibs", "true")
|
||||
|
||||
for (int i = 0; i < libraries.size(); i++) {
|
||||
def foo = libraryNames[i].first
|
||||
def bar = libraryNames[i].second
|
||||
result.addLibraryToArtifactCustom("main", libraries[i].code(foo, bar) )
|
||||
|
||||
if (libraries[i].manualDependsOn) {
|
||||
result.addSetting("main", "dependsOn", "konanArtifacts.$foo")
|
||||
result.addSetting("main", "dependsOn", "konanArtifacts.$bar")
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
|
||||
KonanProject createProjectWithSimpleLibraries() {
|
||||
return createProjectWithLibraries(
|
||||
{ p, n -> createLibraryWithFunction(p, n) },
|
||||
{ "$it.$it()\n" } )
|
||||
}
|
||||
|
||||
|
||||
KonanProject createProjectWithInteropLibraries() {
|
||||
return createProjectWithLibraries(
|
||||
{ p, n -> createInteropLibrary(p, n) },
|
||||
{ "println(${it}.cos(0.0))\n" }
|
||||
)
|
||||
}
|
||||
|
||||
def 'Plugin should support libraries from the same project'() {
|
||||
expect:
|
||||
createProjectWithSimpleLibraries()
|
||||
.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"))
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support interop libraries from the same project'() {
|
||||
expect:
|
||||
createProjectWithInteropLibraries()
|
||||
.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"))
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support allLibrariesFrom method for the current project'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.addCompilerArtifact("foo", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
it.addSetting("foo", "noDefaultLibs", "true")
|
||||
it.addSetting("foo", "noEndorsedLibs", "true")
|
||||
|
||||
it.addCompilerArtifact("bar", "fun bar() { println(43) }", ArtifactType.LIBRARY)
|
||||
it.addSetting("bar", "noDefaultLibs", "true")
|
||||
it.addSetting("bar", "noEndorsedLibs", "true")
|
||||
|
||||
it.addCompilerArtifact("main" ,"fun main(args: Array<String>) { foo(); bar() }")
|
||||
it.addSetting("main", "noDefaultLibs", "true" )
|
||||
it.addSetting("main", "noEndorsedLibs", "true" )
|
||||
it.addLibraryToArtifactCustom("main", "allLibrariesFrom project")
|
||||
}
|
||||
project.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"))
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support allLibrariesFrom method for another project'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory)
|
||||
def subproject = KonanProject.createEmpty(project.createSubDir("subproject")) { KonanProject it ->
|
||||
it.buildFile.write("apply plugin: 'konan'\n")
|
||||
}
|
||||
project.settingsFile.append("include ':subproject'")
|
||||
|
||||
project.addCompilerArtifact("wrongFoo","fun foo() { println(24) }", ArtifactType.LIBRARY)
|
||||
project.addSetting("wrongFoo", "noDefaultLibs", "true")
|
||||
project.addSetting("wrongFoo", "noEndorsedLibs", "true")
|
||||
|
||||
subproject.addCompilerArtifact("foo", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
subproject.addSetting("foo", "noDefaultLibs", "true")
|
||||
subproject.addSetting("foo", "noEndorsedLibs", "true")
|
||||
|
||||
subproject.addCompilerArtifact("bar", "fun bar() { println(43) }", ArtifactType.LIBRARY)
|
||||
subproject.addSetting("bar", "noDefaultLibs", "true")
|
||||
subproject.addSetting("bar", "noEndorsedLibs", "true")
|
||||
|
||||
project.addCompilerArtifact("main" ,"fun main(args: Array<String>) { foo(); bar() }")
|
||||
project.addSetting("main", "noDefaultLibs", "true" )
|
||||
project.addSetting("main", "noEndorsedLibs", "true" )
|
||||
project.addLibraryToArtifactCustom("main", "allLibrariesFrom project('subproject')")
|
||||
|
||||
project.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"))
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support allInteropLibrariesFrom method for the current project'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory)
|
||||
def subproject = KonanProject.createEmpty(project.createSubDir("subproject")) { KonanProject it ->
|
||||
it.buildFile.write("apply plugin: 'konan'\n")
|
||||
}
|
||||
project.settingsFile.append("include ':subproject'")
|
||||
|
||||
|
||||
project.addCompilerArtifact("wrongFoo1", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
project.addSetting("wrongFoo1", "noDefaultLibs", "true")
|
||||
project.addSetting("wrongFoo1", "noEndorsedLibs", "true")
|
||||
|
||||
subproject.addCompilerArtifact("wrongFoo2", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
subproject.addSetting("wrongFoo2", "noDefaultLibs", "true")
|
||||
subproject.addSetting("wrongFoo2", "noEndorsedLibs", "true")
|
||||
|
||||
subproject.addCompilerArtifact("math1", "headers = math.h", ArtifactType.INTEROP)
|
||||
subproject.addSetting("math1", "noDefaultLibs", "true")
|
||||
subproject.addSetting("math1", "noEndorsedLibs", "true")
|
||||
|
||||
subproject.addCompilerArtifact("math2", "headers = math.h", ArtifactType.INTEROP)
|
||||
subproject.addSetting("math2", "noDefaultLibs", "true")
|
||||
subproject.addSetting("math2", "noEndorsedLibs", "true")
|
||||
|
||||
project.addCompilerArtifact("main" ,"""
|
||||
|fun foo() {}
|
||||
|
|
||||
|fun main(args: Array<String>) { foo(); math1.cos(0.0); math2.cos(0.0) }
|
||||
""".stripMargin())
|
||||
project.addSetting("main", "noDefaultLibs", "true" )
|
||||
project.addSetting("main", "noEndorsedLibs", "true" )
|
||||
project.addLibraryToArtifactCustom("main", "allInteropLibrariesFrom project('subproject')")
|
||||
|
||||
|
||||
project.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"))
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support allInteropLibrariesFrom method for another projecct'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.addCompilerArtifact("wrongFoo", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
it.addSetting("wrongFoo", "noDefaultLibs", "true")
|
||||
it.addSetting("wrongFoo", "noEndorsedLibs", "true")
|
||||
|
||||
it.addCompilerArtifact("math1", "headers = math.h", ArtifactType.INTEROP)
|
||||
it.addSetting("math1", "noDefaultLibs", "true")
|
||||
it.addSetting("math1", "noEndorsedLibs", "true")
|
||||
|
||||
it.addCompilerArtifact("math2", "headers = math.h", ArtifactType.INTEROP)
|
||||
it.addSetting("math2", "noDefaultLibs", "true")
|
||||
it.addSetting("math2", "noEndorsedLibs", "true")
|
||||
|
||||
it.addCompilerArtifact("main" ,"""
|
||||
|fun foo() {}
|
||||
|
|
||||
|fun main(args: Array<String>) { foo(); math1.cos(0.0); math2.cos(0.0) }
|
||||
""".stripMargin())
|
||||
it.addSetting("main", "noDefaultLibs", "true" )
|
||||
it.addSetting("main", "noEndorsedLibs", "true" )
|
||||
it.addLibraryToArtifactCustom("main", "allInteropLibrariesFrom project")
|
||||
}
|
||||
project.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"))
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support custom repositories for libraries'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.addCompilerArtifact("foo", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
it.addSetting("foo", "noDefaultLibs", "true")
|
||||
it.addSetting("foo", "noEndorsedLibs", "true")
|
||||
it.addSetting("foo", "baseDir", "file('out')")
|
||||
|
||||
|
||||
it.addCompilerArtifact("main" ,"fun main(args: Array<String>) { foo() }")
|
||||
it.addSetting("main", "noDefaultLibs", "true" )
|
||||
it.addSetting("main", "noEndorsedLibs", "true" )
|
||||
it.addSetting("main", "dependsOn", "konanArtifacts.foo.$KonanProject.HOST")
|
||||
it.addLibraryToArtifactCustom("main", "klib 'foo'")
|
||||
it.addLibraryToArtifactCustom("main", "useRepo 'out/$KonanProject.HOST'")
|
||||
}
|
||||
project.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"), "-i")
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support library dependencies in the same project'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.addCompilerArtifact("foo", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
it.addSetting("foo", "noDefaultLibs", "true")
|
||||
it.addSetting("foo", "noEndorsedLibs", "true")
|
||||
|
||||
it.addCompilerArtifact("bar", "fun bar() { println(43) }", ArtifactType.LIBRARY)
|
||||
it.addSetting("bar", "noDefaultLibs", "true")
|
||||
it.addSetting("bar", "noEndorsedLibs", "true")
|
||||
it.addLibraryToArtifact("bar", "foo")
|
||||
|
||||
it.addCompilerArtifact("main" ,"fun main(args: Array<String>) { foo(); bar() }")
|
||||
it.addSetting("main", "noDefaultLibs", "true" )
|
||||
it.addSetting("main", "noEndorsedLibs", "true" )
|
||||
it.addLibraryToArtifact("main", "bar")
|
||||
}
|
||||
|
||||
project.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"), "-i")
|
||||
.build()
|
||||
}
|
||||
|
||||
def 'Plugin should support library dependencies from other projects'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory)
|
||||
def subproject1 = KonanProject.createEmpty(project.createSubDir("subproject1")) { KonanProject it ->
|
||||
it.buildFile.write("apply plugin: 'konan'\n")
|
||||
}
|
||||
def subproject2 = KonanProject.createEmpty(project.createSubDir("subproject2")) { KonanProject it ->
|
||||
it.buildFile.write("apply plugin: 'konan'\n")
|
||||
}
|
||||
project.settingsFile.append("include ':subproject1'\ninclude ':subproject2'")
|
||||
|
||||
subproject1.addCompilerArtifact("foo", "fun foo() { println(42) }", ArtifactType.LIBRARY)
|
||||
subproject1.addSetting("foo", "noDefaultLibs", "true")
|
||||
subproject1.addSetting("foo", "noEndorsedLibs", "true")
|
||||
|
||||
subproject2.addCompilerArtifact("bar", "fun bar() { println(43) }", ArtifactType.LIBRARY)
|
||||
subproject2.addSetting("bar", "noDefaultLibs", "true")
|
||||
subproject2.addSetting("bar", "noEndorsedLibs", "true")
|
||||
subproject2.addLibraryToArtifactCustom(
|
||||
"bar", "artifact rootProject.project('subproject1'), 'foo'"
|
||||
)
|
||||
|
||||
project.addCompilerArtifact("main" ,"fun main(args: Array<String>) { foo(); bar() }")
|
||||
project.addSetting("main", "noDefaultLibs", "true" )
|
||||
project.addSetting("main", "noEndorsedLibs", "true" )
|
||||
project.addLibraryToArtifactCustom(
|
||||
"main", "artifact project('subproject2'), 'bar'"
|
||||
)
|
||||
|
||||
project.createRunner()
|
||||
.withArguments(KonanProject.compilationTask("main"))
|
||||
.build()
|
||||
}
|
||||
|
||||
// TODO: Add tests for incorrect cases (e.g. attempt to use an executable as a library)
|
||||
}
|
||||
-390
@@ -1,390 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import spock.lang.Ignore
|
||||
|
||||
import java.nio.file.Files
|
||||
import java.nio.file.Paths
|
||||
|
||||
class MultiplatformSpecification extends BaseKonanSpecification {
|
||||
|
||||
public static final String KOTLIN_VERSION = System.getProperty("kotlin.version")
|
||||
public static final String KOTLIN_REPO = System.getProperty("kotlin.repo")
|
||||
public static final String DEFAULT_COMMON_BUILD_FILE_CONTENT = """\
|
||||
buildscript {
|
||||
repositories {
|
||||
maven {
|
||||
url = '$KOTLIN_REPO'
|
||||
}
|
||||
maven {
|
||||
url = 'https://cache-redirector.jetbrains.com/maven-central'
|
||||
}
|
||||
}
|
||||
dependencies {
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$KOTLIN_VERSION"
|
||||
}
|
||||
}
|
||||
|
||||
apply plugin: 'kotlin-platform-common'
|
||||
|
||||
repositories {
|
||||
maven {
|
||||
url = '$KOTLIN_REPO'
|
||||
}
|
||||
maven {
|
||||
url = 'https://cache-redirector.jetbrains.com/maven-central'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib-common:$KOTLIN_VERSION"
|
||||
}
|
||||
""".stripIndent()
|
||||
|
||||
static File createCommonProject(KonanProject platformProject,
|
||||
String commonProjectName = "common",
|
||||
String commonBuildFileContent = DEFAULT_COMMON_BUILD_FILE_CONTENT) {
|
||||
def commonDirectory = platformProject.createSubDir(commonProjectName)
|
||||
def commonBuildFile = Paths.get(commonDirectory.absolutePath, "build.gradle")
|
||||
commonBuildFile.write(commonBuildFileContent)
|
||||
platformProject.settingsFile.append("include ':$commonProjectName'\n")
|
||||
return commonDirectory
|
||||
}
|
||||
|
||||
static File createCommonSource(File commonDirectory,
|
||||
Iterable<String> subdirectory,
|
||||
String fileName,
|
||||
String content) {
|
||||
def commonSrcDir = commonDirectory.toPath().resolve(Paths.get(*subdirectory))
|
||||
def commonSource = commonSrcDir.resolve(fileName)
|
||||
Files.createDirectories(commonSrcDir)
|
||||
commonSource.write(content)
|
||||
return commonSource.toFile()
|
||||
}
|
||||
|
||||
def 'Plugin should support multiplatform projects'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"""\
|
||||
@file:Suppress("OPT_IN_USAGE_ERROR")
|
||||
@OptionalExpectation
|
||||
expect annotation class Optional()
|
||||
|
||||
@Optional
|
||||
fun opt() = 42
|
||||
|
||||
expect fun foo(): Int
|
||||
""".stripIndent()
|
||||
)
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun foo() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments(":build").build()
|
||||
}
|
||||
|
||||
def 'Multiplatform projects should be disabled by default'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun foo(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "fun foo() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments(":build").build()
|
||||
}
|
||||
|
||||
def 'Plugin should use the \'main\' source set as a default common source set'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
Paths.get(commonDirectory.absolutePath, "build.gradle").append("""
|
||||
sourceSets {
|
||||
common.kotlin.srcDir 'src/common/kotlin'
|
||||
}
|
||||
""".stripIndent())
|
||||
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun foo(): Int")
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "common", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun bar(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun foo() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments(":build").build()
|
||||
}
|
||||
|
||||
def 'Plugin should allow a user to specify custom common source set'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
Paths.get(commonDirectory.absolutePath, "build.gradle").append("""
|
||||
sourceSets {
|
||||
common.kotlin.srcDir 'src/common/kotlin'
|
||||
}
|
||||
""".stripIndent())
|
||||
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "common", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun bar(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun bar() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
commonSourceSets 'common'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments(":build").build()
|
||||
}
|
||||
|
||||
def 'Plugin should allow setting several common source sets'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
Paths.get(commonDirectory.absolutePath, "build.gradle").append("""
|
||||
sourceSets {
|
||||
common.kotlin.srcDir 'src/common/kotlin'
|
||||
}
|
||||
""".stripIndent())
|
||||
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "common", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun bar(): Int")
|
||||
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"main.kt",
|
||||
"expect fun foo() : Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun bar() = 42\nactual fun foo() = 43")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
commonSourceSets 'common', 'main'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments(":build").build()
|
||||
}
|
||||
|
||||
def 'Build should fail if the expectedBy dependency is not a project one'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun foo(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun foo() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy files('common/src/main/kotlin/common.kt')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def result = project.createRunner().withArguments(":build").buildAndFail()
|
||||
|
||||
then:
|
||||
result.output.contains("dependency is not a project: ")
|
||||
}
|
||||
|
||||
def 'Build should support several expectedBy-dependencies'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it, "commonFoo")
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun foo(): Int")
|
||||
|
||||
commonDirectory = createCommonProject(it, "commonBar")
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun bar(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun foo() = 0\nactual fun bar() = 0")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':commonFoo')
|
||||
expectedBy project(':commonBar')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments(":build").build()
|
||||
}
|
||||
|
||||
def 'Build should fail if the common project has no common plugin'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it,"common", "")
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun foo(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun bar() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def result = project.createRunner().withArguments(":build").buildAndFail()
|
||||
|
||||
then:
|
||||
result.output.contains("has an 'expectedBy' dependency to non-common project")
|
||||
}
|
||||
|
||||
@Ignore("TODO in the Big Kotlin plugin")
|
||||
def 'Build should fail if custom common source set doesn\'t exist'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "main", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun foo(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun bar() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
enableMultiplatform true
|
||||
commonSourceSets 'common'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def result = project.createRunner().withArguments(":build").buildAndFail()
|
||||
|
||||
then:
|
||||
result.output.contains("Cannot find a source set with name 'common' in a common project")
|
||||
}
|
||||
|
||||
def 'Setting custom source set should enable the multiplatform support'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
def commonDirectory = createCommonProject(it)
|
||||
Paths.get(commonDirectory.absolutePath, "build.gradle").append("""
|
||||
sourceSets {
|
||||
common.kotlin.srcDir 'src/common/kotlin'
|
||||
}
|
||||
""".stripIndent())
|
||||
|
||||
createCommonSource(commonDirectory,
|
||||
["src", "common", "kotlin"],
|
||||
"common.kt",
|
||||
"expect fun bar(): Int")
|
||||
|
||||
it.generateSrcFile("platform.kt", "actual fun bar() = 42")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
library('foo') {
|
||||
commonSourceSets 'common'
|
||||
}
|
||||
}
|
||||
|
||||
dependencies {
|
||||
expectedBy project(':common')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments(":build").build()
|
||||
}
|
||||
}
|
||||
-130
@@ -1,130 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import org.jetbrains.kotlin.konan.target.Distribution
|
||||
import org.jetbrains.kotlin.konan.target.PlatformManager
|
||||
|
||||
class PathSpecification extends BaseKonanSpecification {
|
||||
|
||||
boolean fileExists(KonanProject project, String path) {
|
||||
project.konanBuildDir.toPath().resolve(path).toFile().exists()
|
||||
}
|
||||
|
||||
def platformManager = new PlatformManager(new Distribution(KonanProject.konanHome, false, null), false)
|
||||
|
||||
def 'Plugin should provide a correct path to the artifacts created'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(
|
||||
projectDirectory,
|
||||
platformManager.enabled.collect { t -> t.visibleName }
|
||||
) { KonanProject it ->
|
||||
it.generateSrcFile("main.kt")
|
||||
it.generateDefFile("interop.def", "")
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
program('program')
|
||||
library('library')
|
||||
bitcode('bitcode')
|
||||
interop('interop')
|
||||
framework('framework')
|
||||
dynamic('dynamic')
|
||||
}
|
||||
|
||||
tasks.register("checkArtifacts", DefaultTask) {
|
||||
dependsOn(':build')
|
||||
doLast {
|
||||
for(artifact in konanArtifacts) {
|
||||
for (target in artifact) {
|
||||
if (!target.artifact.exists()) throw new Exception("Artifact doesn't exist. Type: \${artifact.name}, target: \${target.target}")
|
||||
}
|
||||
}
|
||||
for (target in konanArtifacts.dynamic) {
|
||||
if (!target.headerFile.exists()) throw new Exception("Header file doesn't exist. Target: \${target.target}")
|
||||
}
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
project.createRunner().withArguments("checkArtifacts").build()
|
||||
|
||||
}
|
||||
|
||||
def 'Plugin should create all necessary directories'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory)
|
||||
project.addCompilerArtifact("lib", "fun foo() {}", ArtifactType.LIBRARY)
|
||||
project.addCompilerArtifact("bit", "fun bar() {}", ArtifactType.BITCODE)
|
||||
project.createRunner().withArguments('build').build()
|
||||
|
||||
then:
|
||||
project.konanBuildDir.toPath().resolve("bin/$KonanProject.HOST").toFile().listFiles().findAll {
|
||||
File it -> it.file && it.name.matches("^${KonanProject.DEFAULT_ARTIFACT_NAME}\\.[^.]+")
|
||||
}.size() > 0
|
||||
|
||||
fileExists(project, "libs/$KonanProject.HOST/${KonanProject.DEFAULT_INTEROP_NAME}.klib")
|
||||
fileExists(project, "libs/$KonanProject.HOST/lib.klib")
|
||||
fileExists(project, "bitcode/$KonanProject.HOST/bit.bc")
|
||||
}
|
||||
|
||||
def 'Plugin should stop building if the compiler classpath is empty'() {
|
||||
when:
|
||||
def project = KonanProject.create(projectDirectory)
|
||||
project.propertiesFile.write("konan.home=fakepath")
|
||||
def result = project.createRunner().withArguments('build').buildAndFail()
|
||||
def task = result.task(project.defaultCompilationTask())
|
||||
|
||||
then:
|
||||
task == null || task.outcome == TaskOutcome.FAILED
|
||||
}
|
||||
|
||||
def 'Plugin should stop building if the stub generator classpath is empty'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory)
|
||||
project.propertiesFile.write("konan.home=fakepath")
|
||||
def result = project.createRunner().withArguments('build').buildAndFail()
|
||||
def task = result.task(project.compilationTask(KonanProject.DEFAULT_INTEROP_NAME))
|
||||
|
||||
then:
|
||||
task == null || task.outcome == TaskOutcome.FAILED
|
||||
}
|
||||
|
||||
def 'Plugin should remove custom output directories'() {
|
||||
when:
|
||||
def customOutputDir = projectDirectory.toPath().resolve("foo").toFile()
|
||||
def project = KonanProject.create(projectDirectory, ArtifactType.LIBRARY) { KonanProject it ->
|
||||
it.addSetting("baseDir", customOutputDir)
|
||||
}
|
||||
|
||||
def res1 = project.createRunner().withArguments("build").build()
|
||||
def artifactExistsAfterBuild = customOutputDir.toPath()
|
||||
.resolve("${KonanProject.HOST}/${KonanProject.DEFAULT_ARTIFACT_NAME}.klib").toFile()
|
||||
.exists()
|
||||
|
||||
def res2 = project.createRunner().withArguments("clean").build()
|
||||
def artifactExistsAfterClean = customOutputDir.toPath()
|
||||
.resolve("${KonanProject.HOST}/${KonanProject.DEFAULT_ARTIFACT_NAME}.klib").toFile()
|
||||
.exists()
|
||||
|
||||
then:
|
||||
res1.taskPaths(TaskOutcome.SUCCESS).containsAll(project.buildingTasks)
|
||||
res2.taskPaths(TaskOutcome.SUCCESS).contains(":clean")
|
||||
artifactExistsAfterBuild
|
||||
!artifactExistsAfterClean
|
||||
}
|
||||
}
|
||||
-73
@@ -1,73 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
|
||||
class RegressionSpecification extends BaseKonanSpecification {
|
||||
|
||||
def 'KT-19916'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(getProjectDirectory()) { KonanProject prj ->
|
||||
prj.generateSettingsFile("include ':subproject'")
|
||||
def subprojectDir = prj.projectPath.resolve("subproject").toFile()
|
||||
subprojectDir.mkdirs()
|
||||
subprojectDir.toPath().resolve("build.gradle").write("""
|
||||
dependencies {
|
||||
libs gradleApi()
|
||||
}
|
||||
""".stripIndent())
|
||||
|
||||
prj.buildFile.append("""
|
||||
subprojects {
|
||||
apply plugin: 'konan'
|
||||
apply plugin: Foo
|
||||
}
|
||||
|
||||
class Foo implements Plugin<Project> {
|
||||
void apply(Project project) {
|
||||
project.configurations.maybeCreate("libs")
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
|
||||
def result = project.createRunner().withArguments('tasks').build()
|
||||
|
||||
then:
|
||||
result.task(':tasks').outcome == TaskOutcome.SUCCESS
|
||||
}
|
||||
|
||||
// Ensure gradle plugin fails in case of linker errors.
|
||||
def 'KT-20192'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(getProjectDirectory()) { KonanProject prj ->
|
||||
prj.addCompilerArtifact(KonanProject.DEFAULT_ARTIFACT_NAME,"""
|
||||
external fun foo()
|
||||
|
||||
fun main(args: Array<String>) {
|
||||
foo()
|
||||
}
|
||||
""", ArtifactType.PROGRAM)
|
||||
}
|
||||
def result = project.createRunner().withArguments('build').buildAndFail()
|
||||
|
||||
then:
|
||||
result.taskPaths(TaskOutcome.FAILED).contains(project.defaultCompilationTask())
|
||||
}
|
||||
|
||||
}
|
||||
-167
@@ -1,167 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.gradle.testkit.runner.BuildResult
|
||||
import org.gradle.testkit.runner.TaskOutcome
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import spock.lang.Requires
|
||||
import spock.lang.Unroll
|
||||
|
||||
class TaskSpecification extends BaseKonanSpecification {
|
||||
|
||||
def 'Configs should allow user to add dependencies to them'() {
|
||||
when:
|
||||
def project = KonanProject.createWithInterop(projectDirectory, ArtifactType.LIBRARY)
|
||||
project.buildFile.append("""
|
||||
tasks.register("beforeInterop", DefaultTask) { doLast { println("Before Interop") } }
|
||||
tasks.register("beforeCompilation", DefaultTask) { doLast { println("Before compilation") } }
|
||||
""".stripIndent())
|
||||
project.addSetting(KonanProject.DEFAULT_INTEROP_NAME,"dependsOn", "beforeInterop")
|
||||
project.addSetting("dependsOn", "beforeCompilation")
|
||||
def result = project.createRunner().withArguments('build').build()
|
||||
|
||||
then:
|
||||
def beforeInterop = result.task(":beforeInterop")
|
||||
beforeInterop != null && beforeInterop.outcome == TaskOutcome.SUCCESS
|
||||
def beforeCompilation = result.task(":beforeCompilation")
|
||||
beforeCompilation != null && beforeCompilation.outcome == TaskOutcome.SUCCESS
|
||||
}
|
||||
|
||||
def 'Compiler should print time measurements if measureTime flag is set'() {
|
||||
when:
|
||||
def project = KonanProject.create(projectDirectory, ArtifactType.LIBRARY)
|
||||
project.addSetting("measureTime", "true")
|
||||
def result = project.createRunner().withArguments('build').build()
|
||||
|
||||
then:
|
||||
result.output.findAll(~/Frontend builds AST:\s+\d+\s+msec/).size() == 1
|
||||
result.output.findAll(~/IR Lowering:\s+\d+\s+msec/).size() == 1
|
||||
}
|
||||
|
||||
@Unroll('Plugin should support #option option for cinterop')
|
||||
def 'Plugin should support includeDir option for cinterop'() {
|
||||
expect:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.addCompilerArtifact("interopLib", "headers=foo.h\n$headerFilter", ArtifactType.INTEROP)
|
||||
it.generateSrcFile(it.projectPath, "foo.h", "#include <bar.h>")
|
||||
def fooDir = it.projectPath.resolve("foo")
|
||||
it.generateSrcFile(fooDir, "bar.h", "const int foo = 5;")
|
||||
it.addSetting("interopLib", option, fooDir.toFile())
|
||||
it.addSetting("interopLib", option, it.projectDir)
|
||||
}
|
||||
project.createRunner().withArguments("build").build()
|
||||
|
||||
where:
|
||||
option | headerFilter
|
||||
"includeDirs.headerFilterOnly" | "headerFilter=foo.h bar.h"
|
||||
"includeDirs.allHeaders" | ""
|
||||
"includeDirs" | ""
|
||||
}
|
||||
|
||||
@Requires({ HostManager.host instanceof KonanTarget.MACOS_X64 })
|
||||
def 'Plugin should create framework tasks only for Apple targets'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.buildFile.append("""
|
||||
konan.targets = ['wasm32', 'macbook', 'iphone', 'iphone_sim']
|
||||
|
||||
konanArtifacts {
|
||||
framework('foo')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def result = project.createRunner().withArguments('tasks', '--all').build()
|
||||
|
||||
then:
|
||||
!compilationTaskExists(result,'foo', 'wasm32')
|
||||
compilationTaskExists (result,'foo', 'macbook')
|
||||
compilationTaskExists (result,'foo', 'iphone')
|
||||
compilationTaskExists (result,'foo', 'iphone_sim')
|
||||
}
|
||||
|
||||
def 'Plugin should support different targets for different artifacts'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory, ['host']) { KonanProject it ->
|
||||
it.buildFile.append("""
|
||||
konanArtifacts {
|
||||
program('defaultTarget')
|
||||
program('customTarget', targets: ['wasm32'])
|
||||
program('customTargets', targets: ['host', 'wasm32'])
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def result = project.createRunner().withArguments('tasks', '--all').build()
|
||||
def hostName = HostManager.hostName
|
||||
|
||||
then:
|
||||
compilationTaskExists (result, 'defaultTarget', hostName)
|
||||
!compilationTaskExists(result, 'defaultTarget', 'wasm32')
|
||||
!compilationTaskExists(result, 'customTarget', hostName)
|
||||
compilationTaskExists (result, 'customTarget', 'wasm32')
|
||||
compilationTaskExists (result, 'customTargets', hostName)
|
||||
compilationTaskExists (result, 'customTargets', 'wasm32')
|
||||
}
|
||||
|
||||
def 'Plugin should not create dynamic task for wasm'() {
|
||||
when:
|
||||
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
|
||||
it.buildFile.append("""
|
||||
konan.targets = ['wasm32']
|
||||
|
||||
konanArtifacts {
|
||||
dynamic('foo')
|
||||
}
|
||||
""".stripIndent())
|
||||
}
|
||||
def result = project.createRunner().withArguments('tasks', '--all').build()
|
||||
|
||||
then:
|
||||
!compilationTaskExists(result, 'foo', 'wasm32')
|
||||
}
|
||||
|
||||
|
||||
boolean taskExists(BuildResult result, String taskName) {
|
||||
def taskNameForSearch = taskName.startsWith(':') ? taskName.substring(1) : taskName
|
||||
return result.output =~ "\\s$taskNameForSearch\\s"
|
||||
}
|
||||
|
||||
boolean compilationTaskExists(BuildResult result, String artifactName, String targetName) {
|
||||
return taskExists(result, KonanProject.compilationTask(artifactName, targetName))
|
||||
}
|
||||
|
||||
BuildResult failOnPropertyAccess(KonanProject project, String property) {
|
||||
project.buildFile.append("""
|
||||
tasks.register("testTask", DefaultTask) {
|
||||
doLast {
|
||||
println(${project.defaultInteropConfig()}.$property)
|
||||
}
|
||||
}
|
||||
""".stripIndent())
|
||||
return project.createRunner().withArguments("testTask").buildAndFail()
|
||||
}
|
||||
|
||||
BuildResult failOnTaskAccess(KonanProject project, String task) {
|
||||
project.buildFile.append("""
|
||||
tasks.register("testTask", DefaultTask) {
|
||||
dependsOn $task
|
||||
}
|
||||
""".stripIndent())
|
||||
return project.createRunner().withArguments("testTask").buildAndFail()
|
||||
}
|
||||
}
|
||||
@@ -1,48 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.io.File
|
||||
import java.net.URI
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
open class CompatibilityTests {
|
||||
val tmpFolder = TemporaryFolder()
|
||||
@Rule get
|
||||
|
||||
val projectDirectory: File
|
||||
get() = tmpFolder.root
|
||||
|
||||
@Test
|
||||
fun `Plugin should fail if running with Gradle prior to the required one`() {
|
||||
val project = KonanProject.createEmpty(projectDirectory)
|
||||
val result = project
|
||||
.createRunner()
|
||||
.withGradleDistribution(URI.create(
|
||||
"https://cache-redirector.jetbrains.com/services.gradle.org/distributions/gradle-4.5-bin.zip"
|
||||
))
|
||||
.withArguments("tasks")
|
||||
.buildAndFail()
|
||||
println(result.output)
|
||||
assertTrue("Build doesn't show the warning message") {
|
||||
result.output.contains("Kotlin/Native Gradle plugin is incompatible with this version of Gradle.")
|
||||
}
|
||||
}
|
||||
}
|
||||
-204
@@ -1,204 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.jetbrains.kotlin.gradle.plugin.test.KonanProject.escapeBackSlashes
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import org.junit.runner.RunWith
|
||||
import org.tools4j.spockito.Spockito
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
|
||||
@RunWith(Spockito::class)
|
||||
open class PropertiesAsEnvVariablesTest {
|
||||
|
||||
val tmpFolder = TemporaryFolder()
|
||||
@Rule get
|
||||
|
||||
val projectDirectory: File
|
||||
get() = tmpFolder.root
|
||||
|
||||
private fun artifactFileName(baseName: String, type: ArtifactType, target: KonanTarget = HostManager.host): String {
|
||||
var suffix = ""
|
||||
var prefix = ""
|
||||
when (type) {
|
||||
ArtifactType.PROGRAM -> suffix = target.family.exeSuffix
|
||||
ArtifactType.INTEROP,
|
||||
ArtifactType.LIBRARY -> suffix = "klib"
|
||||
ArtifactType.BITCODE -> suffix = "bc"
|
||||
ArtifactType.FRAMEWORK -> suffix = "framework"
|
||||
ArtifactType.DYNAMIC -> {
|
||||
prefix = target.family.dynamicPrefix
|
||||
suffix = target.family.dynamicSuffix
|
||||
}
|
||||
ArtifactType.STATIC -> {
|
||||
prefix = target.family.staticPrefix
|
||||
suffix = target.family.staticSuffix
|
||||
}
|
||||
|
||||
}
|
||||
return "$prefix${baseName}.$suffix"
|
||||
}
|
||||
|
||||
private fun assertFileExists(directory: File, filename: String) = assert(directory.list().contains(filename)) {
|
||||
"No such file: $filename in directory: ${directory.absolutePath}"
|
||||
}
|
||||
|
||||
@Test
|
||||
@Spockito.Unroll(
|
||||
"|property |value |assertion |message |",
|
||||
"|konan.debugging.symbols |YES |it.enableDebug |Debug should be enabled |",
|
||||
"|konan.debugging.symbols |true |it.enableDebug |Debug should be enabled |",
|
||||
"|konan.debugging.symbols |NO |!it.enableDebug |Debug should be disabled |",
|
||||
"|konan.debugging.symbols |false |!it.enableDebug |Debug should be disabled |",
|
||||
"|konan.optimizations.enable |YES |it.enableOptimizations |Opts should be enabled |",
|
||||
"|konan.optimizations.enable |true |it.enableOptimizations |Opts should be enabled |",
|
||||
"|konan.optimizations.enable |NO |!it.enableOptimizations |Opts should be disabled |",
|
||||
"|konan.optimizations.enable |false |!it.enableOptimizations |Opts should be disabled |"
|
||||
)
|
||||
@Spockito.Name("[{row}]: {variable}={value}")
|
||||
fun `Plugin should support enabling and disabling debug and opt options via a project property`(
|
||||
property: String,
|
||||
value: String,
|
||||
assertion: String,
|
||||
message: String
|
||||
) {
|
||||
val project = KonanProject.createEmpty(projectDirectory)
|
||||
project.buildFile.appendText("""
|
||||
|
||||
apply plugin: 'konan'
|
||||
konanArtifacts {
|
||||
library('main')
|
||||
}
|
||||
|
||||
task assertEnableDebug {
|
||||
doLast {
|
||||
konanArtifacts.main.forEach {
|
||||
if (!($assertion)) throw new AssertionError("$message for ${'$'}it.name")
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
project.createRunner()
|
||||
.withArguments("assertEnableDebug", "-P${property}=${value}")
|
||||
.build()
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Plugin should support setting destination directory via a project property`() {
|
||||
val project = KonanProject.createEmpty(projectDirectory)
|
||||
val newDestinationDir = project.createSubDir("newDestination")
|
||||
val newDestinationPath = newDestinationDir.absolutePath
|
||||
project.buildFile.appendText("""
|
||||
apply plugin: 'konan'
|
||||
konanArtifacts {
|
||||
program('program')
|
||||
library('library')
|
||||
dynamic('dynamic')
|
||||
framework('framework')
|
||||
}
|
||||
|
||||
task assertDestinationDir {
|
||||
doLast {
|
||||
konanArtifacts.forEach { artifact ->
|
||||
artifact.forEach {
|
||||
if (it.destinationDir.absolutePath != '${escapeBackSlashes(newDestinationPath)}'){
|
||||
throw new AssertionError("Unexpected destination dir for ${'$'}it.name\\n" +
|
||||
"expected: ${escapeBackSlashes(newDestinationPath)}\\n" +
|
||||
"actual: ${'$'}it.destinationDir")
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
project.generateSrcFile("main.kt")
|
||||
project.createRunner()
|
||||
.withArguments("assertDestinationDir", "build", "-Pkonan.configuration.build.dir=$newDestinationPath")
|
||||
.build()
|
||||
|
||||
assertFileExists(newDestinationDir, artifactFileName("program", ArtifactType.PROGRAM))
|
||||
assertFileExists(newDestinationDir, artifactFileName("library", ArtifactType.LIBRARY))
|
||||
assertFileExists(newDestinationDir, artifactFileName("dynamic", ArtifactType.DYNAMIC))
|
||||
if (HostManager.hostIsMac) {
|
||||
assertFileExists(newDestinationDir, artifactFileName("framework", ArtifactType.FRAMEWORK))
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Plugin should rerun tasks if konan_configuration_build_dir has been changed`() {
|
||||
val project = KonanProject.createEmpty(projectDirectory)
|
||||
val destination1 = project.createSubDir("destination1", "subdir")
|
||||
val destination2 = project.createSubDir("destination2", "subdir")
|
||||
|
||||
project.buildFile.appendText("""
|
||||
apply plugin: 'konan'
|
||||
konanArtifacts {
|
||||
library('main')
|
||||
}
|
||||
""".trimIndent())
|
||||
project.generateSrcFile("main.kt")
|
||||
|
||||
project.createRunner()
|
||||
.withArguments("build", "-Pkonan.configuration.build.dir=${destination1.absolutePath}")
|
||||
.build()
|
||||
project.createRunner()
|
||||
.withArguments("build", "-Pkonan.configuration.build.dir=${destination2.absolutePath}")
|
||||
.build()
|
||||
|
||||
assertFileExists(destination1, artifactFileName("main", ArtifactType.LIBRARY))
|
||||
assertFileExists(destination2, artifactFileName("main", ArtifactType.LIBRARY))
|
||||
}
|
||||
|
||||
@Test
|
||||
fun `Up-to-date checks should work with different directories for different targets`() {
|
||||
val project = KonanProject.createEmpty(projectDirectory)
|
||||
val fooDir = project.createSubDir("foo")
|
||||
val barDir = project.createSubDir("bar")
|
||||
project.buildFile.appendText("""
|
||||
apply plugin: 'konan'
|
||||
|
||||
konanArtifacts {
|
||||
library('foo')
|
||||
library('bar')
|
||||
}
|
||||
|
||||
task assertUpToDate {
|
||||
dependsOn 'compileKonanFoo'
|
||||
doLast {
|
||||
if (!konanArtifacts.foo.getByTarget('host').state.upToDate) {
|
||||
throw new AssertionError("Compilation task is not up-to-date")
|
||||
}
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
project.generateSrcFile("main.kt")
|
||||
|
||||
project.createRunner()
|
||||
.withArguments("compileKonanFoo", "-Pkonan.configuration.build.dir=${fooDir.absolutePath}")
|
||||
.build()
|
||||
project.createRunner()
|
||||
.withArguments("compileKonanBar", "-Pkonan.configuration.build.dir=${barDir.absolutePath}")
|
||||
.build()
|
||||
project.createRunner()
|
||||
.withArguments("assertUpToDate", "-Pkonan.configuration.build.dir=${fooDir.absolutePath}")
|
||||
.build()
|
||||
}
|
||||
}
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* 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.test
|
||||
|
||||
import org.junit.Rule
|
||||
import org.junit.rules.TemporaryFolder
|
||||
import java.io.File
|
||||
import kotlin.test.Test
|
||||
import kotlin.test.assertFalse
|
||||
import kotlin.test.assertTrue
|
||||
|
||||
class TaskTests {
|
||||
val tmpFolder = TemporaryFolder()
|
||||
@Rule get
|
||||
|
||||
val projectDirectory: File
|
||||
get() = tmpFolder.root
|
||||
|
||||
@Test
|
||||
fun `Plugin should support separate run tasks for different binaries`() {
|
||||
val project = KonanProject.createEmpty(projectDirectory).apply {
|
||||
buildFile.appendText("""
|
||||
konanArtifacts {
|
||||
program('foo') {
|
||||
srcDir 'src/foo/kotlin'
|
||||
}
|
||||
program('bar') {
|
||||
srcDir 'src/bar/kotlin'
|
||||
}
|
||||
}
|
||||
""".trimIndent())
|
||||
}
|
||||
project.generateSrcFile(
|
||||
listOf("src", "foo", "kotlin"),
|
||||
"main.kt",
|
||||
"fun main(args: Array<String>) = println(\"Run Foo: \${args[0]}, \${args[1]}\")")
|
||||
project.generateSrcFile(
|
||||
listOf("src", "bar", "kotlin"),
|
||||
"main.kt",
|
||||
"fun main(args: Array<String>) = println(\"Run Bar: \${args[0]}, \${args[1]}\")")
|
||||
val resultFoo = project.createRunner()
|
||||
.withArguments("runFoo", "-PrunArgs=arg1 arg2")
|
||||
.build()
|
||||
val resultAll = project.createRunner()
|
||||
.withArguments("run", "-PrunArgs=arg1 arg2")
|
||||
.build()
|
||||
|
||||
assertTrue(resultFoo.output.contains("Run Foo: arg1, arg2"), "No Foo output for 'runFoo'")
|
||||
assertFalse(resultFoo.output.contains("Run Bar: "), "There is Bar output for 'runFoo'")
|
||||
assertTrue(resultAll.output.contains("Run Foo: arg1, arg2"), "No Foo output for 'run'")
|
||||
assertTrue(resultAll.output.contains("Run Bar: arg1, arg2"), "No Bar output for 'run'")
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user