Allow prefix and relative path in resolvable properties.

It allows us to move more logic to konan.properties from ClangArgs.
E.g., something like `-$absoluteTargetSysRoot/usr/include/c++/4.9.4`
This commit is contained in:
Sergey Bogolepov
2020-10-21 19:48:25 +07:00
parent 84129098cb
commit eeda48e63e
2 changed files with 78 additions and 3 deletions
@@ -107,13 +107,33 @@ fun Properties.resolvablePropertyString(
*/
private fun String.resolveValue(properties: Properties, visitedProperties: MutableSet<String> = mutableSetOf()): List<String> =
when {
startsWith("$") -> {
val property = this.substringAfter('$')
contains("$") -> {
val prefix = this.substringBefore('$', missingDelimiterValue = "")
val withoutSigil = this.substringAfter('$')
val property = withoutSigil.substringBefore('/')
val relative = withoutSigil.substringAfter('/', missingDelimiterValue = "")
// Keep track of visited properties to avoid running in circles.
if (!visitedProperties.add(property)) {
error("Circular dependency: ${visitedProperties.joinToString()}")
}
properties.resolvablePropertyList(property, visitedProperties = visitedProperties)
val substitutionResult = properties.resolvablePropertyList(property, visitedProperties = visitedProperties)
when {
substitutionResult.size > 1 -> when {
relative.isNotEmpty() ->
error("Cannot append `/$relative` to multiple values: ${substitutionResult.joinToString()}")
prefix.isNotEmpty() ->
error("Cannot add prefix `$prefix` to multiple values: ${substitutionResult.joinToString()}")
else -> substitutionResult
}
else -> substitutionResult.map {
// Avoid repeated '/' at the end.
if (relative.isNotEmpty()) {
"$prefix${it.dropLastWhile { it == '/' }}/$relative"
} else {
"$prefix$it"
}
}
}
}
else -> listOf(this)
}
@@ -65,6 +65,61 @@ class ResolvablePropertiesTests {
props.resolvablePropertyString("k1")
}
@Test
fun `trivial relative path`() {
val props = propertiesOf(
"k1" to "v1",
"k2" to "\$k1/sysroot"
)
assertEquals("v1/sysroot", props.resolvablePropertyString("k2"))
}
@Test
fun `two-fold relative path`() {
val props = propertiesOf(
"k1" to "v1",
"k2" to "\$k1/toolchain",
"k3" to "\$k2/sysroot"
)
assertEquals("v1/toolchain/sysroot", props.resolvablePropertyString("k3"))
}
@Test
fun `absolute path`() {
val props = propertiesOf(
"k1" to "/",
"k2" to "\$k1/bin"
)
assertEquals("/bin", props.resolvablePropertyString("k2"))
}
@Test(expected = java.lang.IllegalStateException::class)
fun `incorrect relative path`() {
val props = propertiesOf(
"k1" to "v1 v2",
"k2" to "\$k1/sysroot"
)
props.resolvablePropertyString("k2")
}
@Test
fun `simple prefix`() {
val props = propertiesOf(
"k1" to "v1",
"k2" to "--key=\$k1"
)
assertEquals("--key=v1", props.resolvablePropertyString("k2"))
}
@Test
fun `with prefix and relative`() {
val props = propertiesOf(
"absoluteTargetSysRoot" to "/",
"include" to "-I\$absoluteTargetSysRoot/usr/include/c++/4.9.4"
)
assertEquals("-I/usr/include/c++/4.9.4", props.resolvablePropertyString("include"))
}
companion object {
private fun propertiesOf(vararg pairs: Pair<String, Any>): Properties =
Properties().also {