Support -Xexport-library for K/N in the MPP plugin
This commit is contained in:
+5
-17
@@ -14,22 +14,10 @@ import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName
|
||||
import javax.inject.Inject
|
||||
|
||||
/*
|
||||
Naming:
|
||||
|
||||
executable('foo', [debug, release]) -> fooDebugExecutable + fooReleaseExecutable
|
||||
executable -> debugExecutable, releaseExecutable
|
||||
executable([debug]) -> debugExecutable
|
||||
|
||||
// Tests:
|
||||
1. Cannot add a second binary with the same parameters.
|
||||
2. Can access a binary by name
|
||||
3. Access linkTask
|
||||
4. Access runTask
|
||||
5. Final binaries have correct names
|
||||
6. Old APIs work fine:
|
||||
- creating binaries,
|
||||
- getting binaries and link tasks,
|
||||
- setting binary parameters using compilation DSL: linker opts and entry points
|
||||
Use the following naming scheme:
|
||||
executable('foo', [debug, release]) -> fooDebugExecutable + fooReleaseExecutable
|
||||
executable() -> debugExecutable, releaseExecutable
|
||||
executable([debug]) -> debugExecutable
|
||||
*/
|
||||
|
||||
open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
@@ -131,7 +119,7 @@ open class KotlinNativeBinaryContainer @Inject constructor(
|
||||
}
|
||||
|
||||
require(outputKind.availableFor(target.konanTarget)) {
|
||||
"Cannot create binary $name: ${outputKind.taskNameClassifier.decapitalize()} binaries are not available for target ${target.name}"
|
||||
"Cannot create ${outputKind.description}: $name. Binaries of this kind are not available for target ${target.name}"
|
||||
}
|
||||
|
||||
val binary = create(name, baseName, buildType, defaultCompilation)
|
||||
|
||||
+34
-7
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin
|
||||
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.Task
|
||||
import org.gradle.api.artifacts.Configuration
|
||||
import org.gradle.api.artifacts.ConfigurationContainer
|
||||
import org.gradle.api.artifacts.Dependency
|
||||
import org.gradle.api.artifacts.PublishArtifact
|
||||
import org.gradle.api.artifacts.*
|
||||
import org.gradle.api.artifacts.type.ArtifactTypeDefinition
|
||||
import org.gradle.api.attributes.Usage
|
||||
import org.gradle.api.attributes.Usage.USAGE_ATTRIBUTE
|
||||
@@ -29,6 +26,7 @@ import org.gradle.api.tasks.testing.Test
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.gradle.language.jvm.tasks.ProcessResources
|
||||
import org.gradle.nativeplatform.test.tasks.RunTestExecutable
|
||||
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
|
||||
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.MAIN_COMPILATION_NAME
|
||||
@@ -464,7 +462,7 @@ open class KotlinNativeTargetConfigurator(
|
||||
// endregion.
|
||||
|
||||
// region Task creation.
|
||||
private fun Project.createLinkTask(target: KotlinNativeTarget, binary: NativeBinary) {
|
||||
private fun Project.createLinkTask(binary: NativeBinary) {
|
||||
tasks.create(
|
||||
binary.linkTaskName,
|
||||
KotlinNativeLink::class.java
|
||||
@@ -569,6 +567,7 @@ open class KotlinNativeTargetConfigurator(
|
||||
override fun configureTarget(target: KotlinNativeTarget) {
|
||||
super.configureTarget(target)
|
||||
configureBinaries(target)
|
||||
configureFrameworkExport(target)
|
||||
configureCInterops(target)
|
||||
warnAboutIncorrectDependencies(target)
|
||||
}
|
||||
@@ -610,8 +609,9 @@ open class KotlinNativeTargetConfigurator(
|
||||
|
||||
protected fun configureBinaries(target: KotlinNativeTarget) {
|
||||
val project = target.project
|
||||
// Create link and run tasks.
|
||||
target.binaries.all {
|
||||
project.createLinkTask(target, it)
|
||||
project.createLinkTask(it)
|
||||
}
|
||||
|
||||
target.binaries.withType(Executable::class.java).all {
|
||||
@@ -655,6 +655,33 @@ open class KotlinNativeTargetConfigurator(
|
||||
}
|
||||
}
|
||||
|
||||
fun configureFrameworkExport(target: KotlinNativeTarget) {
|
||||
val project = target.project
|
||||
|
||||
target.compilations.all {
|
||||
// Allow resolving api configurations directly to be able to check that
|
||||
// all exported dependency are also added in the corresponding api configurations.
|
||||
// The check is performed during a link task execution.
|
||||
project.configurations.maybeCreate(it.apiConfigurationName).apply {
|
||||
isCanBeResolved = true
|
||||
usesPlatformOf(target)
|
||||
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(target))
|
||||
}
|
||||
}
|
||||
|
||||
target.binaries.withType(Framework::class.java).all { framework ->
|
||||
val exportConfiguration = project.configurations.maybeCreate(framework.exportConfigurationName).apply {
|
||||
isVisible = false
|
||||
isTransitive = false
|
||||
isCanBeConsumed = false
|
||||
isCanBeResolved = true
|
||||
usesPlatformOf(target)
|
||||
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(target))
|
||||
description = "Dependenceis to be exported in framework ${framework.name} for target ${target.targetName}"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun defineConfigurationsForTarget(target: KotlinNativeTarget) {
|
||||
super.defineConfigurationsForTarget(target)
|
||||
val configurations = target.project.configurations
|
||||
@@ -725,7 +752,7 @@ open class KotlinNativeTargetConfigurator(
|
||||
usesPlatformOf(target)
|
||||
isVisible = false
|
||||
isCanBeConsumed = false
|
||||
attributes.attribute(USAGE_ATTRIBUTE, compilation.target.project.usageByName(KotlinUsages.KOTLIN_API))
|
||||
attributes.attribute(USAGE_ATTRIBUTE, KotlinUsages.consumerApiUsage(target))
|
||||
description = "Dependencies for cinterop '${cinterop.name}' (compilation '${compilation.name}')."
|
||||
}
|
||||
}
|
||||
|
||||
+16
-1
@@ -149,7 +149,22 @@ class Framework(
|
||||
override val outputKind: NativeOutputKind
|
||||
get() = NativeOutputKind.FRAMEWORK
|
||||
|
||||
// TODO: Pack task configuration.
|
||||
val exportConfigurationName: String
|
||||
get() = target.disambiguateName(lowerCamelCaseName(name, "export"))
|
||||
|
||||
var transitiveExport: Boolean
|
||||
get() = project.configurations.maybeCreate(exportConfigurationName).isTransitive
|
||||
set(value) {
|
||||
project.configurations.maybeCreate(exportConfigurationName).isTransitive = value
|
||||
}
|
||||
|
||||
fun export(dependency: Any) {
|
||||
project.dependencies.add(exportConfigurationName, dependency)
|
||||
}
|
||||
|
||||
fun export(dependency: Any, configure: Closure<*>) {
|
||||
project.dependencies.add(exportConfigurationName, dependency, configure)
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
+58
-8
@@ -3,6 +3,7 @@ package org.jetbrains.kotlin.gradle.tasks
|
||||
import groovy.lang.Closure
|
||||
import org.gradle.api.DefaultTask
|
||||
import org.gradle.api.Project
|
||||
import org.gradle.api.artifacts.*
|
||||
import org.gradle.api.file.FileCollection
|
||||
import org.gradle.api.file.FileTree
|
||||
import org.gradle.api.provider.Provider
|
||||
@@ -77,6 +78,11 @@ private fun FileCollection.filterOutPublishableInteropLibs(project: Project): Fi
|
||||
}
|
||||
}
|
||||
|
||||
private fun Collection<File>.filterExternalKlibs(project: Project) = filter {
|
||||
// Support only klib files for now.
|
||||
it.extension == "klib" && !it.providedByCompiler(project)
|
||||
}
|
||||
|
||||
// endregion
|
||||
abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile<KotlinCommonOptions> {
|
||||
|
||||
@@ -270,10 +276,7 @@ abstract class AbstractKotlinNativeCompile : AbstractCompile(), KotlinCompile<Ko
|
||||
addArg("-o", outputFile.get().absolutePath)
|
||||
|
||||
// Libraries.
|
||||
libraries.files.filter {
|
||||
// Support only klib files for now.
|
||||
it.extension == "klib" && !it.providedByCompiler(project)
|
||||
}.forEach { library ->
|
||||
libraries.files.filterExternalKlibs(project).forEach { library ->
|
||||
addArg("-l", library.absolutePath)
|
||||
}
|
||||
}
|
||||
@@ -357,14 +360,64 @@ open class KotlinNativeLink : AbstractKotlinNativeCompile() {
|
||||
val linkerOpts: List<String>
|
||||
get() = binary.linkerOpts
|
||||
|
||||
@get:InputFiles
|
||||
val exportLibraries: FileCollection
|
||||
get() = binary.let {
|
||||
if (it is Framework) {
|
||||
project.configurations.getByName(it.exportConfigurationName)
|
||||
} else {
|
||||
project.files()
|
||||
}
|
||||
}
|
||||
|
||||
override fun buildArgs(defaultsOnly: Boolean): List<String> {
|
||||
val superArgs = super.buildArgs(defaultsOnly)
|
||||
return mutableListOf<String>().apply {
|
||||
addAll(superArgs)
|
||||
addArgIfNotNull("-entry", entryPoint)
|
||||
addListArg("-linker-options", linkerOpts)
|
||||
exportLibraries.files.filterExternalKlibs(project).forEach {
|
||||
add("-Xexport-library=${it.absolutePath}")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun validatedExportedLibraries() {
|
||||
val exportConfiguration = exportLibraries as? Configuration ?: return
|
||||
val apiFiles = project.configurations.getByName(compilation.apiConfigurationName).files.filterExternalKlibs(project)
|
||||
|
||||
val failed = mutableSetOf<Dependency>()
|
||||
exportConfiguration.allDependencies.forEach {
|
||||
val dependencyFiles = exportConfiguration.files(it).filterExternalKlibs(project)
|
||||
if (!apiFiles.containsAll(dependencyFiles)) {
|
||||
failed.add(it)
|
||||
}
|
||||
}
|
||||
|
||||
check(failed.isEmpty()) {
|
||||
val failedDependenciesList = failed.joinToString(separator = "\n") {
|
||||
when (it) {
|
||||
is FileCollectionDependency -> "|Files: ${it.files.files}"
|
||||
is ProjectDependency -> "|Project ${it.dependencyProject.path}"
|
||||
else -> "|${it.group}:${it.name}:${it.version}"
|
||||
}
|
||||
}
|
||||
|
||||
"""
|
||||
|Following dependencies exported in the ${binary.name} binary are not specified as API-dependencies of a corresponding source set:
|
||||
|
|
||||
$failedDependenciesList
|
||||
|
|
||||
|Please add them in the API-dependencies and rerun the build.
|
||||
""".trimMargin()
|
||||
}
|
||||
}
|
||||
|
||||
@TaskAction
|
||||
override fun compile() {
|
||||
validatedExportedLibraries()
|
||||
super.compile()
|
||||
}
|
||||
}
|
||||
|
||||
open class CInteropProcess : DefaultTask() {
|
||||
@@ -450,10 +503,7 @@ open class CInteropProcess : DefaultTask() {
|
||||
addArg("-lopt", it)
|
||||
}
|
||||
|
||||
libraries.files.filter {
|
||||
// Support only klib files for now.
|
||||
it.extension == "klib" && !it.providedByCompiler(project)
|
||||
}.forEach { library ->
|
||||
libraries.files.filterExternalKlibs(project).forEach { library ->
|
||||
addArg("-l", library.absolutePath)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user