Avoid using shared module cache in cinterop

To improve compilation predictability
This commit is contained in:
Svyatoslav Scherbina
2019-03-29 14:12:29 +03:00
committed by SvyatoslavScherbina
parent 8a1d8a29b1
commit de90535386
2 changed files with 63 additions and 36 deletions
@@ -9,27 +9,42 @@ fun getModulesInfo(compilation: Compilation, modules: List<String>): ModulesInfo
if (modules.isEmpty()) return ModulesInfo(emptyList(), emptySet())
withIndex { index ->
val ownHeaders = mutableSetOf<String>()
val topLevelHeaders = linkedSetOf<String>()
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<String>): List<String> {
private fun buildModulesInfo(index: CXIndex, modules: List<String>, modulesASTFiles: List<String>): ModulesInfo {
val ownHeaders = mutableSetOf<String>()
val topLevelHeaders = linkedSetOf<String>()
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<String>): List<String> {
val compilationWithImports = object : Compilation by compilation {
override val compilerArgs = compilation.compilerArgs + "-fmodules"
override val additionalPreambleLines = modules.map { "@import $it;" } + compilation.additionalPreambleLines
}
@@ -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> 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 : Disposable, R> T.use(block: (T) -> R): R = try {
block(this)
} finally {
this.dispose()
}