Added shortcut option -add-cache for convenience

This commit is contained in:
Igor Chevdar
2019-12-09 20:07:51 +03:00
parent a6e1af87a4
commit 76e3ad7a5c
11 changed files with 262 additions and 120 deletions
@@ -94,7 +94,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
val K2NativeCompilerArguments.isUsefulWithoutFreeArgs: Boolean
get() = listTargets || listPhases || checkDependencies || !includes.isNullOrEmpty() ||
!librariesToCache.isNullOrEmpty()
!librariesToCache.isNullOrEmpty() || libraryToAddToCache != null
fun Array<String>?.toNonNullList(): List<String> {
return this?.asList<String>() ?: listOf<String>()
@@ -114,9 +114,9 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
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<K2NativeCompilerArguments>() {
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
}
@@ -163,6 +163,14 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
)
var librariesToCache: Array<String>? = null
@Argument(
value = ADD_CACHE,
valueDescription = "<path>",
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"
const val MAKE_CACHE = "-Xmake-cache"
const val ADD_CACHE = "-Xadd-cache"
@@ -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<KotlinLibrary> = 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<KotlinLibrary> = 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:
@@ -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"
}
}
@@ -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<ModuleDescriptor> = getDescriptorsFromLibraries((config.exportedLibraries + config.includedLibraries).toSet())
internal fun Context.getIncludedLibraryDescriptors(): List<ModuleDescriptor> = getDescriptorsFromLibraries(config.includedLibraries.toSet())
internal fun Context.getExportedDependencies(): List<ModuleDescriptor> = getDescriptorsFromLibraries((config.resolve.exportedLibraries + config.resolve.includedLibraries).toSet())
internal fun Context.getIncludedLibraryDescriptors(): List<ModuleDescriptor> = getDescriptorsFromLibraries(config.resolve.includedLibraries.toSet())
private fun Context.getDescriptorsFromLibraries(libraries: Set<KonanLibrary>) =
moduleDescriptor.allDependencyModules.filter {
@@ -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<String>
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<CompilerVersion> =
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<KotlinLibrary>
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<KonanLibrary> {
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)
@@ -34,6 +34,8 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create<List<String>>("libraries included into produced framework API")
val LIBRARIES_TO_CACHE: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create<List<String>>("paths to libraries that to be compiled to cache")
val LIBRARY_TO_ADD_TO_CACHE: CompilerConfigurationKey<String?>
= CompilerConfigurationKey.create<String?>("path to library that to be added to cache")
val CACHE_DIRECTORIES: CompilerConfigurationKey<List<String>>
= CompilerConfigurationKey.create<List<String>>("paths to directories containing caches")
val CACHED_LIBRARIES: CompilerConfigurationKey<Map<String, String>>
@@ -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<CompilerVersion> =
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)
}
@@ -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<String>): List<String> {
@@ -58,12 +74,15 @@ internal class Linker(val context: Context) {
private fun runLinker(objectFiles: List<ObjectFile>,
includedBinaries: List<String>,
libraryProvidedLinkerFlags: List<String>): ExecutableFile? {
val frameworkLinkerArgs: List<String>
val additionalLinkerArgs: List<String>
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()
@@ -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"
}
@@ -25,7 +25,7 @@ internal class CoverageManager(val context: Context) {
context.config.shouldCoverSources
private val librariesToCover: Set<String> =
context.config.coveredLibraries.map { it.libraryName }.toSet()
context.config.resolve.coveredLibraries.map { it.libraryName }.toSet()
private val llvmProfileFilenameGlobal = "__llvm_profile_filename"