[Commonizer] Integrate commonizer to the Gradle plugin, p.1

Detect when it's really necessary to run commonizer. Resolve Kotlin/Native
platform dependencies. Add dependencies to the proper Gradle configurations.

Note: The most common source sets such as "commonMain" and "commonTest"
should not be used as Native intermediate source sets.
This commit is contained in:
Dmitriy Dolovov
2020-02-01 17:00:51 +07:00
parent 4ccff3f1b1
commit d7e82bf899
5 changed files with 412 additions and 101 deletions

View File

@@ -10,16 +10,12 @@
package org.jetbrains.kotlin.gradle.plugin.mpp
import org.gradle.api.Project
import org.gradle.api.artifacts.Dependency
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeHostTestRun
import org.jetbrains.kotlin.gradle.targets.native.KotlinNativeSimulatorTestRun
import org.jetbrains.kotlin.gradle.targets.native.internal.setUpKotlinNativePlatformDependencies
import org.jetbrains.kotlin.gradle.utils.NativeCompilerDownloader
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.konan.target.KonanTarget
@@ -54,27 +50,6 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
}
}
private fun nativeLibrariesList(directory: String) = with(project) {
file("$konanHome/klib/$directory")
.listFiles { file -> file.isDirectory }
?.sortedBy { dir -> dir.name.toLowerCase() }
}
// We declare default K/N dependencies (default and platform libraries) as files to avoid searching them in remote repos (see KT-28128).
private fun defaultLibs(stdlibOnly: Boolean = false): List<Dependency> = with(project) {
var filesList = nativeLibrariesList("common")
if (stdlibOnly) {
filesList = filesList?.filter { dir -> dir.name == "stdlib" }
}
filesList?.map { dir -> dependencies.create(files(dir)) } ?: emptyList()
}
private fun platformLibs(target: KonanTarget): List<Dependency> = with(project) {
val filesList = nativeLibrariesList("platform/${target.name}")
filesList?.map { dir -> dependencies.create(files(dir)) } ?: emptyList()
}
protected abstract fun createTargetConfigurator(): KotlinTargetConfigurator<T>
protected abstract fun instantiateTarget(name: String): T
@@ -93,7 +68,9 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
createTargetConfigurator().configureTarget(result)
addDependenciesOnLibrariesFromDistribution(result)
project.gradle.taskGraph.whenReady {
project.rootProject.setUpKotlinNativePlatformDependencies()
}
if (!konanTarget.enabledOnCurrentHost) {
with(HostManager()) {
@@ -105,69 +82,8 @@ abstract class AbstractKotlinNativeTargetPreset<T : KotlinNativeTarget>(
return result
}
// Allow IDE to resolve the libraries provided by the compiler by adding them into dependencies.
private fun addDependenciesOnLibrariesFromDistribution(result: T) {
result.compilations.all { compilation ->
val target = compilation.konanTarget
project.whenEvaluated {
// First, put common libs:
defaultLibs(!compilation.enableEndorsedLibs).forEach {
project.dependencies.add(compilation.compileDependencyConfigurationName, it)
}
// Then, platform-specific libs:
platformLibs(target).forEach {
project.dependencies.add(compilation.compileDependencyConfigurationName, it)
}
}
}
// Add dependencies to stdlib-native for intermediate single-backend source-sets (like 'allNative')
project.whenEvaluated {
val compilationsBySourceSets = CompilationSourceSetUtil.compilationsBySourceSets(this)
fun KotlinSourceSet.isIntermediateNativeSourceSet(): Boolean {
val compilations = compilationsBySourceSets[this] ?: return false
if (compilations.all { it.defaultSourceSet == this })
return false
return compilations.all { it.target.platformType == KotlinPlatformType.native }
}
val stdlib = defaultLibs(stdlibOnly = true).singleOrNull() ?: run {
warnAboutMissingNativeStdlib(project)
return@whenEvaluated
}
project.kotlinExtension.sourceSets
.filter { it.isIntermediateNativeSourceSet() }
.forEach {
project.dependencies.add(it.implementationMetadataConfigurationName, stdlib)
}
}
}
companion object {
private const val KOTLIN_NATIVE_HOME_PRIVATE_PROPERTY = "konanHome"
private fun warnAboutMissingNativeStdlib(project: Project) {
if (!project.hasProperty("kotlin.native.nostdlib")) {
SingleWarningPerBuild.show(
project,
buildString {
append(NO_NATIVE_STDLIB_WARNING)
if (PropertiesProvider(project).nativeHome != null)
append(NO_NATIVE_STDLIB_PROPERTY_WARNING)
}
)
}
}
internal const val NO_NATIVE_STDLIB_WARNING =
"The Kotlin/Native distribution used in this build does not provide the standard library. "
internal const val NO_NATIVE_STDLIB_PROPERTY_WARNING =
"Make sure that the '${PropertiesProvider.KOTLIN_NATIVE_HOME}' property points to a valid Kotlin/Native distribution."
}
}

View File

@@ -0,0 +1,127 @@
/*
* Copyright 2010-2020 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.gradle.targets.native.internal
import org.jetbrains.kotlin.konan.library.KONAN_DISTRIBUTION_KLIB_DIR
import org.jetbrains.kotlin.konan.target.KonanTarget
import java.io.File
import java.io.IOException
import java.nio.charset.StandardCharsets
import java.nio.file.AtomicMoveNotSupportedException
import java.nio.file.Files
import java.nio.file.StandardCopyOption
import java.util.*
internal fun runCommonizerInBulk(
distributionDir: File,
baseDestinationDir: File,
targetGroups: List<Set<KonanTarget>>,
kotlinVersion: String
): List<File> {
val commandLineParameters = mutableListOf<String>()
val postActions = mutableListOf<() -> Unit>()
val result = targetGroups.map { targets ->
if (targets.size == 1) {
// no need to commonize, just use the libraries from the distribution
distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
} else {
// naive up-to-date check:
// "X.Y.Z-SNAPSHOT" is not enough to uniquely identify the concrete version of Kotlin plugin,
// therefore lets assume that it's always not up to date
val definitelyNotUpToDate = kotlinVersion.endsWith("SNAPSHOT", ignoreCase = true)
// need stable order of targets for consistency
val orderedTargets = targets.sortedBy { it.name }
val discriminator = buildString {
orderedTargets.joinTo(this, separator = "-")
append("-")
append(kotlinVersion.toLowerCase().base64)
}
val destinationDir = baseDestinationDir.resolve(discriminator)
if (definitelyNotUpToDate || !destinationDir.isDirectory) {
val parentDir = destinationDir.parentFile
parentDir.mkdirs()
val destinationTmpDir = createTempDir(
prefix = "tmp-" + destinationDir.name,
suffix = ".new",
directory = parentDir
)
commandLineParameters += "native-dist-commonize"
commandLineParameters += "-distribution-path"
commandLineParameters += distributionDir.toString()
commandLineParameters += "-output-path"
commandLineParameters += destinationTmpDir.toString()
commandLineParameters += "-targets"
commandLineParameters += orderedTargets.joinToString(separator = ",")
postActions.add { renameDirectory(destinationTmpDir, destinationDir) }
}
destinationDir
}
}
callCommonizerCLI(commandLineParameters)
postActions.forEach { it() }
return result
}
private fun callCommonizerCLI(commandLineParameters: List<String>) {
if (commandLineParameters.isEmpty()) return
// TODO: implement
}
private fun renameDirectory(source: File, destination: File) {
val sourcePath = source.toPath()
val destinationPath = destination.toPath()
val suppressedExceptions = mutableListOf<IOException>()
for (it in 0 until 3) {
try {
safeDelete(destination)
Files.move(sourcePath, destinationPath, StandardCopyOption.ATOMIC_MOVE)
return
} catch (e: IOException) {
suppressedExceptions += e
if (e is AtomicMoveNotSupportedException) {
// new attempts have no more sense
break
}
}
}
throw IllegalStateException("Failed to rename $source to $destination").apply { suppressedExceptions.forEach(::addSuppressed) }
}
private fun safeDelete(directory: File) {
if (!directory.exists()) return
// first, rename directory to some temp directory
val tempDir = createTempFile(
prefix = "tmp-" + directory.name,
suffix = ".old",
directory = directory.parentFile
)
tempDir.delete()
Files.move(directory.toPath(), tempDir.toPath(), StandardCopyOption.ATOMIC_MOVE)
// only then delete it recursively
tempDir.deleteRecursively()
}
private val String.base64
get() = Base64.getEncoder().encodeToString(toByteArray(StandardCharsets.UTF_8))

View File

@@ -0,0 +1,268 @@
/*
* Copyright 2010-2020 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.gradle.targets.native.internal
import org.gradle.api.Project
import org.jetbrains.kotlin.compilerRunner.konanHome
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtensionOrNull
import org.jetbrains.kotlin.gradle.internal.isInIdeaSync
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.KOTLIN_NATIVE_HOME
import org.jetbrains.kotlin.gradle.plugin.compareVersionNumbers
import org.jetbrains.kotlin.gradle.plugin.getKotlinPluginVersion
import org.jetbrains.kotlin.gradle.plugin.mpp.CompilationSourceSetUtil
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled
import org.jetbrains.kotlin.gradle.targets.native.internal.NativePlatformDependency.*
import org.jetbrains.kotlin.gradle.utils.SingleWarningPerBuild
import org.jetbrains.kotlin.konan.library.*
import org.jetbrains.kotlin.konan.target.KonanTarget
import org.jetbrains.kotlin.utils.addToStdlib.flattenTo
import java.io.File
internal fun Project.setUpKotlinNativePlatformDependencies() {
if (multiplatformExtensionOrNull == null) {
// not a multiplatform project, nothing to set up
return
}
val kotlinVersion = getKotlinPluginVersion()!!
// run commonizer only for 1.4+, only for HMPP projects and only on IDE sync
val allowCommonizer = compareVersionNumbers(kotlinVersion, "1.4") >= 0
&& isKotlinGranularMetadataEnabled
&& isInIdeaSync
val dependencyResolver = NativePlatformDependencyResolver(this, kotlinVersion)
findSourceSetsToAddDependencies(allowCommonizer).forEach { (sourceSet: KotlinSourceSet, sourceSetDeps: Set<NativePlatformDependency>) ->
sourceSetDeps.forEach { sourceSetDep: NativePlatformDependency ->
dependencyResolver.addForResolve(sourceSetDep) { resolvedFiles: Set<File> ->
resolvedFiles.forEach { resolvedFile ->
dependencies.add(sourceSet.implementationMetadataConfigurationName, dependencies.create(files(resolvedFile)))
}
}
}
}
dependencyResolver.resolveAll()
}
private sealed class NativePlatformDependency {
/* Non-commonized target-neutral libraries taken directly from the Kotlin/Native distribution */
data class OutOfDistributionCommon(val includeEndorsedLibs: Boolean) : NativePlatformDependency()
/* Non-commonized libraries for the specific target taken directly from the Kotlin/Native distribution */
data class OutOfDistributionPlatform(val target: KonanTarget) : NativePlatformDependency()
/* Commonized (common) libraries */
data class CommonizedCommon(val targets: Set<KonanTarget>) : NativePlatformDependency()
/* Commonized libraries for a specific target platform */
data class CommonizedPlatform(val target: KonanTarget, val common: CommonizedCommon) : NativePlatformDependency()
}
private class NativePlatformDependencyResolver(val project: Project, val kotlinVersion: String) {
private val distributionDir = File(project.konanHome)
private val distributionLibsDir = distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR)
private var alreadyResolved = false
private val dependencies = mutableMapOf<NativePlatformDependency, MutableList<(Set<File>) -> Unit>>()
fun addForResolve(dependency: NativePlatformDependency, whenResolved: (Set<File>) -> Unit) {
check(!alreadyResolved)
dependencies.computeIfAbsent(dependency) { mutableListOf() }.add(whenResolved)
}
fun resolveAll() {
check(!alreadyResolved)
alreadyResolved = true
// first, run commonization
val targetGroups: List<Pair<CommonizedCommon, Set<KonanTarget>>> = dependencies.keys.filterIsInstance<CommonizedCommon>()
.map { it to it.targets }
val commonizedLibsDirs: Map<CommonizedCommon, File> =
runCommonizerInBulk(
distributionDir = distributionDir,
baseDestinationDir = distributionDir.resolve(KONAN_DISTRIBUTION_KLIB_DIR).resolve(KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR),
targetGroups = targetGroups.map { it.second },
kotlinVersion = kotlinVersion
).mapIndexed { index: Int, commonizedLibsDir: File ->
targetGroups[index].first to commonizedLibsDir
}.toMap()
// then, resolve dependencies one by one
dependencies.forEach { (dependency, actions) ->
val libs = when (dependency) {
is OutOfDistributionCommon -> {
/* stdlib, endorsed libs */
var hasStdlib = false
val libs = libsInCommonDir(distributionLibsDir) { dir ->
val isStdlib = dir.endsWith(KONAN_STDLIB_NAME)
hasStdlib = hasStdlib || isStdlib
return@libsInCommonDir isStdlib || dependency.includeEndorsedLibs
}
if (!hasStdlib) warnAboutMissingNativeStdlib()
libs
}
is OutOfDistributionPlatform -> {
/* platform libs for a specific target */
libsInPlatformDir(distributionLibsDir, dependency.target)
}
is CommonizedCommon -> {
/* commonized platform libs with expect declarations */
val commonizedLibsDir = commonizedLibsDirs.getValue(dependency)
libsInCommonDir(commonizedLibsDir)
}
is CommonizedPlatform -> {
/* commonized platform libs with actual declarations */
val commonizedLibsDir = commonizedLibsDirs.getValue(dependency.common)
libsInPlatformDir(commonizedLibsDir, dependency.target)
}
}
actions.forEach { it(libs) }
}
}
private fun warnAboutMissingNativeStdlib() {
if (!project.hasProperty("kotlin.native.nostdlib")) {
SingleWarningPerBuild.show(
project,
buildString {
append(NO_NATIVE_STDLIB_WARNING)
if (PropertiesProvider(project).nativeHome != null)
append(NO_NATIVE_STDLIB_PROPERTY_WARNING)
}
)
}
}
companion object {
private fun libsInCommonDir(basePath: File, predicate: (File) -> Boolean = { true }) =
basePath.resolve(KONAN_DISTRIBUTION_COMMON_LIBS_DIR).listFiles()?.filter { predicate(it) }?.toSet() ?: emptySet()
private fun libsInPlatformDir(basePath: File, target: KonanTarget) =
basePath.resolve(KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR).resolve(target.name).listFiles()?.toSet() ?: emptySet()
}
}
private fun Project.findSourceSetsToAddDependencies(allowCommonizer: Boolean): Map<KotlinSourceSet, Set<NativePlatformDependency>> {
val sourceSetsToAddDeps = mutableMapOf<KotlinSourceSet, Set<NativePlatformDependency>>()
if (allowCommonizer) {
sourceSetsToAddDeps += findSourceSetsToAddCommonizedPlatformDependencies()
}
val compilationsBySourceSets = CompilationSourceSetUtil.compilationsBySourceSets(this)
val nativeCompilations = compilationsBySourceSets.values.flattenTo(mutableSetOf()).filterIsInstance<KotlinNativeCompilation>()
nativeCompilations.associate { it.defaultSourceSet to NativeSourceSetDetails(it.konanTarget, it.enableEndorsedLibs) }
.forEach { (defaultSourceSet, details) ->
if (defaultSourceSet !in sourceSetsToAddDeps) {
sourceSetsToAddDeps[defaultSourceSet] = setOf(
OutOfDistributionCommon(details.includeEndorsedLibs),
OutOfDistributionPlatform(details.target)
)
}
}
return sourceSetsToAddDeps
}
private fun Project.findSourceSetsToAddCommonizedPlatformDependencies(): Map<KotlinSourceSet, Set<NativePlatformDependency>> {
val sourceSetsToAddDeps = mutableMapOf<KotlinSourceSet, Set<NativePlatformDependency>>()
val compilationsBySourceSets = CompilationSourceSetUtil.compilationsBySourceSets(this)
val nativeCompilations = compilationsBySourceSets.values.flattenTo(mutableSetOf()).filterIsInstance<KotlinNativeCompilation>()
nativeCompilations.forEach { nativeCompilation ->
// consider source sets in compilation only one step above the default source set
// TODO: reconsider this restriction
val commonSourceSetCandidates = nativeCompilation.defaultSourceSet.dependsOn - nativeCompilation.defaultSourceSet
commonSourceSetCandidates.forEach sourceSet@{ sourceSet ->
if (sourceSet.name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME
|| sourceSet.name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME
) {
// exclude the most common source sets
return@sourceSet
}
if (sourceSet in sourceSetsToAddDeps) {
// already processed
return@sourceSet
}
val leafSourceSets = mutableMapOf<KotlinSourceSet, NativeSourceSetDetails>()
for (compilation in compilationsBySourceSets.getValue(sourceSet)) {
if (compilation !is KotlinNativeCompilation) {
// the source set participates in non-native compilation
return@sourceSet
}
val defaultSourceSet = compilation.defaultSourceSet
if (defaultSourceSet == sourceSet) {
// there is a compilation where the source set is the default source set
return@sourceSet
}
leafSourceSets[defaultSourceSet] = NativeSourceSetDetails(
target = compilation.konanTarget,
includeEndorsedLibs = compilation.enableEndorsedLibs
)
}
val allTargets = leafSourceSets.values.mapTo(mutableSetOf()) { it.target }
if (allTargets.isEmpty())
return@sourceSet
val commonizedCommonDep = CommonizedCommon(allTargets)
val includeEndorsedLibsToCommonSourceSet = leafSourceSets.values.all { it.includeEndorsedLibs }
sourceSetsToAddDeps[sourceSet] = setOf(
OutOfDistributionCommon(includeEndorsedLibsToCommonSourceSet),
commonizedCommonDep
)
leafSourceSets.forEach { (leafSourceSet, details) ->
val existingDep = sourceSetsToAddDeps[leafSourceSet]
if (existingDep == null) {
val commonizedPlatformDep = CommonizedPlatform(details.target, commonizedCommonDep)
sourceSetsToAddDeps[leafSourceSet] = setOf(
OutOfDistributionCommon(details.includeEndorsedLibs),
commonizedPlatformDep
)
} /*else if (existingDep != leafDep) {
// actually, no action required
}*/
}
}
}
return sourceSetsToAddDeps
}
private class NativeSourceSetDetails(
val target: KonanTarget,
val includeEndorsedLibs: Boolean
)
internal const val NO_NATIVE_STDLIB_WARNING =
"The Kotlin/Native distribution used in this build does not provide the standard library. "
internal const val NO_NATIVE_STDLIB_PROPERTY_WARNING =
"Make sure that the '$KOTLIN_NATIVE_HOME' property points to a valid Kotlin/Native distribution."

View File

@@ -5,28 +5,27 @@
package org.jetbrains.kotlin.gradle.internals
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeTargetPreset.Companion.NO_NATIVE_STDLIB_PROPERTY_WARNING
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinNativeTargetPreset.Companion.NO_NATIVE_STDLIB_WARNING
import org.jetbrains.kotlin.gradle.plugin.KOTLIN_12X_MPP_DEPRECATION_WARNING
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companion.GRADLE_NO_METADATA_WARNING
import org.jetbrains.kotlin.gradle.targets.native.internal.NO_NATIVE_STDLIB_PROPERTY_WARNING
import org.jetbrains.kotlin.gradle.targets.native.internal.NO_NATIVE_STDLIB_WARNING
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinProjectStructureMetadata
import org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME
import org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromXml
import org.jetbrains.kotlin.gradle.targets.native.DisabledNativeTargetsReporter
import org.w3c.dom.Document
fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? =
org.jetbrains.kotlin.gradle.plugin.mpp.parseKotlinSourceSetMetadataFromXml(document)
fun parseKotlinSourceSetMetadataFromXml(document: Document): KotlinProjectStructureMetadata? = parseKotlinSourceSetMetadataFromXml(document)
const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME =
org.jetbrains.kotlin.gradle.plugin.mpp.MULTIPLATFORM_PROJECT_METADATA_FILE_NAME
const val MULTIPLATFORM_PROJECT_METADATA_FILE_NAME = MULTIPLATFORM_PROJECT_METADATA_FILE_NAME
const val GRADLE_NO_METADATA_WARNING =
org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.GRADLE_NO_METADATA_WARNING
const val GRADLE_NO_METADATA_WARNING = GRADLE_NO_METADATA_WARNING
const val DISABLED_NATIVE_TARGETS_REPORTER_DISABLE_WARNING_PROPERTY_NAME =
DisabledNativeTargetsReporter.DISABLE_WARNING_PROPERTY_NAME
const val DISABLED_NATIVE_TARGETS_REPORTER_DISABLE_WARNING_PROPERTY_NAME = DisabledNativeTargetsReporter.DISABLE_WARNING_PROPERTY_NAME
const val DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX: String =
DisabledNativeTargetsReporter.WARNING_PREFIX
const val DISABLED_NATIVE_TARGETS_REPORTER_WARNING_PREFIX: String = DisabledNativeTargetsReporter.WARNING_PREFIX
const val NO_NATIVE_STDLIB_WARNING = NO_NATIVE_STDLIB_WARNING
const val NO_NATIVE_STDLIB_PROPERTY_WARNING = NO_NATIVE_STDLIB_PROPERTY_WARNING
val KOTLIN_12X_MPP_DEPRECATION_WARNING = org.jetbrains.kotlin.gradle.plugin.KOTLIN_12X_MPP_DEPRECATION_WARNING
val KOTLIN_12X_MPP_DEPRECATION_WARNING = KOTLIN_12X_MPP_DEPRECATION_WARNING

View File

@@ -12,6 +12,7 @@ const val KONAN_STDLIB_NAME = "stdlib"
const val KONAN_DISTRIBUTION_KLIB_DIR = "klib"
const val KONAN_DISTRIBUTION_COMMON_LIBS_DIR = "common"
const val KONAN_DISTRIBUTION_PLATFORM_LIBS_DIR = "platform"
const val KONAN_DISTRIBUTION_COMMONIZED_LIBS_DIR = "commonized"
const val KONAN_DISTRIBUTION_SOURCES_DIR = "sources"