From de9053538698384f455d7e9bcf49ca5ce610b45c Mon Sep 17 00:00:00 2001 From: Svyatoslav Scherbina Date: Fri, 29 Mar 2019 14:12:29 +0300 Subject: [PATCH] Avoid using shared module cache in cinterop To improve compilation predictability --- .../native/interop/indexer/ModuleSupport.kt | 47 +++++++++++------ .../kotlin/native/interop/indexer/Utils.kt | 52 ++++++++++++------- 2 files changed, 63 insertions(+), 36 deletions(-) diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt index a848a5ea252..72e5eaca6bd 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/ModuleSupport.kt @@ -9,27 +9,42 @@ fun getModulesInfo(compilation: Compilation, modules: List): ModulesInfo if (modules.isEmpty()) return ModulesInfo(emptyList(), emptySet()) withIndex { index -> - - val ownHeaders = mutableSetOf() - val topLevelHeaders = linkedSetOf() - - getModulesASTFiles(index, compilation, modules).forEach { - val moduleTranslationUnit = clang_createTranslationUnit(index, it)!! - try { - val modulesHeaders = getModulesHeaders(index, moduleTranslationUnit, modules.toSet(), topLevelHeaders) - modulesHeaders.mapTo(ownHeaders) { it.canonicalPath } - } finally { - clang_disposeTranslationUnit(moduleTranslationUnit) - } + ModularCompilation(compilation).use { + val modulesASTFiles = getModulesASTFiles(index, it, modules) + return buildModulesInfo(index, modules, modulesASTFiles) } - - return ModulesInfo(topLevelHeaders.toList(), ownHeaders) } } -private fun getModulesASTFiles(index: CXIndex, compilation: Compilation, modules: List): List { +private fun buildModulesInfo(index: CXIndex, modules: List, modulesASTFiles: List): ModulesInfo { + val ownHeaders = mutableSetOf() + val topLevelHeaders = linkedSetOf() + modulesASTFiles.forEach { + val moduleTranslationUnit = clang_createTranslationUnit(index, it)!! + try { + val modulesHeaders = getModulesHeaders(index, moduleTranslationUnit, modules.toSet(), topLevelHeaders) + modulesHeaders.mapTo(ownHeaders) { it.canonicalPath } + } finally { + clang_disposeTranslationUnit(moduleTranslationUnit) + } + } + + return ModulesInfo(topLevelHeaders.toList(), ownHeaders) +} + +internal open class ModularCompilation(compilation: Compilation): Compilation by compilation, Disposable { + private val moduleCacheDirectory = createTempDir("ModuleCache") + + override val compilerArgs = compilation.compilerArgs + + listOf("-fmodules", "-fmodules-cache-path=${moduleCacheDirectory.absolutePath}") + + override fun dispose() { + moduleCacheDirectory.deleteRecursively() + } +} + +private fun getModulesASTFiles(index: CXIndex, compilation: ModularCompilation, modules: List): List { val compilationWithImports = object : Compilation by compilation { - override val compilerArgs = compilation.compilerArgs + "-fmodules" override val additionalPreambleLines = modules.map { "@import $it;" } + compilation.additionalPreambleLines } diff --git a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt index 3ffeca05923..2b08f399cdd 100644 --- a/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt +++ b/Interop/Indexer/src/main/kotlin/org/jetbrains/kotlin/native/interop/indexer/Utils.kt @@ -428,34 +428,36 @@ internal class ModulesMap( val translationUnit: CXTranslationUnit ) : Closeable { + private val modularCompilation: ModularCompilation private val index: CXIndex private val translationUnitWithModules: CXTranslationUnit - init { - index = clang_createIndex(0, 0)!! - try { - translationUnitWithModules = object : Compilation by compilation { - override val compilerArgs = compilation.compilerArgs + "-fmodules" - }.parse(index) + private val arena = Arena() - try { - translationUnitWithModules.ensureNoCompileErrors() - } catch (e: Throwable) { - clang_disposeTranslationUnit(translationUnitWithModules) - throw e - } - - } catch (e: Throwable) { - clang_disposeIndex(index) - throw e - } + private inline fun T.toBeDisposedWith(crossinline block: (T) -> Unit): T = apply { + arena.defer { block(this) } } override fun close() { + arena.clear() + } + + init { try { - clang_disposeTranslationUnit(translationUnitWithModules) - } finally { - clang_disposeIndex(index) + modularCompilation = ModularCompilation(compilation) + .toBeDisposedWith { it.dispose() } + + index = clang_createIndex(0, 0)!! + .toBeDisposedWith { clang_disposeIndex(it) } + + translationUnitWithModules = modularCompilation.parse(index) + .toBeDisposedWith { clang_disposeTranslationUnit(it) } + + translationUnitWithModules.ensureNoCompileErrors() + + } catch (e: Throwable) { + this.close() + throw e } } @@ -726,3 +728,13 @@ fun Type.canonicalIsPointerToChar(): Boolean { val unwrappedType = this.unwrapTypedefs() return unwrappedType is PointerType && unwrappedType.pointeeType.unwrapTypedefs() == CharType } + +internal interface Disposable { + fun dispose() +} + +internal inline fun T.use(block: (T) -> R): R = try { + block(this) +} finally { + this.dispose() +}