diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/defFileDependencies.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/defFileDependencies.kt index 1b10a99565a..8fe749e2f8b 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/defFileDependencies.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/defFileDependencies.kt @@ -11,7 +11,7 @@ import java.io.File import java.util.stream.Collectors import kotlin.streams.toList -fun defFileDependencies(args: Array) { +fun defFileDependencies(args: Array, runFromDaemon: Boolean) { val defFiles = mutableListOf() val targets = mutableListOf() @@ -32,14 +32,14 @@ fun defFileDependencies(args: Array) { } } - defFileDependencies(makeDependencyAssigner(targets, defFiles)) + defFileDependencies(makeDependencyAssigner(targets, defFiles, runFromDaemon)) } -private fun makeDependencyAssigner(targets: List, defFiles: List) = - CompositeDependencyAssigner(targets.map { makeDependencyAssignerForTarget(it, defFiles) }) +private fun makeDependencyAssigner(targets: List, defFiles: List, runFromDaemon: Boolean) = + CompositeDependencyAssigner(targets.map { makeDependencyAssignerForTarget(it, defFiles, runFromDaemon) }) -private fun makeDependencyAssignerForTarget(target: String, defFiles: List): SingleTargetDependencyAssigner { - val tool = prepareTool(target, KotlinPlatform.NATIVE) +private fun makeDependencyAssignerForTarget(target: String, defFiles: List, runFromDaemon: Boolean): SingleTargetDependencyAssigner { + val tool = prepareTool(target, KotlinPlatform.NATIVE, runFromDaemon) val cinteropArguments = CInteropArguments() cinteropArguments.argParser.parse(arrayOf()) val libraries = defFiles.parallelStream().map { diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/ToolConfig.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/ToolConfig.kt index 7520cad2c04..46e4b592487 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/ToolConfig.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/ToolConfig.kt @@ -18,44 +18,28 @@ package org.jetbrains.kotlin.native.interop.tool import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.konan.util.KonanHomeProvider -import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions +import org.jetbrains.kotlin.konan.target.AbstractToolConfig import org.jetbrains.kotlin.native.interop.gen.jvm.KotlinPlatform import org.jetbrains.kotlin.native.interop.indexer.Language -class ToolConfig(userProvidedTargetName: String?, private val flavor: KotlinPlatform, private val propertyOverrides: Map) { - - private val konanHome = KonanHomeProvider.determineKonanHome() - private val distribution = Distribution(konanHome, propertyOverrides = propertyOverrides) - private val platformManager = PlatformManager(distribution) - private val targetManager = platformManager.targetManager(userProvidedTargetName) - private val host = HostManager.host - val target = targetManager.target - - private val platform = platformManager.platform(target) +class ToolConfig(userProvidedTargetName: String?, flavor: KotlinPlatform, propertyOverrides: Map) + : AbstractToolConfig(KonanHomeProvider.determineKonanHome(), userProvidedTargetName, propertyOverrides) { val clang = when (flavor) { KotlinPlatform.JVM -> platform.clangForJni KotlinPlatform.NATIVE -> platform.clang } - val substitutions = defaultTargetSubstitutions(target) - - fun downloadDependencies() = platform.downloadDependencies() - fun getDefaultCompilerOptsForLanguage(language: Language): List = when (language) { Language.C, Language.OBJECTIVE_C -> clang.libclangArgs.toList() Language.CPP -> clang.libclangXXArgs.toList() } - val platformCompilerOpts = if (clang is ClangArgs.Jni) - clang.hostCompilerArgsForJni.toList() else emptyList() + val platformCompilerOpts = + if (clang is ClangArgs.Jni) + clang.hostCompilerArgsForJni.toList() + else emptyList() - val llvmHome = platform.absoluteLlvmHome - val sysRoot = platform.absoluteTargetSysRoot - - val libclang = when (host) { - KonanTarget.MINGW_X64 -> "$llvmHome/bin/libclang.dll" - else -> "$llvmHome/lib/${System.mapLibraryName("clang")}" - } + override fun loadLibclang() { System.load(libclang) } } diff --git a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt index 4d54e78df39..5f1f2b931da 100644 --- a/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt +++ b/kotlin-native/Interop/StubGenerator/src/main/kotlin/org/jetbrains/kotlin/native/interop/gen/jvm/main.kt @@ -65,18 +65,19 @@ fun main(args: Array) { val arguments = FullCInteropArguments() arguments.argParser.parse(args) val flavorName = arguments.flavor - processCLibSafe(flavorName, arguments, InternalInteropOptions(arguments.generated, arguments.natives)) + processCLibSafe(flavorName, arguments, InternalInteropOptions(arguments.generated, arguments.natives), runFromDaemon = false) } fun interop( flavor: String, args: Array, - additionalArgs: InternalInteropOptions + additionalArgs: InternalInteropOptions, + runFromDaemon: Boolean ): Array? = when (flavor) { "jvm", "native" -> { val cinteropArguments = CInteropArguments() cinteropArguments.argParser.parse(args) val platform = KotlinPlatform.values().single { it.name.equals(flavor, ignoreCase = true) } - processCLibSafe(platform, cinteropArguments, additionalArgs) + processCLibSafe(platform, cinteropArguments, additionalArgs, runFromDaemon) } "wasm" -> processIdlLib(args, additionalArgs) else -> error("Unexpected flavor") @@ -207,15 +208,15 @@ private fun findFilesByGlobs(roots: List, globs: List): Map? { + additionalArgs: InternalInteropOptions, runFromDaemon: Boolean): Array? { val ktGenRoot = additionalArgs.generated val nativeLibsDir = additionalArgs.natives val defFile = cinteropArguments.def?.let { File(it) } @@ -225,7 +226,7 @@ private fun processCLib(flavor: KotlinPlatform, cinteropArguments: CInteropArgum cinteropArguments.argParser.printError("-def or -pkg should be provided!") } - val tool = prepareTool(cinteropArguments.target, flavor, parseKeyValuePairs(cinteropArguments.overrideKonanProperties)) + val tool = prepareTool(cinteropArguments.target, flavor, runFromDaemon, parseKeyValuePairs(cinteropArguments.overrideKonanProperties)) val def = DefFile(defFile, tool.substitutions) val isLinkerOptsSetByUser = (cinteropArguments.linkerOpts.valueOrigin == ArgParser.ValueOrigin.SET_BY_USER) || @@ -469,14 +470,10 @@ private fun resolveDependencies( ).getFullList(TopologicalLibraryOrder) } -internal fun prepareTool(target: String?, flavor: KotlinPlatform, propertyOverrides: Map = emptyMap()): ToolConfig { - val tool = ToolConfig(target, flavor, propertyOverrides) - tool.downloadDependencies() - - System.load(tool.libclang) - - return tool -} +internal fun prepareTool(target: String?, flavor: KotlinPlatform, runFromDaemon: Boolean, propertyOverrides: Map = emptyMap()) = + ToolConfig(target, flavor, propertyOverrides).also { + if (!runFromDaemon) it.prepare() // Daemon prepares the tool himself. (See KonanToolRunner.kt) + } internal fun buildNativeLibrary( tool: ToolConfig, diff --git a/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/AbstractToolConfig.kt b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/AbstractToolConfig.kt new file mode 100644 index 00000000000..5c2c8fbb51d --- /dev/null +++ b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/AbstractToolConfig.kt @@ -0,0 +1,38 @@ +/* + * Copyright 2010-2021 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.konan.target + +import org.jetbrains.kotlin.konan.util.defaultTargetSubstitutions + +abstract class AbstractToolConfig(konanHome: String, userProvidedTargetName: String?, propertyOverrides: Map) { + private val distribution = Distribution(konanHome, propertyOverrides = propertyOverrides) + private val platformManager = PlatformManager(distribution) + private val targetManager = platformManager.targetManager(userProvidedTargetName) + private val host = HostManager.host + val target = targetManager.target + + protected val platform = platformManager.platform(target) + + val substitutions = defaultTargetSubstitutions(target) + + fun downloadDependencies() = platform.downloadDependencies() + + val llvmHome = platform.absoluteLlvmHome + val sysRoot = platform.absoluteTargetSysRoot + + val libclang = when (host) { + KonanTarget.MINGW_X64 -> "$llvmHome/bin/libclang.dll" + else -> "$llvmHome/lib/${System.mapLibraryName("clang")}" + } + + abstract fun loadLibclang() + + fun prepare() { + downloadDependencies() + + loadLibclang() + } +} \ No newline at end of file diff --git a/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt b/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt index 41f52389fa8..cd7047c88bc 100644 --- a/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt +++ b/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/KonanToolRunner.kt @@ -27,6 +27,7 @@ import org.jetbrains.kotlin.konan.util.DependencyDirectories import java.io.File import java.util.Properties import org.jetbrains.kotlin.compilerRunner.KotlinToolRunner +import org.jetbrains.kotlin.konan.target.AbstractToolConfig internal interface KonanToolRunner { fun run(args: List) @@ -67,10 +68,10 @@ internal abstract class KonanCliRunner( """.trimIndent() } - data class IsolatedClassLoaderCacheKey(val classpath: Set) + data class IsolatedClassLoaderCacheKey(val classpath: Set, val project: Project) // TODO: can't we use this for other implementations too? - final override val isolatedClassLoaderCacheKey get() = IsolatedClassLoaderCacheKey(classpath) + final override val isolatedClassLoaderCacheKey get() = IsolatedClassLoaderCacheKey(classpath, project) override fun transformArgs(args: List) = listOf(toolName) + args @@ -103,6 +104,16 @@ internal class KonanCliCompilerRunner( } } +private val load0 = Runtime::class.java.getDeclaredMethod("load0", Class::class.java, String::class.java).also { + it.isAccessible = true +} + +internal class CliToolConfig(konanHome: String, target: String) : AbstractToolConfig(konanHome, target, emptyMap()) { + override fun loadLibclang() { + load0.invoke(Runtime.getRuntime(), String::class.java, libclang) + } +} + /** Kotlin/Native C-interop tool runner */ internal class KonanCliInteropRunner( project: Project, @@ -125,6 +136,10 @@ internal class KonanCliInteropRunner( result } + fun init(target: String) { + CliToolConfig(konanHome, target).prepare() + } + private val llvmExecutablesPath: String? by lazy { if (HostManager.host == KonanTarget.MINGW_X64) { // TODO: Read it from Platform properties when it is accessible. diff --git a/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanInteropTask.kt b/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanInteropTask.kt index 30f39c917eb..54eb5af5c9f 100644 --- a/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanInteropTask.kt +++ b/kotlin-native/tools/kotlin-native-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/konan/tasks/KonanInteropTask.kt @@ -36,8 +36,10 @@ import javax.inject.Inject open class KonanInteropTask @Inject constructor(@Internal val workerExecutor: WorkerExecutor) : KonanBuildingTask(), KonanInteropSpec { + private val interopRunner = KonanCliInteropRunner(project, project.konanExtension.jvmArgs) + @get:Internal - override val toolRunner: KonanToolRunner = KonanCliInteropRunner(project, project.konanExtension.jvmArgs) + override val toolRunner: KonanToolRunner = interopRunner override fun init(config: KonanBuildingConfig<*>, destinationDir: File, artifactName: String, target: KonanTarget) { super.init(config, destinationDir, artifactName, target) @@ -174,6 +176,8 @@ open class KonanInteropTask @Inject constructor(@Internal val workerExecutor: Wo } override fun run() { + interopRunner.init(target) + destinationDir.mkdirs() if (dumpParameters) { dumpProperties(this) diff --git a/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/GeneratePlatformLibraries.kt b/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/GeneratePlatformLibraries.kt index f2c8fef160c..1405a4ed7e2 100644 --- a/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/GeneratePlatformLibraries.kt +++ b/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/GeneratePlatformLibraries.kt @@ -250,7 +250,7 @@ private fun generateLibrary( *def.depends.flatMap { listOf("-l", "$outputDirectory/${it.libraryName}") }.toTypedArray() ) logger.verbose("Run cinterop with args: ${cinteropArgs.joinToString(separator = " ")}") - invokeInterop("native", cinteropArgs)?.let { K2Native.mainNoExit(it) } + invokeInterop("native", cinteropArgs, runFromDaemon = false)?.let { K2Native.mainNoExit(it) } if (rebuild) { outKlib.deleteAtomicallyIfPossible(tmpDirectory) diff --git a/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/InteropCompiler.kt b/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/InteropCompiler.kt index 0bd241ea8b0..c3e6a33da0e 100644 --- a/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/InteropCompiler.kt +++ b/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/InteropCompiler.kt @@ -19,7 +19,7 @@ import org.jetbrains.kotlin.native.interop.tool.* * @return null if there is no need in compiler invocation. * Otherwise returns array of compiler args. */ -fun invokeInterop(flavor: String, args: Array): Array? { +fun invokeInterop(flavor: String, args: Array, runFromDaemon: Boolean): Array? { val arguments = if (flavor == "native") CInteropArguments() else JSInteropArguments() arguments.argParser.parse(args) val outputFileName = arguments.output @@ -46,7 +46,8 @@ fun invokeInterop(flavor: String, args: Array): Array? { InternalInteropOptions(generatedDir.absolutePath, nativesDir.absolutePath,manifest.path, cstubsName.takeIf { flavor == "native" } - ) + ), + runFromDaemon ) ?: return null // There is no need in compiler invocation if we're generating only metadata. val nativeStubs = diff --git a/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt b/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt index 5847bca519b..004ba54685e 100644 --- a/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt +++ b/kotlin-native/utilities/cli-runner/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt @@ -11,7 +11,7 @@ import org.jetbrains.kotlin.cli.bc.mainNoExitWithGradleRenderer as konancMainFor import org.jetbrains.kotlin.backend.konan.env.setEnv import org.jetbrains.kotlin.konan.util.usingNativeMemoryAllocator -private fun mainImpl(args: Array, konancMain: (Array) -> Unit) { +private fun mainImpl(args: Array, runFromDaemon: Boolean, konancMain: (Array) -> Unit) { val utilityName = args[0] val utilityArgs = args.drop(1).toTypedArray() when (utilityName) { @@ -37,17 +37,17 @@ private fun mainImpl(args: Array, konancMain: (Array) -> Unit) { konancMain(utilityArgs) } "cinterop" -> { - val konancArgs = invokeInterop("native", utilityArgs) + val konancArgs = invokeInterop("native", utilityArgs, runFromDaemon) konancArgs?.let { konancMain(it) } } "jsinterop" -> { - val konancArgs = invokeInterop("wasm", utilityArgs) + val konancArgs = invokeInterop("wasm", utilityArgs, runFromDaemon) konancArgs?.let { konancMain(it) } } "klib" -> klibMain(utilityArgs) "defFileDependencies" -> - defFileDependencies(utilityArgs) + defFileDependencies(utilityArgs, runFromDaemon) "generatePlatformLibraries" -> generatePlatformLibraries(utilityArgs) @@ -59,7 +59,7 @@ private fun mainImpl(args: Array, konancMain: (Array) -> Unit) { } } -fun main(args: Array) = mainImpl(args, ::konancMain) +fun main(args: Array) = mainImpl(args, false, ::konancMain) private fun setupClangEnv() { setEnv("LIBCLANG_DISABLE_CRASH_RECOVERY", "1") @@ -67,5 +67,5 @@ private fun setupClangEnv() { fun daemonMain(args: Array) = usingNativeMemoryAllocator { setupClangEnv() // For in-process invocation have to setup proper environment manually. - mainImpl(args, ::konancMainForGradle) + mainImpl(args, true, ::konancMainForGradle) } \ No newline at end of file