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()
|
||||
|
||||
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(
|
||||
arguments: K2NativeCompilerArguments,
|
||||
configuration: CompilerConfiguration
|
||||
): Map<String, String>? =
|
||||
arguments.overrideKonanProperties?.mapNotNull {
|
||||
val keyValueSeparatorIndex = it.indexOf('=')
|
||||
if (keyValueSeparatorIndex > 0) {
|
||||
it.substringBefore('=') to it.substringAfter('=')
|
||||
} else {
|
||||
configuration.report(
|
||||
ERROR,
|
||||
"incorrect property format: expected '<key>=<value>', got '$it'"
|
||||
)
|
||||
null
|
||||
}
|
||||
}?.toMap()
|
||||
): Map<String, String>? = parseKeyValuePairs(arguments.overrideKonanProperties, configuration)
|
||||
|
||||
private fun parseKeyValuePairs(
|
||||
argumentValue: Array<String>?,
|
||||
configuration: CompilerConfiguration
|
||||
): Map<String, String>? = argumentValue?.mapNotNull {
|
||||
val keyValueSeparatorIndex = it.indexOf('=')
|
||||
if (keyValueSeparatorIndex > 0) {
|
||||
it.substringBefore('=') to it.substringAfter('=')
|
||||
} else {
|
||||
configuration.report(
|
||||
ERROR,
|
||||
"incorrect property format: expected '<key>=<value>', got '$it'"
|
||||
)
|
||||
null
|
||||
}
|
||||
}?.toMap()
|
||||
|
||||
|
||||
|
||||
|
||||
+7
@@ -344,6 +344,13 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
)
|
||||
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> =
|
||||
super.configureAnalysisFlags(collector, languageVersion).also {
|
||||
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