gradle-plugin: generate CMake file

This commit is contained in:
Aleksey Kladov
2017-11-22 18:14:02 +03:00
committed by ilmat192
parent 5a858247bc
commit a033dbf131
3 changed files with 210 additions and 0 deletions
@@ -240,6 +240,7 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
companion object {
internal const val ARTIFACTS_CONTAINER_NAME = "konanArtifacts"
internal const val KONAN_DOWNLOAD_TASK_NAME = "checkKonanCompiler"
internal const val KONAN_GENERATE_CMAKE_TASK_NAME = "generateCMake"
internal const val COMPILE_ALL_TASK_NAME = "compileKonan"
internal const val KONAN_EXTENSION_NAME = "konan"
@@ -260,6 +261,7 @@ class KonanPlugin @Inject constructor(private val registry: ToolingModelBuilderR
project.plugins.apply("base")
// Create necessary tasks and extensions.
project.tasks.create(KONAN_DOWNLOAD_TASK_NAME, KonanCompilerDownloadTask::class.java)
project.tasks.create(KONAN_GENERATE_CMAKE_TASK_NAME, KonanGenerateCMakeTask::class.java)
project.extensions.create(KONAN_EXTENSION_NAME, KonanExtension::class.java)
project.extensions.create(ARTIFACTS_CONTAINER_NAME, KonanArtifactContainer::class.java, project)
@@ -0,0 +1,140 @@
/*
* 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.DefaultTask
import org.gradle.api.file.FileCollection
import org.gradle.api.tasks.TaskAction
import org.jetbrains.kotlin.gradle.plugin.KonanInteropLibrary
import org.jetbrains.kotlin.gradle.plugin.KonanLibrary
import org.jetbrains.kotlin.gradle.plugin.KonanProgram
import org.jetbrains.kotlin.gradle.plugin.konanArtifactsContainer
import org.jetbrains.kotlin.konan.target.TargetManager
import java.io.File
open class KonanGenerateCMakeTask : DefaultTask() {
@Suppress("unused")
@TaskAction
fun generateCMake() {
val interops = project.konanArtifactsContainer.toList().filterIsInstance<KonanInteropLibrary>()
val libraries = project.konanArtifactsContainer.toList().filterIsInstance<KonanLibrary>()
val programs = project.konanArtifactsContainer.toList().filterIsInstance<KonanProgram>()
val cMakeLists = generateCMakeLists(
project.name,
interops,
libraries,
programs
)
File(project.projectDir, "CMakeLists.txt")
.writeText(cMakeLists)
// This directory is filled out by the IDE
File(project.projectDir, "KotlinCMakeModule")
.mkdir()
}
private fun generateCMakeLists(
projectName: String,
interops: List<KonanInteropLibrary>,
libraries: List<KonanLibrary>,
programs: List<KonanProgram>
): String {
val cMakeCurrentListDir = "$" + "{CMAKE_CURRENT_LIST_DIR}"
return buildString {
appendln("""
cmake_minimum_required(VERSION 3.8)
set(CMAKE_MODULE_PATH $cMakeCurrentListDir/KotlinCMakeModule)
project($projectName Kotlin)
""".trimIndent())
appendln()
for (interop in interops) {
val task = interop[TargetManager.host] ?: continue
appendln(
Call("cinterop")
.arg("NAME", interop.name)
.arg("DEF_FILE", task.defFile.relativePath.toString())
.arg("COMPILER_OPTS", task.cMakeCompilerOpts)
)
}
for (library in libraries) {
val task = library[TargetManager.host] ?: continue
appendln(
Call("konanc_library")
.arg("NAME", library.name)
.arg("SOURCES", task.cMakeSources)
.arg("LIBRARIES", task.cMakeLibraries)
.arg("LINKER_OPTS", task.cMakeLinkerOpts))
}
for (program in programs) {
val task = program[TargetManager.host] ?: continue
appendln(
Call("konanc_executable")
.arg("NAME", program.name)
.arg("SOURCES", task.cMakeSources)
.arg("LIBRARIES", task.cMakeLibraries)
.arg("LINKER_OPTS", task.cMakeLinkerOpts))
}
}
}
private val File.relativePath get() = relativeTo(project.projectDir)
private val FileCollection.asCMakeSourceList: List<String>
get() = files.map { it.relativePath.toString() }
private val KonanInteropTask.cMakeCompilerOpts: String
get() = compilerOpts.joinToString(" ")
private val KonanCompileTask.cMakeSources: String
get() = srcFiles.flatMap { it.asCMakeSourceList }.joinToString(" ")
private val KonanCompileTask.cMakeLibraries: String
get() = mutableListOf<String>().apply {
addAll(libraries.artifacts.map { it.artifactName })
addAll(libraries.namedKlibs)
addAll(libraries.files.flatMap { it.files }.map { it.canonicalPath })
}.joinToString(" ")
private val KonanCompileTask.cMakeLinkerOpts: String
get() = linkerOpts.joinToString(" ")
}
private class Call(val name: String) {
private val args: MutableList<Pair<String, String>> = mutableListOf()
fun arg(key: String, value: String?): Call {
if (value != null && value.isNotBlank()) args += key to value
return this
}
override fun toString(): String =
buildString {
append(name)
append("(")
for ((key, value) in args) {
appendln()
append(" $key $value")
}
appendln(")")
}
}
@@ -0,0 +1,68 @@
package org.jetbrains.kotlin.gradle.plugin.test
class CMakeSpecification extends BaseKonanSpecification {
def 'Plugin should generate CMake from project without additional settings'() {
when:
def project = KonanProject.createEmpty(projectDirectory) { KonanProject it ->
it.buildFile.write("""
plugins { id 'konan' }
konanArtifacts {
interop('stdio')
interop('sdl') {
defFile 'src/main/c_interop/sdl.def'
includeDirs '/usr/include/SDL2'
}
library('main_lib')
program('Main') {
libraries {
artifact 'stdio'
artifact 'main_lib'
linkerOpts '-L/usr/lib/x86_64-linux-gnu'
}
}
}
""".stripIndent())
it.generateDefFile("stdio.def", "")
it.generateSrcFile("main.kt")
}
project.createRunner().withArguments('generateCMake').build()
def cMakeModule = new File(projectDirectory, "KotlinCMakeModule")
def cMakeLists = new File(projectDirectory, "CMakeLists.txt")
def expectedCMakeLists = """
cmake_minimum_required(VERSION 3.8)
set(CMAKE_MODULE_PATH \${CMAKE_CURRENT_LIST_DIR}/KotlinCMakeModule)
project(${projectDirectory.name} Kotlin)
cinterop(
NAME sdl
DEF_FILE src/main/c_interop/sdl.def
COMPILER_OPTS -I/usr/include/SDL2)
cinterop(
NAME stdio
DEF_FILE src/main/c_interop/stdio.def)
konanc_library(
NAME main_lib
SOURCES src/main/kotlin/main.kt)
konanc_executable(
NAME Main
SOURCES src/main/kotlin/main.kt
LIBRARIES stdio main_lib
LINKER_OPTS -L/usr/lib/x86_64-linux-gnu)
""".stripIndent().trim()
then:
cMakeModule.exists()
cMakeLists.exists()
def actualCMakeLists = cMakeLists.text.trim()
actualCMakeLists == expectedCMakeLists
}
}