[interop][shared] extract DefFile class for using in cinterop tool and gradle plugin
This commit is contained in:
committed by
Vasily Levchenko
parent
cc1f7aa5e0
commit
46e6d60749
@@ -26,4 +26,5 @@ mainClassName = "org.jetbrains.kotlin.native.interop.gen.jvm.MainKt"
|
||||
dependencies {
|
||||
compile "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
|
||||
compile project(':Interop:Indexer')
|
||||
compile project(':shared')
|
||||
}
|
||||
|
||||
+24
-66
@@ -16,11 +16,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.native.interop.gen.jvm
|
||||
|
||||
import org.jetbrains.kotlin.konan.util.DefFile
|
||||
import org.jetbrains.kotlin.native.interop.gen.HeadersInclusionPolicyImpl
|
||||
import org.jetbrains.kotlin.native.interop.gen.ImportsImpl
|
||||
import org.jetbrains.kotlin.native.interop.indexer.*
|
||||
import java.io.File
|
||||
import java.io.StringReader
|
||||
import java.lang.IllegalArgumentException
|
||||
import java.util.*
|
||||
import kotlin.reflect.KFunction
|
||||
@@ -126,10 +126,6 @@ private fun ProcessBuilder.runExpectingSuccess() {
|
||||
}
|
||||
}
|
||||
|
||||
private fun Properties.getSpaceSeparated(name: String): List<String> {
|
||||
return this.getProperty(name)?.split(' ')?.filter { it.isNotEmpty() } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun <T> Collection<T>.atMostOne(): T? {
|
||||
return when (this.size) {
|
||||
0 -> null
|
||||
@@ -271,43 +267,6 @@ private fun Properties.storeProperties(file: File) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseDefFile(file: File?, substitutions: Map<String, String>): Triple<Properties, Properties, List<String>> {
|
||||
val properties = Properties()
|
||||
|
||||
if (file == null) {
|
||||
return Triple(properties, Properties(), emptyList())
|
||||
}
|
||||
|
||||
val lines = file.readLines()
|
||||
|
||||
val separator = "---"
|
||||
val separatorIndex = lines.indexOf(separator)
|
||||
|
||||
val propertyLines: List<String>
|
||||
val headerLines: List<String>
|
||||
|
||||
if (separatorIndex != -1) {
|
||||
propertyLines = lines.subList(0, separatorIndex)
|
||||
headerLines = lines.subList(separatorIndex + 1, lines.size)
|
||||
} else {
|
||||
propertyLines = lines
|
||||
headerLines = emptyList()
|
||||
}
|
||||
|
||||
val propertiesReader = StringReader(propertyLines.joinToString(System.lineSeparator()))
|
||||
properties.load(propertiesReader)
|
||||
|
||||
// Pass unsubstituted copy of properties we have obtained from `.def`
|
||||
// to compiler `-maniest`.
|
||||
val manifestAddendProperties = properties.duplicate()
|
||||
|
||||
substitute(properties, substitutions)
|
||||
|
||||
return Triple(properties, manifestAddendProperties, headerLines)
|
||||
}
|
||||
|
||||
private fun Properties.duplicate() = Properties().apply { putAll(this@duplicate) }
|
||||
|
||||
private fun usage() {
|
||||
println("""
|
||||
Run interop tool with -def <def_file_for_lib>.def
|
||||
@@ -327,13 +286,13 @@ private fun downloadDependencies(dependenciesRoot: String, target: String, konan
|
||||
maybeExecuteHelper(dependenciesRoot, konanProperties, dependencyList)
|
||||
}
|
||||
|
||||
private fun selectNativeLanguage(config: Properties): Language {
|
||||
private fun selectNativeLanguage(config: DefFile.DefFileConfig): Language {
|
||||
val languages = mapOf(
|
||||
"C" to Language.C,
|
||||
"Objective-C" to Language.OBJECTIVE_C
|
||||
)
|
||||
|
||||
val language = config.getProperty("language") ?: return Language.C
|
||||
val language = config.language ?: return Language.C
|
||||
|
||||
return languages[language] ?:
|
||||
error("Unexpected language '$language'. Possible values are: ${languages.keys.joinToString { "'$it'" }}")
|
||||
@@ -389,8 +348,7 @@ private fun processLib(konanHome: String,
|
||||
return
|
||||
}
|
||||
|
||||
val (config, manifestAddendProperties, defHeaderLines)
|
||||
= parseDefFile(defFile, substitutions)
|
||||
val def = DefFile(defFile, substitutions)
|
||||
|
||||
val konanFileName = args["-properties"]?.single() ?:
|
||||
"${konanHome}/konan/konan.properties"
|
||||
@@ -409,10 +367,10 @@ private fun processLib(konanHome: String,
|
||||
val verbose = args["-verbose"].isTrue()
|
||||
|
||||
val defaultOpts = konanProperties.defaultCompilerOpts(target, dependencies)
|
||||
val headerFiles = config.getSpaceSeparated("headers") + additionalHeaders
|
||||
val language = selectNativeLanguage(config)
|
||||
val headerFiles = def.config.headers + additionalHeaders
|
||||
val language = selectNativeLanguage(def.config)
|
||||
val compilerOpts: List<String> = mutableListOf<String>().apply {
|
||||
addAll(config.getSpaceSeparated("compilerOpts"))
|
||||
addAll(def.config.compilerOpts)
|
||||
addAll(defaultOpts)
|
||||
addAll(additionalCompilerOpts)
|
||||
addAll(when (language) {
|
||||
@@ -428,19 +386,19 @@ private fun processLib(konanHome: String,
|
||||
})
|
||||
}
|
||||
val compiler = "clang"
|
||||
val excludeSystemLibs = config.getProperty("excludeSystemLibs")?.toBoolean() ?: false
|
||||
val excludeDependentModules = config.getProperty("excludeDependentModules")?.toBoolean() ?: false
|
||||
val excludeSystemLibs = def.config.excludeSystemLibs
|
||||
val excludeDependentModules = def.config.excludeDependentModules
|
||||
|
||||
val entryPoint = config.getSpaceSeparated("entryPoint").atMostOne()
|
||||
val entryPoint = def.config.entryPoints.atMostOne()
|
||||
val linkerOpts =
|
||||
config.getSpaceSeparated("linkerOpts").toTypedArray() + defaultOpts + additionalLinkerOpts
|
||||
val linker = args["-linker"]?.atMostOne() ?: config.getProperty("linker") ?: "clang"
|
||||
val excludedFunctions = config.getSpaceSeparated("excludedFunctions").toSet()
|
||||
val staticLibraries = config.getSpaceSeparated("staticLibraries") + args["-staticLibrary"].orEmpty()
|
||||
val libraryPaths = config.getSpaceSeparated("libraryPaths") + args["-libraryPath"].orEmpty()
|
||||
def.config.linkerOpts.toTypedArray() + defaultOpts + additionalLinkerOpts
|
||||
val linker = args["-linker"]?.atMostOne() ?: def.config.linker
|
||||
val excludedFunctions = def.config.excludedFunctions.toSet()
|
||||
val staticLibraries = def.config.staticLibraries + args["-staticLibrary"].orEmpty()
|
||||
val libraryPaths = def.config.libraryPaths + args["-libraryPath"].orEmpty()
|
||||
argsToCompiler ?. let { it.addAll(argsToCompiler(staticLibraries, libraryPaths)) }
|
||||
|
||||
val fqParts = (args["-pkg"]?.atMostOne() ?: config.getProperty("package"))?.let {
|
||||
val fqParts = (args["-pkg"]?.atMostOne() ?: def.config.packageName)?.let {
|
||||
it.split('.')
|
||||
} ?: defFile!!.name.split('.').reversed().drop(1)
|
||||
|
||||
@@ -452,13 +410,13 @@ private fun processLib(konanHome: String,
|
||||
|
||||
val libName = args["-cstubsname"]?.atMostOne() ?: fqParts.joinToString("") + "stubs"
|
||||
|
||||
val headerFilterGlobs = config.getSpaceSeparated("headerFilter")
|
||||
val headerFilterGlobs = def.config.headerFilter
|
||||
val imports = parseImports(args)
|
||||
val headerInclusionPolicy = HeadersInclusionPolicyImpl(headerFilterGlobs, imports)
|
||||
|
||||
val library = NativeLibrary(
|
||||
includes = headerFiles,
|
||||
additionalPreambleLines = defHeaderLines,
|
||||
additionalPreambleLines = def.defHeaderLines,
|
||||
compilerArgs = compilerOpts,
|
||||
language = language,
|
||||
excludeSystemLibs = excludeSystemLibs,
|
||||
@@ -470,8 +428,8 @@ private fun processLib(konanHome: String,
|
||||
library = library,
|
||||
pkgName = outKtPkg,
|
||||
excludedFunctions = excludedFunctions,
|
||||
strictEnums = config.getSpaceSeparated("strictEnums").toSet(),
|
||||
nonStrictEnums = config.getSpaceSeparated("nonStrictEnums").toSet()
|
||||
strictEnums = def.config.strictEnums.toSet(),
|
||||
nonStrictEnums = def.config.nonStrictEnums.toSet()
|
||||
)
|
||||
|
||||
val nativeIndex = buildNativeIndex(library)
|
||||
@@ -490,13 +448,13 @@ private fun processLib(konanHome: String,
|
||||
}
|
||||
|
||||
// TODO: if a library has partially included headers, then it shouldn't be used as a dependency.
|
||||
manifestAddendProperties["includedHeaders"] = nativeIndex.includedHeaders.joinToString(" ") { it.value }
|
||||
manifestAddendProperties["pkg"] = outKtPkg
|
||||
def.manifestAddendProperties["includedHeaders"] = nativeIndex.includedHeaders.joinToString(" ") { it.value }
|
||||
def.manifestAddendProperties["pkg"] = outKtPkg
|
||||
|
||||
gen.addManifestProperties(manifestAddendProperties)
|
||||
gen.addManifestProperties(def.manifestAddendProperties)
|
||||
|
||||
manifestAddend?.parentFile?.mkdirs()
|
||||
manifestAddend?.let { manifestAddendProperties.storeProperties(it) }
|
||||
manifestAddend?.let { def.manifestAddendProperties.storeProperties(it) }
|
||||
|
||||
val workDir = defFile?.absoluteFile?.parentFile ?: File(userDir)
|
||||
|
||||
|
||||
@@ -0,0 +1,133 @@
|
||||
package org.jetbrains.kotlin.konan.util
|
||||
|
||||
import java.io.File
|
||||
import java.io.StringReader
|
||||
import java.util.*
|
||||
|
||||
class DefFile(val file:File?, val config:DefFileConfig, val manifestAddendProperties:Properties, val defHeaderLines:List<String>) {
|
||||
private constructor(file0:File?, triple: Triple<Properties, Properties, List<String>>): this(file0, DefFileConfig(triple.first), triple.second, triple.third)
|
||||
constructor(file:File?, substitutions: Map<String, String>) : this(file, parseDefFile(file, substitutions))
|
||||
|
||||
val name by lazy {
|
||||
file?.nameWithoutExtension ?: ""
|
||||
}
|
||||
class DefFileConfig(private val properties: Properties) {
|
||||
val headers by lazy {
|
||||
properties.getSpaceSeparated("headers")
|
||||
}
|
||||
|
||||
val language by lazy {
|
||||
properties.getProperty("language")
|
||||
}
|
||||
|
||||
val compilerOpts by lazy {
|
||||
properties.getSpaceSeparated("compilerOpts")
|
||||
}
|
||||
|
||||
val excludeSystemLibs by lazy {
|
||||
properties.getProperty("excludeSystemLibs")?.toBoolean() ?: false
|
||||
}
|
||||
|
||||
val excludeDependentModules by lazy {
|
||||
properties.getProperty("excludeDependentModules")?.toBoolean() ?: false
|
||||
}
|
||||
|
||||
val entryPoints by lazy {
|
||||
properties.getSpaceSeparated("entryPoint")
|
||||
}
|
||||
|
||||
val linkerOpts by lazy {
|
||||
properties.getSpaceSeparated("linkerOpts")
|
||||
}
|
||||
|
||||
val linker by lazy {
|
||||
properties.getProperty("linker", "clang")
|
||||
}
|
||||
|
||||
val excludedFunctions by lazy {
|
||||
properties.getSpaceSeparated("excludedFunctions")
|
||||
}
|
||||
|
||||
val staticLibraries by lazy {
|
||||
properties.getSpaceSeparated("staticLibraries")
|
||||
}
|
||||
|
||||
val libraryPaths by lazy {
|
||||
properties.getSpaceSeparated("libraryPaths")
|
||||
}
|
||||
|
||||
val packageName by lazy {
|
||||
properties.getProperty("package")
|
||||
}
|
||||
|
||||
val headerFilter by lazy {
|
||||
properties.getSpaceSeparated("headerFilter")
|
||||
}
|
||||
|
||||
val strictEnums by lazy {
|
||||
properties.getSpaceSeparated("strictEnums")
|
||||
}
|
||||
|
||||
val nonStrictEnums by lazy {
|
||||
properties.getSpaceSeparated("nonStrictEnums")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Properties.getSpaceSeparated(name: String): List<String> {
|
||||
return this.getProperty(name)?.split(' ')?.filter { it.isNotEmpty() } ?: emptyList()
|
||||
}
|
||||
|
||||
private fun parseDefFile(file: File?, substitutions: Map<String, String>): Triple<Properties, Properties, List<String>> {
|
||||
val properties = Properties()
|
||||
|
||||
if (file == null) {
|
||||
return Triple(properties, Properties(), emptyList())
|
||||
}
|
||||
|
||||
val lines = file.readLines()
|
||||
|
||||
val separator = "---"
|
||||
val separatorIndex = lines.indexOf(separator)
|
||||
|
||||
val propertyLines: List<String>
|
||||
val headerLines: List<String>
|
||||
|
||||
if (separatorIndex != -1) {
|
||||
propertyLines = lines.subList(0, separatorIndex)
|
||||
headerLines = lines.subList(separatorIndex + 1, lines.size)
|
||||
} else {
|
||||
propertyLines = lines
|
||||
headerLines = emptyList()
|
||||
}
|
||||
|
||||
val propertiesReader = StringReader(propertyLines.joinToString(System.lineSeparator()))
|
||||
properties.load(propertiesReader)
|
||||
|
||||
// Pass unsubstituted copy of properties we have obtained from `.def`
|
||||
// to compiler `-maniest`.
|
||||
val manifestAddendProperties = properties.duplicate()
|
||||
|
||||
substitute(properties, substitutions)
|
||||
|
||||
return Triple(properties, manifestAddendProperties, headerLines)
|
||||
}
|
||||
|
||||
// Performs substitution similar to:
|
||||
// foo = ${foo} ${foo.${arch}} ${foo.${os}}
|
||||
fun substitute(properties: Properties, substitutions: Map<String, String>) {
|
||||
for (key in properties.stringPropertyNames()) {
|
||||
for (substitution in substitutions.values) {
|
||||
val suffix = ".$substitution"
|
||||
if (key.endsWith(suffix)) {
|
||||
val baseKey = key.removeSuffix(suffix)
|
||||
val oldValue = properties.getProperty(baseKey, "")
|
||||
val appendedValue = properties.getProperty(key, "")
|
||||
val newValue = if (oldValue != "") "$oldValue $appendedValue" else appendedValue
|
||||
properties.setProperty(baseKey, newValue)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun Properties.duplicate() = Properties().apply { putAll(this@duplicate) }
|
||||
Reference in New Issue
Block a user