diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt index 74d18d45bfe..0d2863c7f69 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2Native.kt @@ -298,6 +298,15 @@ class K2Native : CLICompiler() { configuration.report(ERROR, "-Xgc-aggressive is only supported for -memory-model experimental") } 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 + } + }) } } } diff --git a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt index 66c94c38d16..947f443d8c7 100644 --- a/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt +++ b/kotlin-native/backend.native/cli.bc/src/org/jetbrains/kotlin/cli/bc/K2NativeCompilerArguments.kt @@ -314,6 +314,13 @@ class K2NativeCompilerArguments : CommonCompilerArguments() { @Argument(value="-Xgc-aggressive", description = "Make GC agressive. Works only with -memory-model experimental") 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, Any> = super.configureAnalysisFlags(collector, languageVersion).also { val useExperimental = it[AnalysisFlags.useExperimental] as List<*> diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt index 442a1348497..2a50bb67d43 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/KonanConfigurationKeys.kt @@ -158,6 +158,7 @@ class KonanConfigKeys { = CompilerConfigurationKey.create("when to destroy runtime") val GARBAGE_COLLECTOR: CompilerConfigurationKey = CompilerConfigurationKey.create("gc") val GARBAGE_COLLECTOR_AGRESSIVE: CompilerConfigurationKey = CompilerConfigurationKey.create("turn on agressive GC mode") + val CHECK_LLD_COMPATIBILITY: CompilerConfigurationKey = CompilerConfigurationKey.create("check compatibility with LLD") } } diff --git a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt index 9c536afb26a..fe23c3c51c3 100644 --- a/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt +++ b/kotlin-native/backend.native/compiler/ir/backend.native/src/org/jetbrains/kotlin/backend/konan/Linker.kt @@ -145,6 +145,8 @@ internal class Linker(val context: Context) { BitcodeEmbedding.getLinkerOptions(context.config) + linkerInput.caches.dynamic + libraryProvidedLinkerFlags + additionalLinkerArgs + + checkLldCompatibility() val finalOutputCommands = linker.finalLinkCommands( objectFiles = linkerInput.objectFiles, executable = executable, @@ -176,6 +178,23 @@ internal class Linker(val context: Context) { 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 { // Pre-link is only useful when producing static library. Otherwise its just a waste of time. val isStaticLibrary = linkerOutputKind == LinkerOutputKind.STATIC_LIBRARY && diff --git a/kotlin-native/konan/konan.properties b/kotlin-native/konan/konan.properties index 59972af1880..014a00d01c5 100644 --- a/kotlin-native/konan/konan.properties +++ b/kotlin-native/konan/konan.properties @@ -868,12 +868,14 @@ runtimeDefinitions.android_x64 = __ANDROID__ USE_GCC_UNWIND=1 USE_ELF_SYMBOLS=1 llvmHome.mingw_x64 = $llvm.mingw_x64.dev 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 +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.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 dependencies.mingw_x64 = \ - lldb-2-windows + lldb-2-windows \ + lld-11.1.0-windows-x64 targetTriple.mingw_x64 = x86_64-pc-windows-gnu 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. 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 = \ - 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.macos_x64-mingw_x86 = msys2-mingw-w64-i686-clang-llvm-lld-compiler_rt-8.0.1 dependencies.linux_x64-mingw_x86 = \ @@ -924,7 +928,7 @@ linkerDynamicFlags.mingw_x86 = -shared linkerKonanFlags.mingw_x86 = -static-libgcc -static-libstdc++ \ -Wl,--dynamicbase \ -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 linkerOptimizationFlags.mingw_x86 = -Wl,--gc-sections runtimeDefinitions.mingw_x86 = USE_GCC_UNWIND=1 USE_PE_COFF_SYMBOLS=1 KONAN_WINDOWS=1 \ diff --git a/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Configurables.kt b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Configurables.kt index 8b1ba264aa0..92e2a0b8c2b 100644 --- a/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Configurables.kt +++ b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Configurables.kt @@ -104,7 +104,10 @@ interface AppleConfigurables : Configurables, ClangFlags { 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 { val gccToolchain get() = targetString("gccToolchain") diff --git a/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Linker.kt b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Linker.kt index 11b057dd0db..37247e0e099 100644 --- a/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Linker.kt +++ b/kotlin-native/shared/src/main/kotlin/org/jetbrains/kotlin/konan/target/Linker.kt @@ -438,6 +438,11 @@ class MingwLinker(targetProperties: MingwConfigurables) 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, executable: ExecutableFile, libraries: List, linkerArgs: List, optimize: Boolean, debug: Boolean, @@ -451,10 +456,11 @@ class MingwLinker(targetProperties: MingwConfigurables) return staticGnuArCommands(ar, executable, objectFiles, libraries) val dynamic = kind == LinkerOutputKind.DYNAMIC_LIBRARY - return listOf(when { - HostManager.hostIsMingw -> Command(linker) - else -> Command("wine64", "$linker.exe") - }.apply { + + fun Command.constructLinkerArguments( + additionalArguments: List = listOf(), + skipDefaultArguments: List = listOf() + ): Command = apply { +listOf("-o", executable) +objectFiles // --gc-sections flag may affect profiling. @@ -466,9 +472,28 @@ class MingwLinker(targetProperties: MingwConfigurables) +libraries if (needsProfileLibrary) +profileLibrary!! +linkerArgs - +linkerKonanFlags + +linkerKonanFlags.filterNot { it in skipDefaultArguments } 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()) } }