From 76e3ad7a5c4482e499fb200a45ad99cb78d00048 Mon Sep 17 00:00:00 2001 From: Igor Chevdar Date: Mon, 9 Dec 2019 20:07:51 +0300 Subject: [PATCH] Added shortcut option -add-cache for convenience --- .../org/jetbrains/kotlin/cli/bc/K2Native.kt | 33 +++++- .../cli/bc/K2NativeCompilerArguments.kt | 11 +- .../kotlin/backend/konan/CacheSupport.kt | 55 ++++++--- .../kotlin/backend/konan/CachedLibraries.kt | 8 +- .../kotlin/backend/konan/FeaturedLibraries.kt | 4 +- .../kotlin/backend/konan/KonanConfig.kt | 112 +++++------------- .../backend/konan/KonanConfigurationKeys.kt | 2 + .../konan/KonanLibrariesResolveSupport.kt | 90 ++++++++++++++ .../jetbrains/kotlin/backend/konan/Linker.kt | 31 ++++- .../kotlin/backend/konan/OutputFiles.kt | 34 +++++- .../konan/llvm/coverage/CoverageManager.kt | 2 +- 11 files changed, 262 insertions(+), 120 deletions(-) create mode 100644 backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLibrariesResolveSupport.kt diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 3387cb5b86c..3163a532f4f 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -94,7 +94,7 @@ class K2Native : CLICompiler() { val K2NativeCompilerArguments.isUsefulWithoutFreeArgs: Boolean get() = listTargets || listPhases || checkDependencies || !includes.isNullOrEmpty() || - !librariesToCache.isNullOrEmpty() + !librariesToCache.isNullOrEmpty() || libraryToAddToCache != null fun Array?.toNonNullList(): List { return this?.asList() ?: listOf() @@ -114,9 +114,9 @@ class K2Native : CLICompiler() { with(KonanConfigKeys) { with(configuration) { - put(NODEFAULTLIBS, arguments.nodefaultlibs) - put(NOENDORSEDLIBS, arguments.noendorsedlibs) - put(NOSTDLIB, arguments.nostdlib) + put(NODEFAULTLIBS, arguments.nodefaultlibs || !arguments.libraryToAddToCache.isNullOrEmpty()) + put(NOENDORSEDLIBS, arguments.noendorsedlibs || !arguments.libraryToAddToCache.isNullOrEmpty()) + put(NOSTDLIB, arguments.nostdlib || !arguments.libraryToAddToCache.isNullOrEmpty()) put(NOPACK, arguments.nopack) put(NOMAIN, arguments.nomain) put(LIBRARY_FILES, @@ -218,7 +218,12 @@ class K2Native : CLICompiler() { put(OBJC_GENERICS, arguments.objcGenerics) put(LIBRARIES_TO_CACHE, parseLibrariesToCache(arguments, configuration, outputKind)) - put(CACHE_DIRECTORIES, arguments.cacheDirectories.toNonNullList()) + val libraryToAddToCache = parseLibraryToAddToCache(arguments, configuration, outputKind) + if (libraryToAddToCache != null && !arguments.outputName.isNullOrEmpty()) + configuration.report(ERROR, "$ADD_CACHE already implicitly sets output file name") + val cacheDirectories = arguments.cacheDirectories.toNonNullList() + libraryToAddToCache?.let { put(LIBRARY_TO_ADD_TO_CACHE, it) } + put(CACHE_DIRECTORIES, cacheDirectories) put(CACHED_LIBRARIES, parseCachedLibraries(arguments, configuration)) } } @@ -342,6 +347,24 @@ private fun parseLibrariesToCache( return if (input.isNotEmpty() && !outputKind.isCache) { configuration.report(ERROR, "$MAKE_CACHE can't be used when not producing cache") emptyList() + } else if (input.isNotEmpty() && !arguments.libraryToAddToCache.isNullOrEmpty()) { + configuration.report(ERROR, "supplied both $MAKE_CACHE and $ADD_CACHE options") + emptyList() + } else { + input + } +} + +private fun parseLibraryToAddToCache( + arguments: K2NativeCompilerArguments, + configuration: CompilerConfiguration, + outputKind: CompilerOutputKind +): String? { + val input = arguments.libraryToAddToCache + + return if (input != null && !outputKind.isCache) { + configuration.report(ERROR, "$ADD_CACHE can't be used when not producing cache") + null } else { input } diff --git a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index 303d69869b8..173bc1d478d 100644 --- a/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -163,6 +163,14 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { ) var librariesToCache: Array? = null + @Argument( + value = ADD_CACHE, + valueDescription = "", + description = "Path to the library to be added to cache", + delimiter = "" + ) + var libraryToAddToCache: String? = null + @Argument(value = "-Xprint-bitcode", deprecatedName = "--print_bitcode", description = "Print llvm bitcode") var printBitCode: Boolean = false @@ -248,4 +256,5 @@ const val EMBED_BITCODE_MARKER_FLAG = "-Xembed-bitcode-marker" const val STATIC_FRAMEWORK_FLAG = "-Xstatic-framework" const val INCLUDE_ARG = "-Xinclude" const val CACHED_LIBRARY = "-Xcached-library" -const val MAKE_CACHE = "-Xmake-cache" \ No newline at end of file +const val MAKE_CACHE = "-Xmake-cache" +const val ADD_CACHE = "-Xadd-cache" \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt index bb6fe1ff0bb..48cf21a951d 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CacheSupport.kt @@ -13,7 +13,7 @@ import org.jetbrains.kotlin.library.KotlinLibrary import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult class CacheSupport( - configuration: CompilerConfiguration, + val configuration: CompilerConfiguration, resolvedLibraries: KotlinLibraryResolveResult, target: KonanTarget, produce: CompilerOutputKind @@ -23,6 +23,22 @@ class CacheSupport( // TODO: consider using [FeaturedLibraries.kt]. private val fileToLibrary = allLibraries.associateBy { it.libraryFile } + private val implicitCacheDirectories = configuration.get(KonanConfigKeys.CACHE_DIRECTORIES)!! + .map { + File(it).takeIf { it.isDirectory } + ?: configuration.reportCompilationError("cache directory $it is not found or not a directory") + } + + internal fun tryGetImplicitOutput(): String? { + val libraryToAddToCache = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE) ?: return null + // Put the resulting library in the first cache directory. + val cacheDirectory = implicitCacheDirectories.firstOrNull() ?: return null + val libraryToAddToCacheFile = File(libraryToAddToCache) + val library = allLibraries.single { it.libraryFile == libraryToAddToCacheFile } + return cacheDirectory.child(CachedLibraries.getCachedLibraryName(library)).absolutePath + } + + internal val cachedLibraries: CachedLibraries = run { val explicitCacheFiles = configuration.get(KonanConfigKeys.CACHED_LIBRARIES)!! @@ -33,12 +49,6 @@ class CacheSupport( library to cachePath } - val implicitCacheDirectories = configuration.get(KonanConfigKeys.CACHE_DIRECTORIES)!! - .map { - File(it).takeIf { it.isDirectory } - ?: configuration.reportCompilationError("cache directory $it is not found or not a directory") - } - CachedLibraries( target = target, allLibraries = allLibraries, @@ -47,14 +57,29 @@ class CacheSupport( ) } - internal val librariesToCache: Set = configuration.get(KonanConfigKeys.LIBRARIES_TO_CACHE)!! - .map { File(it) }.map { - fileToLibrary[it] ?: error("library to cache\n" + - " ${it.absolutePath}\n" + - "not found among resolved libraries:\n " + - allLibraries.joinToString("\n ") { it.libraryFile.absolutePath }) - }.toSet() - .also { if (!produce.isCache) check(it.isEmpty()) } + private fun getLibrary(file: File) = + fileToLibrary[file] ?: error("library to cache\n" + + " ${file.absolutePath}\n" + + "not found among resolved libraries:\n " + + allLibraries.joinToString("\n ") { it.libraryFile.absolutePath }) + + internal val librariesToCache: Set = run { + val libraryToAddToCachePath = configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE) + if (libraryToAddToCachePath.isNullOrEmpty()) { + configuration.get(KonanConfigKeys.LIBRARIES_TO_CACHE)!! + .map { getLibrary(File(it)) } + .toSet() + .also { if (!produce.isCache) check(it.isEmpty()) } + } else { + val libraryToAddToCacheFile = File(libraryToAddToCachePath) + val libraryToAddToCache = getLibrary(libraryToAddToCacheFile) + val libraryCache = cachedLibraries.getLibraryCache(libraryToAddToCache) + if (libraryCache == null) + setOf(libraryToAddToCache) + else + emptySet() + } + } init { // Ensure dependencies of every cached library are cached too: diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt index a7cf2296ab4..1a7e9983a0e 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/CachedLibraries.kt @@ -35,7 +35,7 @@ internal class CachedLibraries( Cache(kind, explicitPath) } else { implicitCacheDirectories.firstNotNullResult { dir -> - val baseName = "${library.uniqueName}-cache" + val baseName = getCachedLibraryName(library) val dynamicFile = dir.child(getArtifactName(baseName, CompilerOutputKind.DYNAMIC_CACHE)) val staticFile = dir.child(getArtifactName(baseName, CompilerOutputKind.STATIC_CACHE)) @@ -50,7 +50,7 @@ internal class CachedLibraries( cache?.let { library to it } }.toMap() - private fun getArtifactName(baseName: String, kind: CompilerOutputKind) = + fun getArtifactName(baseName: String, kind: CompilerOutputKind) = "${kind.prefix(target)}$baseName${kind.suffix(target)}" fun isLibraryCached(library: KotlinLibrary): Boolean = @@ -72,4 +72,8 @@ internal class CachedLibraries( Cache.Kind.DYNAMIC -> true } } + + companion object { + fun getCachedLibraryName(library: KotlinLibrary): String = "${library.uniqueName}-cache" + } } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FeaturedLibraries.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FeaturedLibraries.kt index 14b4a389df7..3f57cc1f4d6 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FeaturedLibraries.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/FeaturedLibraries.kt @@ -16,8 +16,8 @@ import org.jetbrains.kotlin.library.SearchPathResolver import org.jetbrains.kotlin.library.isInterop import org.jetbrains.kotlin.library.toUnresolvedLibraries -internal fun Context.getExportedDependencies(): List = getDescriptorsFromLibraries((config.exportedLibraries + config.includedLibraries).toSet()) -internal fun Context.getIncludedLibraryDescriptors(): List = getDescriptorsFromLibraries(config.includedLibraries.toSet()) +internal fun Context.getExportedDependencies(): List = getDescriptorsFromLibraries((config.resolve.exportedLibraries + config.resolve.includedLibraries).toSet()) +internal fun Context.getIncludedLibraryDescriptors(): List = getDescriptorsFromLibraries(config.resolve.includedLibraries.toSet()) private fun Context.getDescriptorsFromLibraries(libraries: Set) = moduleDescriptor.allDependencyModules.filter { diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt index 38c380f56c4..a44f2f053cc 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfig.kt @@ -6,28 +6,29 @@ package org.jetbrains.kotlin.backend.konan import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.config.kotlinSourceRoots import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.* -import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector import org.jetbrains.kotlin.config.CommonConfigurationKeys import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.descriptors.ModuleDescriptor -import org.jetbrains.kotlin.konan.* +import org.jetbrains.kotlin.konan.CURRENT +import org.jetbrains.kotlin.konan.MetaVersion +import org.jetbrains.kotlin.konan.TempFiles import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.library.KonanLibrary -import org.jetbrains.kotlin.konan.library.defaultResolver import org.jetbrains.kotlin.konan.properties.loadProperties +import org.jetbrains.kotlin.konan.target.Distribution +import org.jetbrains.kotlin.konan.target.HostManager +import org.jetbrains.kotlin.konan.target.KonanTarget +import org.jetbrains.kotlin.konan.target.PlatformManager import org.jetbrains.kotlin.konan.target.* import org.jetbrains.kotlin.util.Logger import kotlin.system.exitProcess import org.jetbrains.kotlin.library.toUnresolvedLibraries import org.jetbrains.kotlin.konan.CompilerVersion import org.jetbrains.kotlin.library.KotlinLibrary -import org.jetbrains.kotlin.library.resolver.impl.libraryResolver -import org.jetbrains.kotlin.library.UnresolvedLibrary +import org.jetbrains.kotlin.library.resolver.TopologicalLibraryOrder class KonanConfig(val project: Project, val configuration: CompilerConfiguration) { @@ -41,10 +42,6 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration internal val target = targetManager.target internal val phaseConfig = configuration.get(CLIConfigurationKeys.PHASE_CONFIG)!! - val infoArgsOnly = configuration.kotlinSourceRoots.isEmpty() - && configuration[KonanConfigKeys.INCLUDED_LIBRARIES].isNullOrEmpty() - && configuration[KonanConfigKeys.LIBRARIES_TO_CACHE].isNullOrEmpty() - // TODO: debug info generation mode and debug/release variant selection probably requires some refactoring. val debug: Boolean get() = configuration.getBoolean(KonanConfigKeys.DEBUG) val lightDebug: Boolean get() = configuration.getBoolean(KonanConfigKeys.LIGHT_DEBUG) @@ -76,83 +73,14 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration internal val produceStaticFramework get() = configuration.getBoolean(KonanConfigKeys.STATIC_FRAMEWORK) - val outputFiles = OutputFiles(configuration.get(KonanConfigKeys.OUTPUT), target, produce) - val tempFiles = TempFiles(outputFiles.outputName, configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR)) - - val outputFile = outputFiles.mainFile - - val moduleId: String - get() = configuration.get(KonanConfigKeys.MODULE_NAME) ?: File(outputFiles.outputName).name - internal val purgeUserLibs: Boolean get() = configuration.getBoolean(KonanConfigKeys.PURGE_USER_LIBS) - private val libraryNames: List - get() = configuration.getList(KonanConfigKeys.LIBRARY_FILES) + internal val resolve = KonanLibrariesResolveSupport(configuration, target, distribution) - private val includedLibraryFiles - get() = configuration.getList(KonanConfigKeys.INCLUDED_LIBRARIES).map { File(it) } + internal val resolvedLibraries get() = resolve.resolvedLibraries - private val librariesToCacheFiles - get() = configuration.getList(KonanConfigKeys.LIBRARIES_TO_CACHE).map { File(it) } - - private val unresolvedLibraries = libraryNames.toUnresolvedLibraries - - private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES) - private val resolverLogger = - object : Logger { - private val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) - override fun warning(message: String)= collector.report(STRONG_WARNING, message) - override fun error(message: String) = collector.report(ERROR, message) - override fun log(message: String) = collector.report(LOGGING, message) - override fun fatal(message: String): Nothing { - collector.report(ERROR, message) - (collector as? GroupingMessageCollector)?.flush() - exitProcess(1) - } - } - - private val compatibleCompilerVersions: List = - configuration.getList(KonanConfigKeys.COMPATIBLE_COMPILER_VERSIONS).map { it.parseCompilerVersion() } - - private val resolver = defaultResolver( - repositories, - libraryNames.filter { it.contains(File.separator) }, - target, - distribution, - compatibleCompilerVersions, - resolverLogger - ).libraryResolver() - - // We pass included libraries by absolute paths to avoid repository-based resolution for them. - // Strictly speaking such "direct" libraries should be specially handled by the resolver, not by KonanConfig. - // But currently the resolver is in the middle of a complex refactoring so it was decided to avoid changes in its logic. - // TODO: Handle included libraries in KonanLibraryResolver when it's refactored and moved into the big Kotlin repo. - internal val resolvedLibraries by lazy { - val additionalLibraryFiles = includedLibraryFiles + librariesToCacheFiles - resolver.resolveWithDependencies( - unresolvedLibraries + additionalLibraryFiles.map { UnresolvedLibrary(it.absolutePath, null) }, - noStdLib = configuration.getBoolean(KonanConfigKeys.NOSTDLIB), - noDefaultLibs = configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS), - noEndorsedLibs = configuration.getBoolean(KonanConfigKeys.NOENDORSEDLIBS) - ) - } - - internal val exportedLibraries by lazy { - getExportedLibraries(configuration, resolvedLibraries, resolver.searchPathResolver, report = true) - } - - internal val coveredLibraries by lazy { - getCoveredLibraries(configuration, resolvedLibraries, resolver.searchPathResolver) - } - - internal val includedLibraries by lazy { - getIncludedLibraries(includedLibraryFiles, configuration, resolvedLibraries) - } - - internal val cacheSupport: CacheSupport by lazy { - CacheSupport(configuration, resolvedLibraries, target, produce) - } + internal val cacheSupport = CacheSupport(configuration, resolvedLibraries, target, produce) internal val cachedLibraries: CachedLibraries get() = cacheSupport.cachedLibraries @@ -160,6 +88,21 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration internal val librariesToCache: Set get() = cacheSupport.librariesToCache + val outputFiles = + OutputFiles(configuration.get(KonanConfigKeys.OUTPUT) ?: cacheSupport.tryGetImplicitOutput(), + target, produce) + + val tempFiles = TempFiles(outputFiles.outputName, configuration.get(KonanConfigKeys.TEMPORARY_FILES_DIR)) + + val outputFile get() = outputFiles.mainFile + + val moduleId: String + get() = configuration.get(KonanConfigKeys.MODULE_NAME) ?: File(outputFiles.outputName).name + + val infoArgsOnly = configuration.kotlinSourceRoots.isEmpty() + && configuration[KonanConfigKeys.INCLUDED_LIBRARIES].isNullOrEmpty() + && librariesToCache.isEmpty() + fun librariesWithDependencies(moduleDescriptor: ModuleDescriptor?): List { if (moduleDescriptor == null) error("purgeUnneeded() only works correctly after resolve is over, and we have successfully marked package files as needed or not needed.") @@ -206,5 +149,4 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration } fun CompilerConfiguration.report(priority: CompilerMessageSeverity, message: String) - = this.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(priority, message) - + = this.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY).report(priority, message) \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 0f5a02b42e7..b26c5af4d00 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -34,6 +34,8 @@ class KonanConfigKeys { = CompilerConfigurationKey.create>("libraries included into produced framework API") val LIBRARIES_TO_CACHE: CompilerConfigurationKey> = CompilerConfigurationKey.create>("paths to libraries that to be compiled to cache") + val LIBRARY_TO_ADD_TO_CACHE: CompilerConfigurationKey + = CompilerConfigurationKey.create("path to library that to be added to cache") val CACHE_DIRECTORIES: CompilerConfigurationKey> = CompilerConfigurationKey.create>("paths to directories containing caches") val CACHED_LIBRARIES: CompilerConfigurationKey> diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLibrariesResolveSupport.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLibrariesResolveSupport.kt new file mode 100644 index 00000000000..d2f62892442 --- /dev/null +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanLibrariesResolveSupport.kt @@ -0,0 +1,90 @@ +/* + * Copyright 2010-2018 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.backend.konan + +import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity +import org.jetbrains.kotlin.cli.common.messages.GroupingMessageCollector +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.konan.CompilerVersion +import org.jetbrains.kotlin.konan.file.File +import org.jetbrains.kotlin.konan.library.defaultResolver +import org.jetbrains.kotlin.konan.parseCompilerVersion +import org.jetbrains.kotlin.konan.target.Distribution +import org.jetbrains.kotlin.konan.target.KonanTarget +import org.jetbrains.kotlin.library.UnresolvedLibrary +import org.jetbrains.kotlin.library.resolver.impl.libraryResolver +import org.jetbrains.kotlin.library.toUnresolvedLibraries +import org.jetbrains.kotlin.util.Logger +import kotlin.system.exitProcess + +class KonanLibrariesResolveSupport( + configuration: CompilerConfiguration, + target: KonanTarget, + distribution: Distribution +) { + private val includedLibraryFiles = + configuration.getList(KonanConfigKeys.INCLUDED_LIBRARIES).map { File(it) } + + private val librariesToCacheFiles = + configuration.getList(KonanConfigKeys.LIBRARIES_TO_CACHE).map { File(it) } + + configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE).let { + if (it.isNullOrEmpty()) emptyList() else listOf(File(it)) + } + + private val libraryNames = configuration.getList(KonanConfigKeys.LIBRARY_FILES) + + private val unresolvedLibraries = libraryNames.toUnresolvedLibraries + + private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES) + private val resolverLogger = + object : Logger { + private val collector = configuration.getNotNull(CLIConfigurationKeys.MESSAGE_COLLECTOR_KEY) + override fun warning(message: String)= collector.report(CompilerMessageSeverity.STRONG_WARNING, message) + override fun error(message: String) = collector.report(CompilerMessageSeverity.ERROR, message) + override fun log(message: String) = collector.report(CompilerMessageSeverity.LOGGING, message) + override fun fatal(message: String): Nothing { + collector.report(CompilerMessageSeverity.ERROR, message) + (collector as? GroupingMessageCollector)?.flush() + exitProcess(1) + } + } + + private val compatibleCompilerVersions: List = + configuration.getList(KonanConfigKeys.COMPATIBLE_COMPILER_VERSIONS).map { it.parseCompilerVersion() } + + private val resolver = defaultResolver( + repositories, + libraryNames.filter { it.contains(File.separator) }, + target, + distribution, + compatibleCompilerVersions, + resolverLogger + ).libraryResolver() + + // We pass included libraries by absolute paths to avoid repository-based resolution for them. + // Strictly speaking such "direct" libraries should be specially handled by the resolver, not by KonanConfig. + // But currently the resolver is in the middle of a complex refactoring so it was decided to avoid changes in its logic. + // TODO: Handle included libraries in KonanLibraryResolver when it's refactored and moved into the big Kotlin repo. + internal val resolvedLibraries = run { + val additionalLibraryFiles = includedLibraryFiles + librariesToCacheFiles + resolver.resolveWithDependencies( + unresolvedLibraries + additionalLibraryFiles.map { UnresolvedLibrary(it.absolutePath, null) }, + noStdLib = configuration.getBoolean(KonanConfigKeys.NOSTDLIB), + noDefaultLibs = configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS), + noEndorsedLibs = configuration.getBoolean(KonanConfigKeys.NOENDORSEDLIBS) + ) + } + + internal val exportedLibraries = + getExportedLibraries(configuration, resolvedLibraries, resolver.searchPathResolver, report = true) + + internal val coveredLibraries = + getCoveredLibraries(configuration, resolvedLibraries, resolver.searchPathResolver) + + internal val includedLibraries = + getIncludedLibraries(includedLibraryFiles, configuration, resolvedLibraries) +} \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt index 400b95d5748..fddb170a575 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt @@ -36,6 +36,22 @@ internal class Linker(val context: Context) { val includedBinaries = nativeDependencies.map { it.includedPaths }.flatten() val libraryProvidedLinkerFlags = nativeDependencies.map { it.linkerOpts }.flatten() runLinker(objectFiles, includedBinaries, libraryProvidedLinkerFlags) + renameOutput() + } + + private fun renameOutput() { + val libraryToAddToCache = context.configuration.get(KonanConfigKeys.LIBRARY_TO_ADD_TO_CACHE) + if (context.config.produce.isCache && !libraryToAddToCache.isNullOrEmpty()) { + val outputFiles = context.config.outputFiles + val outputFile = java.io.File(outputFiles.mainFileMangled) + val outputDsymBundle = java.io.File(outputFiles.mainFileMangled + ".dSYM") + if (outputFile.renameTo(java.io.File(outputFiles.mainFile))) + outputDsymBundle.renameTo(java.io.File(outputFiles.mainFile + ".dSYM")) + else { + outputFile.delete() + outputDsymBundle.deleteRecursively() + } + } } private fun asLinkerArgs(args: List): List { @@ -58,12 +74,15 @@ internal class Linker(val context: Context) { private fun runLinker(objectFiles: List, includedBinaries: List, libraryProvidedLinkerFlags: List): ExecutableFile? { - val frameworkLinkerArgs: List + val additionalLinkerArgs: List val executable: String if (context.config.produce != CompilerOutputKind.FRAMEWORK) { - frameworkLinkerArgs = emptyList() - executable = context.config.outputFile + if (context.config.produce == CompilerOutputKind.DYNAMIC_CACHE && target.family.isAppleFamily) + additionalLinkerArgs = listOf("-install_name", context.config.outputFiles.mainFile) + else + additionalLinkerArgs = emptyList() + executable = context.config.outputFiles.mainFileMangled } else { val framework = File(context.config.outputFile) val dylibName = framework.name.removeSuffix(".framework") @@ -74,7 +93,7 @@ internal class Linker(val context: Context) { Family.OSX -> "Versions/A/$dylibName" else -> error(target) } - frameworkLinkerArgs = listOf("-install_name", "@rpath/${framework.name}/$dylibRelativePath") + additionalLinkerArgs = listOf("-install_name", "@rpath/${framework.name}/$dylibRelativePath") val dylibPath = framework.child(dylibRelativePath) dylibPath.parentFile.mkdirs() executable = dylibPath.absolutePath @@ -92,9 +111,9 @@ internal class Linker(val context: Context) { linkerArgs = asLinkerArgs(config.getNotNull(KonanConfigKeys.LINKER_ARGS)) + BitcodeEmbedding.getLinkerOptions(context.config) + caches.dynamic + - libraryProvidedLinkerFlags + frameworkLinkerArgs, + libraryProvidedLinkerFlags + additionalLinkerArgs, optimize = optimize, debug = debug, kind = linkerOutput, - outputDsymBundle = context.config.outputFile + ".dSYM", + outputDsymBundle = context.config.outputFiles.mainFileMangled + ".dSYM", needsProfileLibrary = needsProfileLibrary).forEach { it.logWith(context::log) it.execute() diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt index 588472ee4a0..77eeabe9181 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/OutputFiles.kt @@ -11,12 +11,13 @@ import org.jetbrains.kotlin.konan.file.File import org.jetbrains.kotlin.konan.target.CompilerOutputKind import org.jetbrains.kotlin.konan.target.KonanTarget import org.jetbrains.kotlin.konan.util.visibleName +import kotlin.random.Random /** * Creates and stores terminal compiler outputs. */ -class OutputFiles(outputPath: String?, target: KonanTarget, produce: CompilerOutputKind) { +class OutputFiles(outputPath: String?, target: KonanTarget, val produce: CompilerOutputKind) { private val prefix = produce.prefix(target) private val suffix = produce.suffix(target) @@ -33,6 +34,33 @@ class OutputFiles(outputPath: String?, target: KonanTarget, produce: CompilerOut * Main compiler's output file. */ val mainFile = outputName - .prefixBaseNameIfNot(prefix) - .suffixIfNot(suffix) + .prefixBaseNameIfNeeded(prefix) + .suffixIfNeeded(suffix) + + val mainFileMangled = if (!produce.isCache) mainFile else { + (outputName + Random.nextLong().toString()) + .prefixBaseNameIfNeeded(prefix) + .suffixIfNeeded(suffix) + } + + private fun String.prefixBaseNameIfNeeded(prefix: String): String { + return if (produce.isCache) + prefixBaseNameAlways(prefix) + else prefixBaseNameIfNot(prefix) + } + + private fun String.suffixIfNeeded(prefix: String): String { + return if (produce.isCache) + suffixAlways(prefix) + else suffixIfNot(prefix) + } + + private fun String.prefixBaseNameAlways(prefix: String): String { + val file = File(this).absoluteFile + val name = file.name + val directory = file.parent + return "$directory/$prefix$name" + } + + private fun String.suffixAlways(suffix: String) = "$this$suffix" } \ No newline at end of file diff --git a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt index 4ad86aa63f9..dc3ac8ca1ad 100644 --- a/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt +++ b/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/llvm/coverage/CoverageManager.kt @@ -25,7 +25,7 @@ internal class CoverageManager(val context: Context) { context.config.shouldCoverSources private val librariesToCover: Set = - context.config.coveredLibraries.map { it.libraryName }.toSet() + context.config.resolve.coveredLibraries.map { it.libraryName }.toSet() private val llvmProfileFilenameGlobal = "__llvm_profile_filename"