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(KonanConfigKeys) {
|
||||||
with(configuration) {
|
with(configuration) {
|
||||||
|
|
||||||
|
put(NODEFAULTLIBS, arguments.nodefaultlibs)
|
||||||
put(NOSTDLIB, arguments.nostdlib)
|
put(NOSTDLIB, arguments.nostdlib)
|
||||||
put(NOPACK, arguments.nopack)
|
put(NOPACK, arguments.nopack)
|
||||||
put(NOMAIN, arguments.nomain)
|
put(NOMAIN, arguments.nomain)
|
||||||
|
|||||||
@@ -48,6 +48,9 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
|
|||||||
@Argument(value = "-nativelibrary", shortName = "-nl", valueDescription = "<path>", description = "Include the native bitcode library")
|
@Argument(value = "-nativelibrary", shortName = "-nl", valueDescription = "<path>", description = "Include the native bitcode library")
|
||||||
var nativeLibraries: Array<String>? = null
|
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")
|
@Argument(value = "-nomain", description = "Assume 'main' entry point to be provided by external libraries")
|
||||||
var nomain: Boolean = false
|
var nomain: Boolean = false
|
||||||
|
|
||||||
|
|||||||
+16
-16
@@ -75,26 +75,26 @@ class KonanConfig(val project: Project, val configuration: CompilerConfiguration
|
|||||||
get() = outputName
|
get() = outputName
|
||||||
|
|
||||||
private val libraryNames: List<String>
|
private val libraryNames: List<String>
|
||||||
get() {
|
get() = configuration.getList(KonanConfigKeys.LIBRARY_FILES)
|
||||||
val fromCommandLine = configuration.getList(KonanConfigKeys.LIBRARY_FILES)
|
|
||||||
if (configuration.get(KonanConfigKeys.NOSTDLIB) ?: false) {
|
|
||||||
return fromCommandLine
|
|
||||||
}
|
|
||||||
return fromCommandLine + "stdlib"
|
|
||||||
}
|
|
||||||
|
|
||||||
private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES)
|
private val repositories = configuration.getList(KonanConfigKeys.REPOSITORIES)
|
||||||
private val resolver = KonanLibrarySearchPathResolver(repositories, distribution.klib, distribution.localKonanDir)
|
private val resolver = KonanLibrarySearchPathResolver(repositories, distribution.klib, distribution.localKonanDir)
|
||||||
private val librariesFound: List<File> by lazy {
|
val libraries: List<KonanLibraryReader> by lazy {
|
||||||
val resolvedLibraries = libraryNames.map{it -> resolver.resolve(it)}
|
|
||||||
checkLibraryDuplicates(resolvedLibraries)
|
|
||||||
resolvedLibraries
|
|
||||||
}
|
|
||||||
|
|
||||||
internal val libraries: List<KonanLibraryReader> by lazy {
|
|
||||||
val target = targetManager.target
|
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()
|
private val loadedDescriptors = loadLibMetadata()
|
||||||
|
|||||||
+2
@@ -57,6 +57,8 @@ class KonanConfigKeys {
|
|||||||
= CompilerConfigurationKey.create("module kind")
|
= CompilerConfigurationKey.create("module kind")
|
||||||
val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>>
|
val NATIVE_LIBRARY_FILES: CompilerConfigurationKey<List<String>>
|
||||||
= CompilerConfigurationKey.create("native library file paths")
|
= CompilerConfigurationKey.create("native library file paths")
|
||||||
|
val NODEFAULTLIBS: CompilerConfigurationKey<Boolean>
|
||||||
|
= CompilerConfigurationKey.create("don't link with the default libraries")
|
||||||
val NOMAIN: CompilerConfigurationKey<Boolean>
|
val NOMAIN: CompilerConfigurationKey<Boolean>
|
||||||
= CompilerConfigurationKey.create("assume 'main' entry point to be provided by external libraries")
|
= CompilerConfigurationKey.create("assume 'main' entry point to be provided by external libraries")
|
||||||
val NOSTDLIB: CompilerConfigurationKey<Boolean>
|
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 debug = config.get(KonanConfigKeys.DEBUG) ?: false
|
||||||
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
|
private val nomain = config.get(KonanConfigKeys.NOMAIN) ?: false
|
||||||
private val emitted = context.bitcodeFileName
|
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>) {
|
private fun MutableList<String>.addNonEmpty(elements: List<String>) {
|
||||||
addAll(elements.filter { !it.isEmpty() })
|
addAll(elements.filter { !it.isEmpty() })
|
||||||
|
|||||||
+2
@@ -26,6 +26,8 @@ interface KonanLibraryReader {
|
|||||||
val includedPaths: List<String>
|
val includedPaths: List<String>
|
||||||
val linkerOpts: List<String>
|
val linkerOpts: List<String>
|
||||||
val escapeAnalysis: ByteArray?
|
val escapeAnalysis: ByteArray?
|
||||||
|
val isNeededForLink: Boolean get() = true
|
||||||
|
val isDefaultLink: Boolean get() = false
|
||||||
val manifestProperties: Properties
|
val manifestProperties: Properties
|
||||||
fun moduleDescriptor(specifics: LanguageVersionSettings): ModuleDescriptor
|
fun moduleDescriptor(specifics: LanguageVersionSettings): ModuleDescriptor
|
||||||
}
|
}
|
||||||
|
|||||||
+15
@@ -23,6 +23,7 @@ import org.jetbrains.kotlin.konan.file.File
|
|||||||
interface SearchPathResolver {
|
interface SearchPathResolver {
|
||||||
val searchRoots: List<File>
|
val searchRoots: List<File>
|
||||||
fun resolve(givenPath: String): File
|
fun resolve(givenPath: String): File
|
||||||
|
fun defaultLinks(nostdlib: Boolean, noDefaultLibs: Boolean): List<File>
|
||||||
}
|
}
|
||||||
|
|
||||||
class KonanLibrarySearchPathResolver(repositories: List<String>,
|
class KonanLibrarySearchPathResolver(repositories: List<String>,
|
||||||
@@ -72,5 +73,19 @@ class KonanLibrarySearchPathResolver(repositories: List<String>,
|
|||||||
|
|
||||||
private val File.klib
|
private val File.klib
|
||||||
get() = File(this, "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.library.KonanLibraryReader
|
||||||
import org.jetbrains.kotlin.backend.konan.createInteropLibrary
|
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.backend.konan.serialization.deserializeModule
|
||||||
import org.jetbrains.kotlin.konan.file.File
|
import org.jetbrains.kotlin.konan.file.File
|
||||||
import org.jetbrains.kotlin.konan.properties.*
|
import org.jetbrains.kotlin.konan.properties.*
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
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
|
// For the zipped libraries inPlace gives files from zip file system
|
||||||
// whereas realFiles extracts them to /tmp.
|
// whereas realFiles extracts them to /tmp.
|
||||||
@@ -66,8 +69,22 @@ class LibraryReaderImpl(var libraryFile: File, val currentAbiVersion: Int, val t
|
|||||||
reader.loadSerializedModule()
|
reader.loadSerializedModule()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun packageMetadata(fqName: String): ByteArray =
|
override val isNeededForLink: Boolean
|
||||||
reader.loadSerializedPackageFragment(fqName)
|
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)
|
override fun moduleDescriptor(specifics: LanguageVersionSettings)
|
||||||
= deserializeModule(specifics, {packageMetadata(it)}, moduleHeaderData, createInteropLibrary(this))
|
= deserializeModule(specifics, {packageMetadata(it)}, moduleHeaderData, createInteropLibrary(this))
|
||||||
|
|||||||
+2
@@ -76,6 +76,7 @@ message PackageFragment {
|
|||||||
required string fq_name = 1;
|
required string fq_name = 1;
|
||||||
required Package package = 4;
|
required Package package = 4;
|
||||||
required Classes classes = 5;
|
required Classes classes = 5;
|
||||||
|
required bool is_empty = 6;
|
||||||
|
|
||||||
// To construct name resolver
|
// To construct name resolver
|
||||||
required QualifiedNameTable name_table = 2;
|
required QualifiedNameTable name_table = 2;
|
||||||
@@ -91,5 +92,6 @@ message Classes {
|
|||||||
message Library {
|
message Library {
|
||||||
required string module_name = 1;
|
required string module_name = 1;
|
||||||
repeated string package_fragment_name = 2;
|
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,
|
Library.parseFrom(libraryData,
|
||||||
KonanSerializerProtocol.extensionRegistry)
|
KonanSerializerProtocol.extensionRegistry)
|
||||||
|
|
||||||
|
public fun emptyPackages(libraryData: ByteArray)
|
||||||
|
= parseModuleHeader(libraryData).emptyPackageList
|
||||||
|
|
||||||
internal fun deserializeModule(languageVersionSettings: LanguageVersionSettings,
|
internal fun deserializeModule(languageVersionSettings: LanguageVersionSettings,
|
||||||
packageLoader:(String)->ByteArray, library: ByteArray,
|
packageLoader:(String)->ByteArray, library: ByteArray,
|
||||||
interopLibrary: InteropLibrary?): ModuleDescriptorImpl {
|
interopLibrary: InteropLibrary?): ModuleDescriptorImpl {
|
||||||
@@ -220,6 +223,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
|||||||
val strings = serializerExtension.stringTable
|
val strings = serializerExtension.stringTable
|
||||||
val (stringTableProto, nameTableProto) = strings.buildProto()
|
val (stringTableProto, nameTableProto) = strings.buildProto()
|
||||||
|
|
||||||
|
val isEmpty = members.isEmpty() && classifierDescriptors.isEmpty()
|
||||||
val fragmentBuilder = KonanLinkData.PackageFragment.newBuilder()
|
val fragmentBuilder = KonanLinkData.PackageFragment.newBuilder()
|
||||||
|
|
||||||
val fragmentProto = fragmentBuilder
|
val fragmentProto = fragmentBuilder
|
||||||
@@ -228,6 +232,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
|||||||
.setClasses(classesProto)
|
.setClasses(classesProto)
|
||||||
.setStringTable(stringTableProto)
|
.setStringTable(stringTableProto)
|
||||||
.setNameTable(nameTableProto)
|
.setNameTable(nameTableProto)
|
||||||
|
.setIsEmpty(isEmpty)
|
||||||
.build()
|
.build()
|
||||||
|
|
||||||
return fragmentProto
|
return fragmentProto
|
||||||
@@ -251,6 +256,7 @@ internal class KonanSerializationUtil(val context: Context) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal fun serializeModule(moduleDescriptor: ModuleDescriptor): LinkData {
|
internal fun serializeModule(moduleDescriptor: ModuleDescriptor): LinkData {
|
||||||
val libraryProto = KonanLinkData.Library.newBuilder()
|
val libraryProto = KonanLinkData.Library.newBuilder()
|
||||||
libraryProto.moduleName = moduleDescriptor.name.asString()
|
libraryProto.moduleName = moduleDescriptor.name.asString()
|
||||||
@@ -262,6 +268,9 @@ internal class KonanSerializationUtil(val context: Context) {
|
|||||||
if (packageProto == null) return@iteration
|
if (packageProto == null) return@iteration
|
||||||
|
|
||||||
libraryProto.addPackageFragmentName(it.asString())
|
libraryProto.addPackageFragmentName(it.asString())
|
||||||
|
if (packageProto.isEmpty) {
|
||||||
|
libraryProto.addEmptyPackage(it.asString())
|
||||||
|
}
|
||||||
fragments.add(packageProto.toByteArray())
|
fragments.add(packageProto.toByteArray())
|
||||||
fragmentNames.add(it.asString())
|
fragmentNames.add(it.asString())
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user