Auto link everything found in dist/klib.
Disable such behavior with -nodefaultlibs. Omit libraries from the link stage if their packages have not been referenced.
This commit is contained in:
committed by
alexander-gorshenev
parent
5d79c079b4
commit
27f7e4263b
@@ -78,6 +78,7 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
|
||||
with(KonanConfigKeys) {
|
||||
with(configuration) {
|
||||
|
||||
put(NODEFAULTLIBS, arguments.nodefaultlibs)
|
||||
put(NOSTDLIB, arguments.nostdlib)
|
||||
put(NOPACK, arguments.nopack)
|
||||
put(NOMAIN, arguments.nomain)
|
||||
|
||||
@@ -48,6 +48,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-nativelibrary", shortName = "-nl", valueDescription = "<path>", description = "Include the native bitcode library")
|
||||
var nativeLibraries: Array<String>? = null
|
||||
|
||||
@Argument(value = "-nodefaultlibs", description = "Don't link the libraries from dist/klib automatically")
|
||||
var nodefaultlibs: Boolean = false
|
||||
|
||||
@Argument(value = "-nomain", description = "Assume 'main' entry point to be provided by external libraries")
|
||||
var nomain: Boolean = false
|
||||
|
||||
|
||||
+16
-16
@@ -75,26 +75,26 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
||||
get() = outputName
|
||||
|
||||
private val libraryNames: List<String>
|
||||
get() {
|
||||
val fromCommandLine = configuration.getList(KonanConfigKeys.LIBRARY_FILES)
|
||||
if (configuration.get(KonanConfigKeys.NOSTDLIB) ?: false) {
|
||||
return fromCommandLine
|
||||
}
|
||||
return fromCommandLine + "stdlib"
|
||||
}
|
||||
get() = configuration.getList(KonanConfigKeys.LIBRARY_FILES)
|
||||
|
||||
private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES)
|
||||
private val resolver = KonanLibrarySearchPathResolver(repositories, distribution.klib, distribution.localKonanDir)
|
||||
private val librariesFound: List<File> by lazy {
|
||||
val resolvedLibraries = libraryNames.map{it -> resolver.resolve(it)}
|
||||
checkLibraryDuplicates(resolvedLibraries)
|
||||
resolvedLibraries
|
||||
}
|
||||
|
||||
internal val libraries: List<KonanLibraryReader> by lazy {
|
||||
val libraries: List<KonanLibraryReader> by lazy {
|
||||
val target = targetManager.target
|
||||
// Here we have chosen a particular KonanLibraryReader implementation.
|
||||
librariesFound.map{it -> LibraryReaderImpl(it, currentAbiVersion, target)}
|
||||
|
||||
val defaultLibraries = resolver.defaultLinks(
|
||||
configuration.getBoolean(KonanConfigKeys.NOSTDLIB),
|
||||
configuration.getBoolean(KonanConfigKeys.NODEFAULTLIBS)
|
||||
) .map { LibraryReaderImpl(it, currentAbiVersion, target, isDefaultLink=true) }
|
||||
|
||||
val userProvidedLibraries = libraryNames
|
||||
.map { resolver.resolve(it) }
|
||||
.map{ LibraryReaderImpl(it, currentAbiVersion, target) }
|
||||
|
||||
val resolvedLibraries = defaultLibraries + userProvidedLibraries
|
||||
checkLibraryDuplicates(resolvedLibraries.map{it.libraryFile})
|
||||
|
||||
resolvedLibraries
|
||||
}
|
||||
|
||||
private val loadedDescriptors = loadLibMetadata()
|
||||
|
||||
+2
@@ -57,6 +57,8 @@ class KonanConfigKeys {
|
||||
= CompilerConfigurationKey.create("module kind")
|
||||
val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>>
|
||||
= CompilerConfigurationKey.create("native library file paths")
|
||||
val NODEFAULTLIBS: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create("don't link with the default libraries")
|
||||
val NOMAIN: CompilerConfigurationKey<Boolean>
|
||||
= CompilerConfigurationKey.create("assume 'main' entry point to be provided by external libraries")
|
||||
val NOSTDLIB: CompilerConfigurationKey<Boolean>
|
||||
|
||||
+9
-1
@@ -231,7 +231,15 @@ internal class LinkStage(val context: Context) {
|
||||
private val debug = config.get(KonanConfigKeys.DEBUG) ?: false
|
||||
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
|
||||
private val emitted = context.bitcodeFileName
|
||||
private val libraries = context.config.libraries
|
||||
private val libraries = context.config.libraries
|
||||
.map {
|
||||
if (!it.isNeededForLink) {
|
||||
if (!it.isDefaultLink) {
|
||||
context.reportCompilationWarning("The '${it.libraryName}' library has not been referenced. Omitted from the final link.")
|
||||
}
|
||||
null
|
||||
} else it
|
||||
}.filterNotNull()
|
||||
|
||||
private fun MutableList<String>.addNonEmpty(elements: List<String>) {
|
||||
addAll(elements.filter { !it.isEmpty() })
|
||||
|
||||
+2
@@ -26,6 +26,8 @@ interface KonanLibraryReader {
|
||||
val includedPaths: List<String>
|
||||
val linkerOpts: List<String>
|
||||
val escapeAnalysis: ByteArray?
|
||||
val isNeededForLink: Boolean get() = true
|
||||
val isDefaultLink: Boolean get() = false
|
||||
val manifestProperties: Properties
|
||||
fun moduleDescriptor(specifics: LanguageVersionSettings): ModuleDescriptor
|
||||
}
|
||||
|
||||
+15
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.konan.file.File
|
||||
interface SearchPathResolver {
|
||||
val searchRoots: List<File>
|
||||
fun resolve(givenPath: String): File
|
||||
fun defaultLinks(nostdlib: Boolean, noDefaultLibs: Boolean): List<File>
|
||||
}
|
||||
|
||||
class KonanLibrarySearchPathResolver(repositories: List<String>,
|
||||
@@ -72,5 +73,19 @@ class KonanLibrarySearchPathResolver(repositories: List<String>,
|
||||
|
||||
private val File.klib
|
||||
get() = File(this, "klib")
|
||||
|
||||
// The libraries from the default root are linked autimatically.
|
||||
val defaultRoot: File?
|
||||
get() = if (distHead?.exists ?: false) distHead else null
|
||||
|
||||
override fun defaultLinks(nostdlib: Boolean, noDefaultLibs: Boolean): List<File> {
|
||||
val defaultLibs = defaultRoot?.listFiles.orEmpty()
|
||||
.filterNot { it.name.removeSuffixIfPresent(".klib") == "stdlib" }
|
||||
.map { File(it.absolutePath) }
|
||||
val result = mutableListOf<File>()
|
||||
if (!nostdlib) result.add(resolve("stdlib"))
|
||||
if (!noDefaultLibs) result.addAll(defaultLibs)
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+20
-3
@@ -18,13 +18,16 @@ package org.jetbrains.kotlin.backend.konan.library.impl
|
||||
|
||||
import org.jetbrains.kotlin.backend.konan.library.KonanLibraryReader
|
||||
import org.jetbrains.kotlin.backend.konan.createInteropLibrary
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.emptyPackages
|
||||
import org.jetbrains.kotlin.backend.konan.serialization.deserializeModule
|
||||
import org.jetbrains.kotlin.konan.file.File
|
||||
import org.jetbrains.kotlin.konan.properties.*
|
||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
|
||||
class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int, val target: KonanTarget? = null) : KonanLibraryReader {
|
||||
class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int,
|
||||
val target: KonanTarget? = null, override val isDefaultLink: Boolean = false)
|
||||
: KonanLibraryReader {
|
||||
|
||||
// For the zipped libraries inPlace gives files from zip file system
|
||||
// whereas realFiles extracts them to /tmp.
|
||||
@@ -66,8 +69,22 @@ class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int, val t
|
||||
reader.loadSerializedModule()
|
||||
}
|
||||
|
||||
fun packageMetadata(fqName: String): ByteArray =
|
||||
reader.loadSerializedPackageFragment(fqName)
|
||||
override val isNeededForLink: Boolean
|
||||
get() {
|
||||
packagesAccessed.forEach {
|
||||
if (!emptyPackages(moduleHeaderData).contains(it)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
val packagesAccessed = mutableSetOf<String>()
|
||||
|
||||
fun packageMetadata(fqName: String): ByteArray {
|
||||
packagesAccessed.add(fqName)
|
||||
return reader.loadSerializedPackageFragment(fqName)
|
||||
}
|
||||
|
||||
override fun moduleDescriptor(specifics: LanguageVersionSettings)
|
||||
= deserializeModule(specifics, {packageMetadata(it)}, moduleHeaderData, createInteropLibrary(this))
|
||||
|
||||
+2
@@ -76,6 +76,7 @@ message PackageFragment {
|
||||
required string fq_name = 1;
|
||||
required Package package = 4;
|
||||
required Classes classes = 5;
|
||||
required bool is_empty = 6;
|
||||
|
||||
// To construct name resolver
|
||||
required QualifiedNameTable name_table = 2;
|
||||
@@ -91,5 +92,6 @@ message Classes {
|
||||
message Library {
|
||||
required string module_name = 1;
|
||||
repeated string package_fragment_name = 2;
|
||||
repeated string empty_package = 3;
|
||||
}
|
||||
|
||||
|
||||
+9
@@ -119,6 +119,9 @@ public fun parseModuleHeader(libraryData: ByteArray): Library =
|
||||
Library.parseFrom(libraryData,
|
||||
KonanSerializerProtocol.extensionRegistry)
|
||||
|
||||
public fun emptyPackages(libraryData: ByteArray)
|
||||
= parseModuleHeader(libraryData).emptyPackageList
|
||||
|
||||
internal fun deserializeModule(languageVersionSettings: LanguageVersionSettings,
|
||||
packageLoader:(String)->ByteArray, library: ByteArray,
|
||||
interopLibrary: InteropLibrary?): ModuleDescriptorImpl {
|
||||
@@ -220,6 +223,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
val strings = serializerExtension.stringTable
|
||||
val (stringTableProto, nameTableProto) = strings.buildProto()
|
||||
|
||||
val isEmpty = members.isEmpty() && classifierDescriptors.isEmpty()
|
||||
val fragmentBuilder = KonanLinkData.PackageFragment.newBuilder()
|
||||
|
||||
val fragmentProto = fragmentBuilder
|
||||
@@ -228,6 +232,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
.setClasses(classesProto)
|
||||
.setStringTable(stringTableProto)
|
||||
.setNameTable(nameTableProto)
|
||||
.setIsEmpty(isEmpty)
|
||||
.build()
|
||||
|
||||
return fragmentProto
|
||||
@@ -251,6 +256,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun serializeModule(moduleDescriptor: ModuleDescriptor): LinkData {
|
||||
val libraryProto = KonanLinkData.Library.newBuilder()
|
||||
libraryProto.moduleName = moduleDescriptor.name.asString()
|
||||
@@ -262,6 +268,9 @@ internal class KonanSerializationUtil(val context: Context) {
|
||||
if (packageProto == null) return@iteration
|
||||
|
||||
libraryProto.addPackageFragmentName(it.asString())
|
||||
if (packageProto.isEmpty) {
|
||||
libraryProto.addEmptyPackage(it.asString())
|
||||
}
|
||||
fragments.add(packageProto.toByteArray())
|
||||
fragmentNames.add(it.asString())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user