Native: introduce binary options machinery
This commit is contained in:
committed by
Space
parent
18cc498763
commit
7cc1ea8801
@@ -367,6 +367,10 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
|
parseBinaryOptions(arguments, configuration).forEach { optionWithValue ->
|
||||||
|
configuration.put(optionWithValue)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -570,22 +574,64 @@ private fun parseDebugPrefixMap(
|
|||||||
}
|
}
|
||||||
}.toMap()
|
}.toMap()
|
||||||
|
|
||||||
|
private class BinaryOptionWithValue<T : Any>(val option: BinaryOption<T>, val value: T)
|
||||||
|
|
||||||
|
private fun <T : Any> CompilerConfiguration.put(binaryOptionWithValue: BinaryOptionWithValue<T>) {
|
||||||
|
this.put(binaryOptionWithValue.option.compilerConfigurationKey, binaryOptionWithValue.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun parseBinaryOptions(
|
||||||
|
arguments: K2NativeCompilerArguments,
|
||||||
|
configuration: CompilerConfiguration
|
||||||
|
): List<BinaryOptionWithValue<*>> {
|
||||||
|
val keyValuePairs = parseKeyValuePairs(arguments.binaryOptions, configuration) ?: return emptyList()
|
||||||
|
|
||||||
|
return keyValuePairs.mapNotNull { (key, value) ->
|
||||||
|
val option = BinaryOptions.getByName(key)
|
||||||
|
if (option == null) {
|
||||||
|
configuration.report(STRONG_WARNING, "Unknown binary option '$key'")
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
parseBinaryOption(option, value, configuration)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun <T : Any> parseBinaryOption(
|
||||||
|
option: BinaryOption<T>,
|
||||||
|
valueName: String,
|
||||||
|
configuration: CompilerConfiguration
|
||||||
|
): BinaryOptionWithValue<T>? {
|
||||||
|
val value = option.valueParser.parse(valueName)
|
||||||
|
return if (value == null) {
|
||||||
|
configuration.report(STRONG_WARNING, "Unknown value '$valueName' of binary option '${option.name}'. " +
|
||||||
|
"Possible values are: ${option.valueParser.validValuesHint}")
|
||||||
|
null
|
||||||
|
} else {
|
||||||
|
BinaryOptionWithValue(option, value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun parseOverrideKonanProperties(
|
private fun parseOverrideKonanProperties(
|
||||||
arguments: K2NativeCompilerArguments,
|
arguments: K2NativeCompilerArguments,
|
||||||
configuration: CompilerConfiguration
|
configuration: CompilerConfiguration
|
||||||
): Map<String, String>? =
|
): Map<String, String>? = parseKeyValuePairs(arguments.overrideKonanProperties, configuration)
|
||||||
arguments.overrideKonanProperties?.mapNotNull {
|
|
||||||
val keyValueSeparatorIndex = it.indexOf('=')
|
private fun parseKeyValuePairs(
|
||||||
if (keyValueSeparatorIndex > 0) {
|
argumentValue: Array<String>?,
|
||||||
it.substringBefore('=') to it.substringAfter('=')
|
configuration: CompilerConfiguration
|
||||||
} else {
|
): Map<String, String>? = argumentValue?.mapNotNull {
|
||||||
configuration.report(
|
val keyValueSeparatorIndex = it.indexOf('=')
|
||||||
ERROR,
|
if (keyValueSeparatorIndex > 0) {
|
||||||
"incorrect property format: expected '<key>=<value>', got '$it'"
|
it.substringBefore('=') to it.substringAfter('=')
|
||||||
)
|
} else {
|
||||||
null
|
configuration.report(
|
||||||
}
|
ERROR,
|
||||||
}?.toMap()
|
"incorrect property format: expected '<key>=<value>', got '$it'"
|
||||||
|
)
|
||||||
|
null
|
||||||
|
}
|
||||||
|
}?.toMap()
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+7
@@ -344,6 +344,13 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
)
|
)
|
||||||
var llvmVariant: String? = null
|
var llvmVariant: String? = null
|
||||||
|
|
||||||
|
@Argument(
|
||||||
|
value = "-Xbinary",
|
||||||
|
valueDescription = "<option=value>",
|
||||||
|
description = "Specify binary option"
|
||||||
|
)
|
||||||
|
var binaryOptions: Array<String>? = null
|
||||||
|
|
||||||
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> =
|
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> =
|
||||||
super.configureAnalysisFlags(collector, languageVersion).also {
|
super.configureAnalysisFlags(collector, languageVersion).also {
|
||||||
val useExperimental = it[AnalysisFlags.useExperimental] as List<*>
|
val useExperimental = it[AnalysisFlags.useExperimental] as List<*>
|
||||||
|
|||||||
+74
@@ -0,0 +1,74 @@
|
|||||||
|
/*
|
||||||
|
* 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.backend.konan
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.config.CompilerConfigurationKey
|
||||||
|
import kotlin.properties.PropertyDelegateProvider
|
||||||
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
|
||||||
|
// Note: options defined in this class are a part of user interface, including the names:
|
||||||
|
// users can pass these options using a -Xbinary=name=value compiler argument or corresponding Gradle DSL.
|
||||||
|
object BinaryOptions : BinaryOptionRegistry() {
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BinaryOption<T : Any>(
|
||||||
|
val name: String,
|
||||||
|
val valueParser: ValueParser<T>,
|
||||||
|
val compilerConfigurationKey: CompilerConfigurationKey<T> = CompilerConfigurationKey.create(name)
|
||||||
|
) {
|
||||||
|
interface ValueParser<T : Any> {
|
||||||
|
fun parse(value: String): T?
|
||||||
|
val validValuesHint: String?
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
open class BinaryOptionRegistry {
|
||||||
|
private val registeredOptionsByName = mutableMapOf<String, BinaryOption<*>>()
|
||||||
|
|
||||||
|
protected fun register(option: BinaryOption<*>) {
|
||||||
|
val previousOption = registeredOptionsByName[option.name]
|
||||||
|
if (previousOption != null) {
|
||||||
|
error("option '${option.name}' is registered twice")
|
||||||
|
}
|
||||||
|
registeredOptionsByName[option.name] = option
|
||||||
|
}
|
||||||
|
|
||||||
|
fun getByName(name: String): BinaryOption<*>? = registeredOptionsByName[name]
|
||||||
|
|
||||||
|
protected fun booleanOption(): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, CompilerConfigurationKey<Boolean>>> =
|
||||||
|
PropertyDelegateProvider { _, property ->
|
||||||
|
val option = BinaryOption(property.name, BooleanValueParser)
|
||||||
|
register(option)
|
||||||
|
ReadOnlyProperty { _, _ ->
|
||||||
|
option.compilerConfigurationKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
protected inline fun <reified T : Enum<T>> option(): PropertyDelegateProvider<Any?, ReadOnlyProperty<Any?, CompilerConfigurationKey<T>>> =
|
||||||
|
PropertyDelegateProvider { _, property ->
|
||||||
|
val option = BinaryOption(property.name, EnumValueParser(enumValues<T>().toList()))
|
||||||
|
register(option)
|
||||||
|
ReadOnlyProperty { _, _ ->
|
||||||
|
option.compilerConfigurationKey
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private object BooleanValueParser : BinaryOption.ValueParser<Boolean> {
|
||||||
|
override fun parse(value: String): Boolean? = value.toBooleanStrictOrNull()
|
||||||
|
|
||||||
|
override val validValuesHint: String?
|
||||||
|
get() = "true|false"
|
||||||
|
}
|
||||||
|
|
||||||
|
@PublishedApi
|
||||||
|
internal class EnumValueParser<T : Enum<T>>(val values: List<T>) : BinaryOption.ValueParser<T> {
|
||||||
|
// TODO: should we really ignore case here?
|
||||||
|
override fun parse(value: String): T? = values.firstOrNull { it.name.equals(value, ignoreCase = true) }
|
||||||
|
|
||||||
|
override val validValuesHint: String?
|
||||||
|
get() = values.joinToString("|")
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user