diff --git a/compiler/util-io/src/org/jetbrains/kotlin/konan/properties/Properties.kt b/compiler/util-io/src/org/jetbrains/kotlin/konan/properties/Properties.kt index f8a88cfe804..c4924226a69 100644 --- a/compiler/util-io/src/org/jetbrains/kotlin/konan/properties/Properties.kt +++ b/compiler/util-io/src/org/jetbrains/kotlin/konan/properties/Properties.kt @@ -69,3 +69,51 @@ fun Properties.keepOnlyDefaultProfiles() { // TODO: it actually affects only resolution made in :dependencies, // that's why we assume that 'default' profile comes first (and check this above). } + + +/** + * Wraps [propertyList] with resolving mechanism. See [String.resolveValue]. + */ +fun Properties.resolvablePropertyList( + key: String, suffix: String? = null, escapeInQuotes: Boolean = false, + visitedProperties: MutableSet = mutableSetOf() +): List = propertyList(key, suffix, escapeInQuotes).flatMap { + // We need to create a copy of a visitedProperties to avoid collisions + // between different elements of the list. + it.resolveValue(this, visitedProperties.toMutableSet()) +} + +/** + * Wraps [propertyString] with resolving mechanism. See [String.resolveValue]. + */ +fun Properties.resolvablePropertyString( + key: String, suffix: String? = null, + visitedProperties: MutableSet = mutableSetOf() +): String? = propertyString(key, suffix) + ?.split(' ') + ?.flatMap { it.resolveValue(this, visitedProperties) } + ?.joinToString(" ") + +/** + * Adds trivial symbol resolving mechanism to properties files. + * + * Given the following properties file: + * + * key0 = value1 value2 + * key1 = value3 $key0 + * key2 = $key1 + * + * "$key1".resolveValue(properties) will return List("value3", "value1", "value2") + */ +private fun String.resolveValue(properties: Properties, visitedProperties: MutableSet = mutableSetOf()): List = + when { + startsWith("$") -> { + val property = this.substringAfter('$') + // Keep track of visited properties to avoid running in circles. + if (!visitedProperties.add(property)) { + error("Circular dependency: ${visitedProperties.joinToString()}") + } + properties.resolvablePropertyList(property, visitedProperties = visitedProperties) + } + else -> listOf(this) + } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt index c6f56b999bf..27328d5d5eb 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/compilerRunner/nativeToolRunners.kt @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.mpp.isAtLeast import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader import org.jetbrains.kotlin.konan.CompilerVersion +import org.jetbrains.kotlin.konan.properties.resolvablePropertyString import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.util.DependencyDirectories @@ -104,7 +105,7 @@ internal abstract class AbstractKotlinNativeCInteropRunner(toolName: String, pro project.file("${project.konanHome}/konan/konan.properties").inputStream().use(::load) } - konanProperties.getProperty("llvmHome.mingw_x64")?.let { toolchainDir -> + konanProperties.resolvablePropertyString("llvmHome.mingw_x64")?.let { toolchainDir -> DependencyDirectories.defaultDependenciesRoot .resolve("$toolchainDir/bin") .absolutePath diff --git a/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt b/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt index 2c22e4c53a0..a5be1693e31 100644 --- a/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt +++ b/native/utils/src/org/jetbrains/kotlin/konan/target/Distribution.kt @@ -43,6 +43,10 @@ class Distribution( fun additionalPropertyFiles(genericName: String) = preconfiguredPropertyFiles(genericName) + userPropertyFiles(genericName) + /** + * Please note that konan.properties uses simple resolving mechanism. + * See [org.jetbrains.kotlin.konan.properties.resolveValue]. + */ val properties by lazy { val result = Properties()