diff --git a/build.gradle b/build.gradle index ce7adc3eb4a..d90e89a3fa4 100644 --- a/build.gradle +++ b/build.gradle @@ -351,6 +351,15 @@ task distCompiler(type: Copy) { } } +task distDef(type: Copy) { + + destinationDir distDir + + from(project("platformLibs").file("src/platform")) { + into('klib/platformDef') + } +} + task listDist(type: Exec) { commandLine 'find', distDir } @@ -472,6 +481,7 @@ task bundle(type: (isWindows()) ? Zip : Tar) { } task bundleRestricted(type: Tar) { + dependsOn("distDef") def simpleOsName = HostManager.simpleOsName() baseName = "kotlin-native-restricted-$simpleOsName-$konanVersionFull" from("$project.rootDir/dist") { diff --git a/cmd/generate-platform b/cmd/generate-platform new file mode 100755 index 00000000000..6b219a1eafa --- /dev/null +++ b/cmd/generate-platform @@ -0,0 +1,20 @@ +#!/usr/bin/env bash + +# Copyright 2010-2017 JetBrains s.r.o. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +DIR="${BASH_SOURCE[0]%/*}" +: ${DIR:="."} + +"${DIR}"/run_konan generatePlatformLibraries "$@" diff --git a/cmd/generate-platform.bat b/cmd/generate-platform.bat new file mode 100644 index 00000000000..39265eebd01 --- /dev/null +++ b/cmd/generate-platform.bat @@ -0,0 +1,17 @@ +@echo off + +rem Copyright 2010-2017 JetBrains s.r.o. +rem +rem Licensed under the Apache License, Version 2.0 (the "License"); +rem you may not use this file except in compliance with the License. +rem You may obtain a copy of the License at +rem +rem http://www.apache.org/licenses/LICENSE-2.0 +rem +rem Unless required by applicable law or agreed to in writing, software +rem distributed under the License is distributed on an "AS IS" BASIS, +rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +rem See the License for the specific language governing permissions and +rem limitations under the License. + +call %~dps0run_konan.bat generatePlatformLibraries %* diff --git a/cmd/run_konan b/cmd/run_konan index b9daa2f8d08..d8dad18b4c0 100755 --- a/cmd/run_konan +++ b/cmd/run_konan @@ -80,7 +80,6 @@ done < "${KONAN_HOME}/tools/env_blacklist" KONAN_JAR="${KONAN_HOME}/konan/lib/kotlin-native.jar" KONAN_CLASSPATH="$KONAN_JAR" TOOL_CLASS=org.jetbrains.kotlin.cli.utilities.MainKt - LIBCLANG_DISABLE_CRASH_RECOVERY=1 \ $TIMECMD "$JAVACMD" "${java_opts[@]}" "${java_args[@]}" -cp "$KONAN_CLASSPATH" "$TOOL_CLASS" "$TOOL_NAME" "${konan_args[@]}" diff --git a/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/GeneratePlatformLibraries.kt b/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/GeneratePlatformLibraries.kt new file mode 100644 index 00000000000..59ab9de1429 --- /dev/null +++ b/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/GeneratePlatformLibraries.kt @@ -0,0 +1,136 @@ +/* + * Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license + * that can be found in the LICENSE file. + */ + +package org.jetbrains.kotlin.cli.utilities + +import org.jetbrains.kotlin.cli.bc.K2Native +import org.jetbrains.kotlin.konan.file.File +import java.util.concurrent.* +import kotlinx.cli.* + +fun generatePlatformLibraries(args: Array) { + val argParser = ArgParser("generate-platform", prefixStyle = ArgParser.OPTION_PREFIX_STYLE.JVM) + val inputDirectoryPath by argParser.option( + ArgType.String, "input-directory", "i", "Input directory").required() + val outputDirectoryPath by argParser.option( + ArgType.String, "output-directory", "o", "Output directory").required() + val target by argParser.option( + ArgType.String, "target", "t", "Compilation target").required() + val saveTemps by argParser.option( + ArgType.Boolean, "save-temps", "s", "Save temporary files").default(false) + argParser.parse(args) + + val inputDirectory = File(inputDirectoryPath) + val outputDirectory = File(outputDirectoryPath) + + if (!inputDirectory.exists) throw Error("input directory doesn't exist") + if (!outputDirectory.exists) { + outputDirectory.mkdirs() + } + + generatePlatformLibraries(target, inputDirectory, outputDirectory, saveTemps) +} + +private class DefFile(val name: String, val depends: MutableList) { + + override fun hashCode(): Int { + return name.hashCode() + } + + override fun equals(other: Any?): Boolean { + return other is DefFile && other.name == name + } + override fun toString(): String = "$name: [${depends.joinToString(separator = ", ") { it.name }}]" +} + +private fun topoSort(defFiles: List): List { + // Do DFS toposort. + val markGray = mutableSetOf() + val markBlack = mutableSetOf() + val result = mutableListOf() + + fun visit(def: DefFile) { + if (markBlack.contains(def)) return + if (markGray.contains(def)) throw Error("$def is part of cycle") + markGray += def + def.depends.forEach { + visit(it) + } + markGray -= def + markBlack += def + result += def + } + + var index = 0 + while (markBlack.size < defFiles.size) { + visit(defFiles[index++]) + } + return result +} + +private fun generatePlatformLibraries(target: String, inputDirectory: File, outputDirectory: File, saveTemps: Boolean) { + fun buildKlib(def: DefFile) { + val file = File("$inputDirectory/${def.name}.def") + File("${outputDirectory.absolutePath}/build-${def.name}").mkdirs() + val outKlib = "${outputDirectory.absolutePath}/build-${def.name}/${def.name}.klib" + val args = arrayOf("-o", outKlib, + "-target", target, + "-def", file.absolutePath, + "-compiler-option", "-fmodules-cache-path=$outputDirectory/clangModulesCache", + "-repo", "${outputDirectory.absolutePath}", + "-no-default-libs", "-no-endorsed-libs", "-Xpurge-user-libs", + *def.depends.flatMap { listOf("-l", "$outputDirectory/${it.name}") }.toTypedArray()) + println("Processing ${def.name}...") + K2Native.mainNoExit(invokeInterop("native", args)) + org.jetbrains.kotlin.cli.klib.main(arrayOf("install", outKlib, + "-target", target, + "-repository", "${outputDirectory.absolutePath}" + )) + if (!saveTemps) { + File("$outputDirectory/build-${def.name}").deleteRecursively() + } + } + println("generate platform libraries from $inputDirectory to $outputDirectory for $target") + // Build dependencies graph. + val defFiles = mutableMapOf() + val dependsRegex = Regex("^depends = (.*)") + inputDirectory.listFilesOrEmpty.filter { it.extension == "def" }.forEach { file -> + val name = file.name.split(".").also { assert(it.size == 2) }[0] + val def = defFiles.getOrPut(name) { + DefFile(name, mutableListOf()) + } + file.forEachLine { line -> + val match = dependsRegex.matchEntire(line) + if (match != null) { + match.groupValues[1].split(" ").forEach { dependency -> + def.depends.add(defFiles.getOrPut(dependency) { + DefFile(dependency, mutableListOf()) + }) + } + } + } + } + val sorted = topoSort(defFiles.values.toList()) + val numCores = Runtime.getRuntime().availableProcessors() + val executorPool = ThreadPoolExecutor(numCores, numCores, + 10, TimeUnit.SECONDS, ArrayBlockingQueue(1000), + Executors.defaultThreadFactory(), RejectedExecutionHandler { r, executor -> + println("Execution rejected: $r") + throw Error("Must not happen!") + }) + val built = ConcurrentHashMap(sorted.associateWith { 0 }) + // Now run interop tool on toposorted dependencies. + sorted.forEach { def -> + executorPool.execute { + // A bit ugly, we just block here until all dependencies are built. + while (def.depends.any { built[it] == 0 }) { + Thread.sleep(100) + } + buildKlib(def) + built[def] = 1 + } + } + executorPool.shutdown() +} \ No newline at end of file diff --git a/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt b/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt index 7b5111d4714..3f489f21bdf 100644 --- a/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt +++ b/utilities/src/main/kotlin/org/jetbrains/kotlin/cli/utilities/main.kt @@ -17,16 +17,18 @@ private fun mainImpl(args: Array, konancMain: (Array) -> Unit) { konancMain(utilityArgs) "cinterop" -> { val konancArgs = invokeInterop("native", utilityArgs) - konancArgs?.let { konancMain(it) } + konancMain(konancArgs) } "jsinterop" -> { val konancArgs = invokeInterop("wasm", utilityArgs) - konancArgs?.let { konancMain(it) } + konancMain(konancArgs) } "klib" -> klibMain(utilityArgs) "defFileDependencies" -> defFileDependencies(utilityArgs) + "generatePlatformLibraries" -> + generatePlatformLibraries(utilityArgs) else -> error("Unexpected utility name") }