Move cinterop tool to @Argument based command line description.

This commit is contained in:
Alexander Gorshenev
2017-12-20 16:26:57 +03:00
committed by alexander-gorshenev
parent 70866092d2
commit 83a56f1931
4 changed files with 147 additions and 53 deletions
+1
View File
@@ -25,6 +25,7 @@ mainClassName = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
dependencies {
compile "org.jetbrains.kotlin:kotlin-stdlib:$buildKotlinVersion"
compile "org.jetbrains.kotlin:kotlin-compiler:$buildKotlinVersion"
compile project(':Interop:Indexer')
compile project(':shared')
}
@@ -0,0 +1,113 @@
/*
* 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.native.interop.tool
import org.jetbrains.kotlin.cli.common.arguments.*
open class CommonInteropArguments : CommonToolArguments() {
@Argument(value = "-flavor", valueDescription = "<flavor>", description = "One of: jvm, native")
var flavor: String? = null
@Argument(value = "-pkg", valueDescription = "<fully qualified name>", description = "place generated bindings to the package")
var pkg: String? = null
@Argument(value = "-generated", valueDescription = "<dir>", description = "place generated bindings to the directory")
var generated: String? = null
}
class CInteropArguments : CommonInteropArguments() {
@Argument(value = "-import", valueDescription = "<imports>", description = "a semicolon separated list of headers, prepended with the package name")
var import: Array<String> = arrayOf()
@Argument(value = "-target", valueDescription = "<target>", description = "native target to compile to")
var target: String? = null
@Argument(value = "-natives", valueDescription = "<directory>", description = "where to put the built native files")
var natives: String? = null
@Argument(value = "-def", valueDescription = "<file>", description = "the library definition file")
var def: String? = null
@Argument(value = "-manifest", valueDescription = "<file>", description = "library manifest addend")
var manifest: String? = null
@Argument(value = "-properties", valueDescription = "<file>", description = "an alternative location of konan.properties file")
var properties: String? = null
// TODO: the short -h for -header conflicts with -h for -help.
// The -header currently wins, but need to make it a little more sound.
@Argument(value = "-header", shortName = "-h", valueDescription = "<file>", description = "header file to produce kotlin bindings for")
var header: Array<String> = arrayOf()
@Argument(value = HEADER_FILTER_ADDITIONAL_SEARCH_PREFIX, shortName = "-hfasp", valueDescription = "<file>", description = "header file to produce kotlin bindings for")
var headerFilterPrefix: Array<String> = arrayOf()
@Argument(value = "-compilerOpts", shortName = "-copt", valueDescription = "<arg>", description = "additional compiler options")
var compilerOpts: Array<String> = arrayOf()
@Argument(value = "-linkerOpts", shortName = "-lopt", valueDescription = "<arg>", description = "additional linker options")
var linkerOpts: Array<String> = arrayOf()
@Argument(value = "-shims", description = "wrap bindings by a tracing layer")
var shims: Boolean = false
@Argument(value = "-linker", valueDescription = "<file>", description = "use specified linker")
var linker: String? = null
@Argument(value = "-staticLibrary", valueDescription = "<file>", description = "embed static library to the result")
var staticLibrary: Array<String> = arrayOf()
@Argument(value = "-libraryPath", valueDescription = "<dir>", description = "add a library search path")
var libraryPath: Array<String> = arrayOf()
@Argument(value = "-cstubsname", valueDescription = "<name>", description = "provide a name for the generated c stubs file")
var cstubsname: String? = null
@Argument(value = "-keepcstubs", description = "preserve the generated c stubs for inspection")
var keepcstubs: Boolean = false
}
const val HEADER_FILTER_ADDITIONAL_SEARCH_PREFIX = "-headerFilterAdditionalSearchPrefix"
fun <T: CommonToolArguments> parseCommandLine(args: Array<String>, arguments: T): T {
parseCommandLineArguments(args.asList(), arguments)
reportArgumentParseProblems(arguments.errors)
return arguments
}
// Integrate with CLITool from the big Kotlin and get rid of the mess below.
internal fun warn(msg: String) {
println("warning: $msg")
}
// This is a copy of CLITool.kt's function adapted to work without a collector.
private fun reportArgumentParseProblems(errors: ArgumentParseErrors) {
for (flag in errors.unknownExtraFlags) {
warn("Flag is not supported by this version of the compiler: $flag")
}
for (argument in errors.extraArgumentsPassedInObsoleteForm) {
warn("Advanced option value is passed in an obsolete form. Please use the '=' character " +
"to specify the value: $argument=...")
}
for ((key, value) in errors.duplicateArguments) {
warn("Argument $key is passed multiple times. Only the last value will be used: $value")
}
for ((deprecatedName, newName) in errors.deprecatedArguments) {
warn("Argument $deprecatedName is deprecated. Please use $newName instead")
}
}
@@ -29,8 +29,8 @@ import java.util.*
fun main(args: Array<String>) = interop(args, null)
fun interop(args: Array<String>, argsToCompiler: MutableList<String>? = null) {
processLib(parseArgs(args), argsToCompiler)
val arguments = parseCommandLine(args, CInteropArguments())
processLib(arguments, argsToCompiler)
}
// Options, whose values are space-separated and can be escaped.
@@ -42,22 +42,6 @@ private fun String.asArgList(key: String) =
else
listOf(this)
private fun parseArgs(args: Array<String>): Map<String, List<String>> {
val commandLine = mutableMapOf<String, MutableList<String>>()
for (index in 0..args.size - 1 step 2) {
val key = args[index]
if (key[0] != '-') {
throw IllegalArgumentException("Expected a flag with initial dash: $key")
}
if (index + 1 == args.size) {
throw IllegalArgumentException("Expected an value after $key")
}
val value = args[index + 1].asArgList(key)
commandLine[key]?.addAll(value) ?: commandLine.put(key, value.toMutableList())
}
return commandLine
}
// Performs substitution similar to:
// foo = ${foo} ${foo.${arch}} ${foo.${os}}
private fun substitute(properties: Properties, substitutions: Map<String, String>) {
@@ -150,10 +134,8 @@ private fun Properties.putAndRunOnReplace(key: Any, newValue: Any, beforeReplace
this[key] = newValue
}
private fun warn(msg: String) {
println("warning: $msg")
}
// TODO: Utilize Usage from the big Kotlin.
// That requires to extend the CLITool class.
private fun usage() {
println("""
Run interop tool with -def <def_file_for_lib>.def
@@ -201,23 +183,21 @@ private fun argsToCompiler(staticLibraries: List<String>, libraryPaths: List<Str
.map { it -> listOf("-includeBinary", it) } .flatten()
}
private fun parseImports(args: Map<String, List<String>>): ImportsImpl {
val headerIdToPackage = (args["-import"] ?: emptyList()).map { arg ->
private fun parseImports(imports: Array<String>): ImportsImpl {
val headerIdToPackage = imports.map { arg ->
val (pkg, joinedIds) = arg.split(':')
val ids = joinedIds.split(',')
val ids = joinedIds.split(';')
ids.map { HeaderId(it) to pkg }
}.reversed().flatten().toMap()
return ImportsImpl(headerIdToPackage)
}
fun getCompilerFlagsForVfsOverlay(args: Map<String, List<String>>, def: DefFile): List<String> {
fun getCompilerFlagsForVfsOverlay(headerFilterPrefix: Array<String>, def: DefFile): List<String> {
val relativeToRoot = mutableMapOf<Path, Path>() // TODO: handle clashes
val HEADER_FILTER_ADDITIONAL_SEARCH_PREFIX = "-headerFilterAdditionalSearchPrefix"
val filteredIncludeDirs = args[HEADER_FILTER_ADDITIONAL_SEARCH_PREFIX]?.map { Paths.get(it) }
if (filteredIncludeDirs != null) {
val filteredIncludeDirs = headerFilterPrefix .map { Paths.get(it) }
if (filteredIncludeDirs.isNotEmpty()) {
val headerFilterGlobs = def.config.headerFilter
if (headerFilterGlobs.isEmpty()) {
error("'$HEADER_FILTER_ADDITIONAL_SEARCH_PREFIX' option requires " +
@@ -267,36 +247,36 @@ private fun findFilesByGlobs(roots: List<Path>, globs: List<String>): Map<Path,
}
private fun processLib(args: Map<String, List<String>>,
private fun processLib(arguments: CInteropArguments,
argsToCompiler: MutableList<String>?) {
val userDir = System.getProperty("user.dir")
val ktGenRoot = args["-generated"]?.single() ?: userDir
val nativeLibsDir = args["-natives"]?.single() ?: userDir
val flavorName = args["-flavor"]?.single() ?: "jvm"
val ktGenRoot = arguments.generated ?: userDir
val nativeLibsDir = arguments.natives ?: userDir
val flavorName = arguments.flavor ?: "jvm"
val flavor = KotlinPlatform.values().single { it.name.equals(flavorName, ignoreCase = true) }
val defFile = args["-def"]?.single()?.let { File(it) }
val manifestAddend = args["-manifest"]?.single()?.let { File(it) }
val defFile = arguments.def?.let { File(it) }
val manifestAddend = arguments.manifest?.let { File(it) }
if (defFile == null && args["-pkg"] == null) {
if (defFile == null && arguments.pkg == null) {
usage()
return
}
val tool = ToolConfig(
args["-target"]?.single(),
args["-properties"]?.single(),
arguments.target,
arguments.properties,
System.getProperty("konan.home")
)
tool.downloadDependencies()
val def = DefFile(defFile, tool.substitutions)
val additionalHeaders = args["-h"].orEmpty()
val additionalCompilerOpts = args["-copt"].orEmpty() + args["-compilerOpts"].orEmpty()
val additionalLinkerOpts = args["-lopt"].orEmpty() + args["-linkerOpts"].orEmpty()
val generateShims = args["-shims"].isTrue()
val verbose = args["-verbose"].isTrue()
val additionalHeaders = arguments.header
val additionalCompilerOpts = arguments.compilerOpts
val additionalLinkerOpts = arguments.linkerOpts
val generateShims = arguments.shims
val verbose = arguments.verbose
System.load(tool.libclang)
@@ -306,7 +286,7 @@ private fun processLib(args: Map<String, List<String>>,
addAll(def.config.compilerOpts)
addAll(tool.defaultCompilerOpts)
addAll(additionalCompilerOpts)
addAll(getCompilerFlagsForVfsOverlay(args, def))
addAll(getCompilerFlagsForVfsOverlay(arguments.headerFilterPrefix, def))
addAll(when (language) {
Language.C -> emptyList()
Language.OBJECTIVE_C -> {
@@ -328,15 +308,15 @@ private fun processLib(args: Map<String, List<String>>,
def.config.linkerOpts.toTypedArray() +
tool.defaultCompilerOpts +
additionalLinkerOpts
val linkerName = args["-linker"]?.atMostOne() ?: def.config.linker
val linkerName = arguments.linker ?: def.config.linker
val linker = "${tool.llvmHome}/bin/$linkerName"
val compiler = "${tool.llvmHome}/bin/clang"
val excludedFunctions = def.config.excludedFunctions.toSet()
val staticLibraries = def.config.staticLibraries + args["-staticLibrary"].orEmpty()
val libraryPaths = def.config.libraryPaths + args["-libraryPath"].orEmpty()
val staticLibraries = def.config.staticLibraries + arguments.staticLibrary
val libraryPaths = def.config.libraryPaths + arguments.libraryPath
argsToCompiler ?. let { it.addAll(argsToCompiler(staticLibraries, libraryPaths)) }
val fqParts = (args["-pkg"]?.atMostOne() ?: def.config.packageName)?.let {
val fqParts = (arguments.pkg ?: def.config.packageName)?.let {
it.split('.')
} ?: defFile!!.name.split('.').reversed().drop(1)
@@ -346,10 +326,10 @@ private fun processLib(args: Map<String, List<String>>,
val outKtFileRelative = (fqParts + outKtFileName).joinToString("/")
val outKtFile = File(ktGenRoot, outKtFileRelative)
val libName = args["-cstubsname"]?.atMostOne() ?: fqParts.joinToString("") + "stubs"
val libName = arguments.cstubsname ?: fqParts.joinToString("") + "stubs"
val headerFilterGlobs = def.config.headerFilter
val imports = parseImports(args)
val imports = parseImports(arguments.import)
val headerInclusionPolicy = HeadersInclusionPolicyImpl(headerFilterGlobs, imports)
val library = NativeLibrary(
@@ -431,7 +411,7 @@ private fun processLib(args: Map<String, List<String>>,
runCmd(compilerCmd, workDir, verbose)
}
if (!args["-keepcstubs"].isTrue()) {
if (!arguments.keepcstubs) {
outCFile.delete()
}
}
@@ -76,7 +76,7 @@ fun invokeCinterop(args: Array<String>) {
manifestProperties["package"]?.let {
val pkg = it as String
val headerIds = (manifestProperties["includedHeaders"] as String).split(' ')
val arg = "$pkg:${headerIds.joinToString(",")}"
val arg = "$pkg:${headerIds.joinToString(";")}"
listOf("-import", arg)
} ?: emptyList()
}