Avoid reparsing C headers in cinterop whenever possible (#3082)
Thus optimize it.
This commit is contained in:
committed by
GitHub
parent
ba19ead041
commit
ab29d5e073
+13
-6
@@ -947,18 +947,23 @@ internal class NativeIndexImpl(val library: NativeLibrary, val verbose: Boolean
|
||||
|
||||
}
|
||||
|
||||
fun buildNativeIndexImpl(library: NativeLibrary, verbose: Boolean): NativeIndex {
|
||||
fun buildNativeIndexImpl(library: NativeLibrary, verbose: Boolean): IndexerResult {
|
||||
val result = NativeIndexImpl(library, verbose)
|
||||
indexDeclarations(result)
|
||||
return result
|
||||
val compilation = indexDeclarations(result)
|
||||
return IndexerResult(result, compilation)
|
||||
}
|
||||
|
||||
private fun indexDeclarations(nativeIndex: NativeIndexImpl) {
|
||||
private fun indexDeclarations(nativeIndex: NativeIndexImpl): CompilationWithPCH {
|
||||
withIndex { index ->
|
||||
val translationUnit = nativeIndex.library.parse(index, options = CXTranslationUnit_DetailedPreprocessingRecord)
|
||||
val translationUnit = nativeIndex.library.parse(
|
||||
index,
|
||||
options = CXTranslationUnit_DetailedPreprocessingRecord or CXTranslationUnit_ForSerialization
|
||||
)
|
||||
try {
|
||||
translationUnit.ensureNoCompileErrors()
|
||||
|
||||
val compilation = nativeIndex.library.withPrecompiledHeader(translationUnit)
|
||||
|
||||
val headers = getFilteredHeaders(nativeIndex, index, translationUnit)
|
||||
|
||||
nativeIndex.includedHeaders = headers.map {
|
||||
@@ -991,7 +996,9 @@ private fun indexDeclarations(nativeIndex: NativeIndexImpl) {
|
||||
CXChildVisitResult.CXChildVisit_Continue
|
||||
}
|
||||
|
||||
findMacros(nativeIndex, translationUnit, headers)
|
||||
findMacros(nativeIndex, compilation, translationUnit, headers)
|
||||
|
||||
return compilation
|
||||
} finally {
|
||||
clang_disposeTranslationUnit(translationUnit)
|
||||
}
|
||||
|
||||
+13
-10
@@ -23,10 +23,15 @@ import java.io.File
|
||||
/**
|
||||
* Finds all "macro constants" and registers them as [NativeIndex.constants] in given index.
|
||||
*/
|
||||
internal fun findMacros(nativeIndex: NativeIndexImpl, translationUnit: CXTranslationUnit, headers: Set<CXFile?>) {
|
||||
internal fun findMacros(
|
||||
nativeIndex: NativeIndexImpl,
|
||||
compilation: CompilationWithPCH,
|
||||
translationUnit: CXTranslationUnit,
|
||||
headers: Set<CXFile?>
|
||||
) {
|
||||
val names = collectMacroNames(nativeIndex, translationUnit, headers)
|
||||
// TODO: apply user-defined filters.
|
||||
val macros = expandMacros(nativeIndex.library, names, typeConverter = { nativeIndex.convertType(it) })
|
||||
val macros = expandMacros(compilation, names, typeConverter = { nativeIndex.convertType(it) })
|
||||
|
||||
macros.filterIsInstanceTo(nativeIndex.macroConstants)
|
||||
macros.filterIsInstanceTo(nativeIndex.wrappedMacros)
|
||||
@@ -38,18 +43,16 @@ private typealias TypeConverter = (CValue<CXType>) -> Type
|
||||
* For each name expands the macro with this name declared in the library,
|
||||
* checking if it gets expanded to a constant expression.
|
||||
*
|
||||
* Note: in the worst case this method parses the code against the library a lot of times,
|
||||
* so it requires library headers precompiled to significantly speed up the parsing and avoid visiting headers' AST.
|
||||
*
|
||||
* @return the list of constants.
|
||||
*/
|
||||
private fun expandMacros(
|
||||
originalLibrary: NativeLibrary,
|
||||
library: CompilationWithPCH,
|
||||
names: List<String>,
|
||||
typeConverter: TypeConverter
|
||||
): List<MacroDef> {
|
||||
|
||||
// In the worst case code is parsed against the library a lot of times;
|
||||
// so precompile library headers to significantly speed up the parsing and avoid visiting headers' AST:
|
||||
val library = originalLibrary.precompileHeaders()
|
||||
|
||||
withIndex(excludeDeclarationsFromPCH = true) { index ->
|
||||
val sourceFile = library.createTempSource()
|
||||
val compilerArgs = library.compilerArgs.toMutableList()
|
||||
@@ -94,7 +97,7 @@ private fun expandMacros(
|
||||
* As a side effect, modifies the [sourceFile] and reparses the [translationUnit].
|
||||
*/
|
||||
private fun tryExpandMacros(
|
||||
library: NativeLibrary,
|
||||
library: CompilationWithPCH,
|
||||
translationUnit: CXTranslationUnit,
|
||||
sourceFile: File,
|
||||
names: List<String>,
|
||||
@@ -158,7 +161,7 @@ private const val CODE_SNIPPET_FUNCTION_NAME_PREFIX = "kni_indexer_function_"
|
||||
* generate a bridge for this macro.
|
||||
* - Otherwise the macro is skipped.
|
||||
*/
|
||||
private fun reparseWithCodeSnippets(library: NativeLibrary,
|
||||
private fun reparseWithCodeSnippets(library: CompilationWithPCH,
|
||||
translationUnit: CXTranslationUnit, sourceFile: File,
|
||||
names: List<String>) {
|
||||
|
||||
|
||||
+3
-3
@@ -53,9 +53,9 @@ internal open class ModularCompilation(compilation: Compilation): Compilation by
|
||||
}
|
||||
|
||||
private fun getModulesASTFiles(index: CXIndex, compilation: ModularCompilation, modules: List<String>): List<String> {
|
||||
val compilationWithImports = object : Compilation by compilation {
|
||||
override val additionalPreambleLines = modules.map { "@import $it;" } + compilation.additionalPreambleLines
|
||||
}
|
||||
val compilationWithImports = compilation.copy(
|
||||
additionalPreambleLines = modules.map { "@import $it;" } + compilation.additionalPreambleLines
|
||||
)
|
||||
|
||||
val result = linkedSetOf<String>()
|
||||
|
||||
|
||||
+19
-2
@@ -57,7 +57,22 @@ interface Compilation {
|
||||
val language: Language
|
||||
}
|
||||
|
||||
// TODO: consider replacing inheritance by composition and turning Compilation into final class.
|
||||
data class CompilationWithPCH(
|
||||
override val compilerArgs: List<String>,
|
||||
override val language: Language
|
||||
) : Compilation {
|
||||
|
||||
constructor(compilerArgs: List<String>, precompiledHeader: String, language: Language)
|
||||
: this(compilerArgs + listOf("-include-pch", precompiledHeader), language)
|
||||
|
||||
override val includes: List<String>
|
||||
get() = emptyList()
|
||||
|
||||
override val additionalPreambleLines: List<String>
|
||||
get() = emptyList()
|
||||
}
|
||||
|
||||
// TODO: Compilation hierarchy seems to require some refactoring.
|
||||
|
||||
data class NativeLibrary(override val includes: List<String>,
|
||||
override val additionalPreambleLines: List<String>,
|
||||
@@ -68,10 +83,12 @@ data class NativeLibrary(override val includes: List<String>,
|
||||
val headerExclusionPolicy: HeaderExclusionPolicy,
|
||||
val headerFilter: NativeLibraryHeaderFilter) : Compilation
|
||||
|
||||
data class IndexerResult(val index: NativeIndex, val compilation: CompilationWithPCH)
|
||||
|
||||
/**
|
||||
* Retrieves the definitions from given C header file using given compiler arguments (e.g. defines).
|
||||
*/
|
||||
fun buildNativeIndex(library: NativeLibrary, verbose: Boolean): NativeIndex = buildNativeIndexImpl(library, verbose)
|
||||
fun buildNativeIndex(library: NativeLibrary, verbose: Boolean): IndexerResult = buildNativeIndexImpl(library, verbose)
|
||||
|
||||
/**
|
||||
* This class describes the IR of definitions from C header file(s).
|
||||
|
||||
+35
-20
@@ -241,30 +241,46 @@ internal fun Compilation.createTempSource(): File {
|
||||
return result
|
||||
}
|
||||
|
||||
fun Compilation.copy(
|
||||
includes: List<String> = this.includes,
|
||||
additionalPreambleLines: List<String> = this.additionalPreambleLines,
|
||||
compilerArgs: List<String> = this.compilerArgs,
|
||||
language: Language = this.language
|
||||
): Compilation = CompilationImpl(
|
||||
includes = includes,
|
||||
additionalPreambleLines = additionalPreambleLines,
|
||||
compilerArgs = compilerArgs,
|
||||
language = language
|
||||
)
|
||||
|
||||
data class CompilationImpl(
|
||||
override val includes: List<String>,
|
||||
override val additionalPreambleLines: List<String>,
|
||||
override val compilerArgs: List<String>,
|
||||
override val language: Language
|
||||
) : Compilation
|
||||
|
||||
/**
|
||||
* Precompiles the headers of this library.
|
||||
*
|
||||
* @return the library which includes the precompiled header instead of original ones.
|
||||
*/
|
||||
internal fun NativeLibrary.precompileHeaders(): NativeLibrary {
|
||||
val precompiledHeader = createTempFile(suffix = ".pch").apply { this.deleteOnExit() }
|
||||
|
||||
withIndex { index ->
|
||||
val options = CXTranslationUnit_ForSerialization
|
||||
val translationUnit = this.parse(index, options)
|
||||
try {
|
||||
translationUnit.ensureNoCompileErrors()
|
||||
clang_saveTranslationUnit(translationUnit, precompiledHeader.absolutePath, 0)
|
||||
} finally {
|
||||
clang_disposeTranslationUnit(translationUnit)
|
||||
}
|
||||
fun Compilation.precompileHeaders(): CompilationWithPCH = withIndex { index ->
|
||||
val options = CXTranslationUnit_ForSerialization
|
||||
val translationUnit = this.parse(index, options)
|
||||
try {
|
||||
translationUnit.ensureNoCompileErrors()
|
||||
withPrecompiledHeader(translationUnit)
|
||||
} finally {
|
||||
clang_disposeTranslationUnit(translationUnit)
|
||||
}
|
||||
}
|
||||
|
||||
return this.copy(
|
||||
includes = emptyList(),
|
||||
additionalPreambleLines = emptyList(),
|
||||
compilerArgs = this.compilerArgs + listOf("-include-pch", precompiledHeader.absolutePath)
|
||||
)
|
||||
internal fun Compilation.withPrecompiledHeader(translationUnit: CXTranslationUnit): CompilationWithPCH {
|
||||
val precompiledHeader = createTempFile(suffix = ".pch").apply { this.deleteOnExit() }
|
||||
clang_saveTranslationUnit(translationUnit, precompiledHeader.absolutePath, 0)
|
||||
|
||||
return CompilationWithPCH(this.compilerArgs, precompiledHeader.absolutePath, this.language)
|
||||
}
|
||||
|
||||
internal fun NativeLibrary.includesDeclaration(cursor: CValue<CXCursor>): Boolean {
|
||||
@@ -289,10 +305,9 @@ internal fun CXTranslationUnit.getErrorLineNumbers(): Sequence<Int> =
|
||||
/**
|
||||
* For each list of lines, checks if the code fragment composed from these lines is compilable against given library.
|
||||
*/
|
||||
fun List<List<String>>.mapFragmentIsCompilable(originalLibrary: NativeLibrary): List<Boolean> {
|
||||
val library = originalLibrary
|
||||
fun List<List<String>>.mapFragmentIsCompilable(originalLibrary: CompilationWithPCH): List<Boolean> {
|
||||
val library: CompilationWithPCH = originalLibrary
|
||||
.copy(compilerArgs = originalLibrary.compilerArgs + "-ferror-limit=0")
|
||||
.precompileHeaders()
|
||||
|
||||
val indicesOfNonCompilable = mutableSetOf<Int>()
|
||||
|
||||
|
||||
+2
-2
@@ -17,15 +17,15 @@
|
||||
package org.jetbrains.kotlin.native.interop.gen
|
||||
|
||||
import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform
|
||||
import org.jetbrains.kotlin.native.interop.indexer.CompilationWithPCH
|
||||
import org.jetbrains.kotlin.native.interop.indexer.Language
|
||||
import org.jetbrains.kotlin.native.interop.indexer.NativeLibrary
|
||||
import org.jetbrains.kotlin.native.interop.indexer.mapFragmentIsCompilable
|
||||
|
||||
class SimpleBridgeGeneratorImpl(
|
||||
private val platform: KotlinPlatform,
|
||||
private val pkgName: String,
|
||||
private val jvmFileClassName: String,
|
||||
private val libraryForCStubs: NativeLibrary,
|
||||
private val libraryForCStubs: CompilationWithPCH,
|
||||
override val topLevelNativeScope: NativeScope,
|
||||
private val topLevelKotlinScope: KotlinScope
|
||||
) : SimpleBridgeGenerator {
|
||||
|
||||
+2
-2
@@ -17,13 +17,13 @@
|
||||
package org.jetbrains.kotlin.native.interop.gen.jvm
|
||||
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.jetbrains.kotlin.native.interop.indexer.NativeLibrary
|
||||
import org.jetbrains.kotlin.native.interop.indexer.CompilationWithPCH
|
||||
|
||||
/**
|
||||
* Describes the native library and the options for adjusting the Kotlin API to be generated for this library.
|
||||
*/
|
||||
class InteropConfiguration(
|
||||
val library: NativeLibrary,
|
||||
val library: CompilationWithPCH,
|
||||
val pkgName: String,
|
||||
val excludedFunctions: Set<String>,
|
||||
val excludedMacros: Set<String>,
|
||||
|
||||
+1
-1
@@ -965,7 +965,7 @@ class StubGenerator(
|
||||
Language.C -> emptyList()
|
||||
Language.OBJECTIVE_C -> listOf("void objc_terminate();")
|
||||
}
|
||||
)
|
||||
).precompileHeaders()
|
||||
|
||||
/**
|
||||
* Produces to [out] the contents of C source file to be compiled into native lib used for Kotlin bindings impl.
|
||||
|
||||
+9
-9
@@ -220,8 +220,10 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
|
||||
|
||||
val library = buildNativeLibrary(tool, def, argParser, imports)
|
||||
|
||||
val (nativeIndex, compilation) = buildNativeIndex(library, verbose)
|
||||
|
||||
val configuration = InteropConfiguration(
|
||||
library = library,
|
||||
library = compilation,
|
||||
pkgName = outKtPkg,
|
||||
excludedFunctions = excludedFunctions,
|
||||
excludedMacros = excludedMacros,
|
||||
@@ -233,8 +235,6 @@ private fun processCLib(args: Array<String>, additionalArgs: Map<String, Any> =
|
||||
target = tool.target
|
||||
)
|
||||
|
||||
val nativeIndex = buildNativeIndex(library, verbose)
|
||||
|
||||
val gen = StubGenerator(nativeIndex, configuration, libName, verbose, flavor, imports)
|
||||
|
||||
outKtFile.parentFile.mkdirs()
|
||||
@@ -330,12 +330,12 @@ internal fun buildNativeLibrary(
|
||||
})
|
||||
}
|
||||
|
||||
val compilation = object : Compilation {
|
||||
override val includes = headerFiles
|
||||
override val additionalPreambleLines = def.defHeaderLines
|
||||
override val compilerArgs = compilerOpts + tool.platformCompilerOpts
|
||||
override val language = language
|
||||
}
|
||||
val compilation = CompilationImpl(
|
||||
includes = headerFiles,
|
||||
additionalPreambleLines = def.defHeaderLines,
|
||||
compilerArgs = compilerOpts + tool.platformCompilerOpts,
|
||||
language = language
|
||||
)
|
||||
|
||||
val headerFilter: NativeLibraryHeaderFilter
|
||||
val includes: List<String>
|
||||
|
||||
Reference in New Issue
Block a user