[K/N] Introduce LLD compatibility checker for MinGW

We are going to switch to LLD linker for MinGW targets.
Right now LLD for MinGW doesn't support all features
of ld.bfd and thus this change might be breaking for some users.
To make transition smoother, we run lld -### to show a warning to user
so they can update their compilation options before LLD will be turned
on by default.

More details: https://youtrack.jetbrains.com/issue/KT-47605
This commit is contained in:
Sergey Bogolepov
2021-07-06 14:53:59 +07:00
committed by Space
parent 30d0fea003
commit 9ed97a27f1
7 changed files with 78 additions and 10 deletions
@@ -298,6 +298,15 @@ class K2Native : CLICompiler<K2NativeCompilerArguments>() {
configuration.report(ERROR, "-Xgc-aggressive is only supported for -memory-model experimental") configuration.report(ERROR, "-Xgc-aggressive is only supported for -memory-model experimental")
} }
put(GARBAGE_COLLECTOR_AGRESSIVE, arguments.gcAggressive) put(GARBAGE_COLLECTOR_AGRESSIVE, arguments.gcAggressive)
put(CHECK_LLD_COMPATIBILITY, when (val it = arguments.checkLldCompatibility) {
"enable" -> true
"disable" -> false
null -> true
else -> {
configuration.report(ERROR, "Unsupported '-Xcheck-compatibility-with-lld' value: $it. Possible values are 'enable'/'disable'")
true
}
})
} }
} }
} }
@@ -314,6 +314,13 @@ class K2NativeCompilerArguments : CommonCompilerArguments() {
@Argument(value="-Xgc-aggressive", description = "Make GC agressive. Works only with -memory-model experimental") @Argument(value="-Xgc-aggressive", description = "Make GC agressive. Works only with -memory-model experimental")
var gcAggressive: Boolean = false var gcAggressive: Boolean = false
@Argument(
value = "-Xcheck-compatibility-with-lld",
valueDescription = "{disable|enable}",
description = "Check that linker flags are compatible with LLD."
)
var checkLldCompatibility: String? = null
override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> = override fun configureAnalysisFlags(collector: MessageCollector, languageVersion: LanguageVersion): MutableMap<AnalysisFlag<*>, Any> =
super.configureAnalysisFlags(collector, languageVersion).also { super.configureAnalysisFlags(collector, languageVersion).also {
val useExperimental = it[AnalysisFlags.useExperimental] as List<*> val useExperimental = it[AnalysisFlags.useExperimental] as List<*>
@@ -158,6 +158,7 @@ class KonanConfigKeys {
= CompilerConfigurationKey.create("when to destroy runtime") = CompilerConfigurationKey.create("when to destroy runtime")
val GARBAGE_COLLECTOR: CompilerConfigurationKey<GC> = CompilerConfigurationKey.create("gc") val GARBAGE_COLLECTOR: CompilerConfigurationKey<GC> = CompilerConfigurationKey.create("gc")
val GARBAGE_COLLECTOR_AGRESSIVE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("turn on agressive GC mode") val GARBAGE_COLLECTOR_AGRESSIVE: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("turn on agressive GC mode")
val CHECK_LLD_COMPATIBILITY: CompilerConfigurationKey<Boolean> = CompilerConfigurationKey.create("check compatibility with LLD")
} }
} }
@@ -145,6 +145,8 @@ internal class Linker(val context: Context) {
BitcodeEmbedding.getLinkerOptions(context.config) + BitcodeEmbedding.getLinkerOptions(context.config) +
linkerInput.caches.dynamic + linkerInput.caches.dynamic +
libraryProvidedLinkerFlags + additionalLinkerArgs libraryProvidedLinkerFlags + additionalLinkerArgs
checkLldCompatibility()
val finalOutputCommands = linker.finalLinkCommands( val finalOutputCommands = linker.finalLinkCommands(
objectFiles = linkerInput.objectFiles, objectFiles = linkerInput.objectFiles,
executable = executable, executable = executable,
@@ -176,6 +178,23 @@ internal class Linker(val context: Context) {
return executable return executable
} }
private fun checkLldCompatibility() {
if (linker is MingwLinker && config.getBoolean(KonanConfigKeys.CHECK_LLD_COMPATIBILITY)) {
linker.lldCompatibilityChecker = { command ->
command.logWith(context::log)
val result = command.getResult(withErrors = true)
if (result.exitCode != 0) {
val message = """
Kotlin/Native will switch from ld to LLD linker in future releases and this warning will become an error.
See https://youtrack.jetbrains.com/issue/KT-47605 for details.
${result.outputLines.joinToString("\n")}
""".lineSequence().map { it.trim() }.joinToString("\n")
context.reportCompilationWarning(message)
}
}
}
}
private fun shouldPerformPreLink(caches: CachesToLink, linkerOutputKind: LinkerOutputKind): Boolean { private fun shouldPerformPreLink(caches: CachesToLink, linkerOutputKind: LinkerOutputKind): Boolean {
// Pre-link is only useful when producing static library. Otherwise its just a waste of time. // Pre-link is only useful when producing static library. Otherwise its just a waste of time.
val isStaticLibrary = linkerOutputKind == LinkerOutputKind.STATIC_LIBRARY && val isStaticLibrary = linkerOutputKind == LinkerOutputKind.STATIC_LIBRARY &&
+7 -3
View File
@@ -868,12 +868,14 @@ runtimeDefinitions.android_x64 = __ANDROID__ USE_GCC_UNWIND=1 USE_ELF_SYMBOLS=1
llvmHome.mingw_x64 = $llvm.mingw_x64.dev llvmHome.mingw_x64 = $llvm.mingw_x64.dev
targetToolchain.mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1 targetToolchain.mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1
libffiDir.mingw_x64 = libffi-3.2.1-mingw-w64-x86-64 libffiDir.mingw_x64 = libffi-3.2.1-mingw-w64-x86-64
lldLocation.mingw_x64 = lld-11.1.0-windows-x64/ld.lld.exe
targetToolchain.linux_x64-mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1 targetToolchain.linux_x64-mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1
targetToolchain.macos_x64-mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1 targetToolchain.macos_x64-mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1
# for Windows we are currently using LLDB 9 # for Windows we are currently using LLDB 9
dependencies.mingw_x64 = \ dependencies.mingw_x64 = \
lldb-2-windows lldb-2-windows \
lld-11.1.0-windows-x64
targetTriple.mingw_x64 = x86_64-pc-windows-gnu targetTriple.mingw_x64 = x86_64-pc-windows-gnu
targetSysRoot.mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1 targetSysRoot.mingw_x64 = msys2-mingw-w64-x86_64-clang-llvm-lld-compiler_rt-8.0.1
@@ -897,8 +899,10 @@ runtimeDefinitions.mingw_x64 = USE_GCC_UNWIND=1 USE_PE_COFF_SYMBOLS=1 KONAN_WIND
# Windows i686, based on mingw-w64. # Windows i686, based on mingw-w64.
targetToolchain.mingw_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1 targetToolchain.mingw_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1
lldLocation.mingw_x86 = lld-11.1.0-windows-x64/ld.lld.exe
dependencies.mingw_x64-mingw_x86 = \ dependencies.mingw_x64-mingw_x86 = \
msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1 msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1 \
lld-11.1.0-windows-x64
targetToolchain.linux_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1 targetToolchain.linux_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1
targetToolchain.macos_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1 targetToolchain.macos_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1
dependencies.linux_x64-mingw_x86 = \ dependencies.linux_x64-mingw_x86 = \
@@ -924,7 +928,7 @@ linkerDynamicFlags.mingw_x86 = -shared
linkerKonanFlags.mingw_x86 = -static-libgcc -static-libstdc++ \ linkerKonanFlags.mingw_x86 = -static-libgcc -static-libstdc++ \
-Wl,--dynamicbase \ -Wl,--dynamicbase \
-Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic \ -Wl,-Bstatic,--whole-archive -lwinpthread -Wl,--no-whole-archive,-Bdynamic \
-Wl,--defsym,___cxa_demangle=_Konan_cxa_demangle -Wl,--defsym,__cxa_demangle=Konan_cxa_demangle
mimallocLinkerDependencies.mingw_x86 = -lbcrypt mimallocLinkerDependencies.mingw_x86 = -lbcrypt
linkerOptimizationFlags.mingw_x86 = -Wl,--gc-sections linkerOptimizationFlags.mingw_x86 = -Wl,--gc-sections
runtimeDefinitions.mingw_x86 = USE_GCC_UNWIND=1 USE_PE_COFF_SYMBOLS=1 KONAN_WINDOWS=1 \ runtimeDefinitions.mingw_x86 = USE_GCC_UNWIND=1 USE_PE_COFF_SYMBOLS=1 KONAN_WINDOWS=1 \
@@ -104,7 +104,10 @@ interface AppleConfigurables : Configurables, ClangFlags {
val absoluteAdditionalToolsDir get() = absolute(additionalToolsDir) val absoluteAdditionalToolsDir get() = absolute(additionalToolsDir)
} }
interface MingwConfigurables : Configurables, ClangFlags interface MingwConfigurables : Configurables, ClangFlags {
val lldLocation get() = targetString("lldLocation")!!
val absoluteLldLocation get() = absolute(lldLocation)
}
interface GccConfigurables : Configurables, ClangFlags { interface GccConfigurables : Configurables, ClangFlags {
val gccToolchain get() = targetString("gccToolchain") val gccToolchain get() = targetString("gccToolchain")
@@ -438,6 +438,11 @@ class MingwLinker(targetProperties: MingwConfigurables)
return if (dir != null) "$dir/lib/windows/libclang_rt.$libraryName-$targetSuffix.a" else null return if (dir != null) "$dir/lib/windows/libclang_rt.$libraryName-$targetSuffix.a" else null
} }
/**
* Handle to command that runs LLD -### (i.e. without actual linkage) with arguments from [finalLinkCommands].
*/
var lldCompatibilityChecker: ((Command) -> Unit)? = null
override fun finalLinkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile, override fun finalLinkCommands(objectFiles: List<ObjectFile>, executable: ExecutableFile,
libraries: List<String>, linkerArgs: List<String>, libraries: List<String>, linkerArgs: List<String>,
optimize: Boolean, debug: Boolean, optimize: Boolean, debug: Boolean,
@@ -451,10 +456,11 @@ class MingwLinker(targetProperties: MingwConfigurables)
return staticGnuArCommands(ar, executable, objectFiles, libraries) return staticGnuArCommands(ar, executable, objectFiles, libraries)
val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY
return listOf(when {
HostManager.hostIsMingw -> Command(linker) fun Command.constructLinkerArguments(
else -> Command("wine64", "$linker.exe") additionalArguments: List<String> = listOf(),
}.apply { skipDefaultArguments: List<String> = listOf()
): Command = apply {
+listOf("-o", executable) +listOf("-o", executable)
+objectFiles +objectFiles
// --gc-sections flag may affect profiling. // --gc-sections flag may affect profiling.
@@ -466,9 +472,28 @@ class MingwLinker(targetProperties: MingwConfigurables)
+libraries +libraries
if (needsProfileLibrary) +profileLibrary!! if (needsProfileLibrary) +profileLibrary!!
+linkerArgs +linkerArgs
+linkerKonanFlags +linkerKonanFlags.filterNot { it in skipDefaultArguments }
if (mimallocEnabled) +mimallocLinkerDependencies if (mimallocEnabled) +mimallocLinkerDependencies
}) +additionalArguments
}
if (HostManager.hostIsMingw) {
lldCompatibilityChecker?.let { checkLldCompatibiity ->
// -### flag allows to avoid actual linkage process.
val lldCommand = Command(linker).constructLinkerArguments(
// Add -fuse-ld to the end of the list to override previous appearances.
additionalArguments = listOf("-fuse-ld=$absoluteLldLocation", "-Wl,-###"),
// LLD doesn't support defsym.
skipDefaultArguments = listOf("-Wl,--defsym,__cxa_demangle=Konan_cxa_demangle")
)
checkLldCompatibiity(lldCommand)
}
}
return listOf(when {
HostManager.hostIsMingw -> Command(linker)
else -> Command("wine64", "$linker.exe")
}.constructLinkerArguments())
} }
} }