diff --git a/kotlin-native/konan/konan.properties b/kotlin-native/konan/konan.properties index 2cf15c30200e9..42ff27c96d703 100644 --- a/kotlin-native/konan/konan.properties +++ b/kotlin-native/konan/konan.properties @@ -89,7 +89,7 @@ cacheableTargets.macos_arm64 = \ # Targets that support compiler caches, but these caches # are not considered stable enough to be turned on by default. optInCacheableTargets = - +linkerStaticSortingRegexFlags = --use-group # Mac OS X. # Can be an absolute path instead of predefined value. llvmHome.macos_x64 = $llvm.macos_x64.dev diff --git a/native/utils/src/org/jetbrains/kotlin/konan/target/Configurables.kt b/native/utils/src/org/jetbrains/kotlin/konan/target/Configurables.kt index f19a37f9ade9e..0818a51b1dc93 100644 --- a/native/utils/src/org/jetbrains/kotlin/konan/target/Configurables.kt +++ b/native/utils/src/org/jetbrains/kotlin/konan/target/Configurables.kt @@ -66,6 +66,7 @@ interface Configurables : TargetableExternalStorage, RelocationModeFlags { // TODO: Delegate to a map? val linkerOptimizationFlags get() = targetList("linkerOptimizationFlags") + val linkerStaticSortingRegexFlags get() = targetList("linkerStaticSortingRegexFlags") val linkerKonanFlags get() = targetList("linkerKonanFlags") val linkerNoDebugFlags get() = targetList("linkerNoDebugFlags") val linkerDynamicFlags get() = targetList("linkerDynamicFlags") @@ -83,6 +84,26 @@ interface Configurables : TargetableExternalStorage, RelocationModeFlags { val llvmInlineThreshold get() = targetString("llvmInlineThreshold") val runtimeDefinitions get() = targetList("runtimeDefinitions") + + fun toSortingRegex(): List> { + return linkerStaticSortingRegexFlags + .flatMap { flag -> + flag.split('&') // split 0@aaa&1@bbb into [0@aaa, 1@bbb] + }.mapNotNull { rule -> + rule.split('@', limit = 2).takeIf { parts -> + parts.size == 2 // must include delimiter + }?.let { (orderStr, regexStr) -> + // convert to int and compile regular expressions + orderStr.toIntOrNull()?.let { order -> + try { + order to Regex(regexStr) + } catch (e: Exception) { + null // 忽略无效正则 + } + } + } + } + } } interface ConfigurablesWithEmulator : Configurables { diff --git a/native/utils/src/org/jetbrains/kotlin/konan/target/Linker.kt b/native/utils/src/org/jetbrains/kotlin/konan/target/Linker.kt index aba91941e7dad..5118f97f5ffff 100644 --- a/native/utils/src/org/jetbrains/kotlin/konan/target/Linker.kt +++ b/native/utils/src/org/jetbrains/kotlin/konan/target/Linker.kt @@ -429,7 +429,37 @@ class GccBasedLinker(targetProperties: GccConfigurables) +provideCompilerRtLibrary("tsan_cxx")!! } } - +libraries + // the static libraries have order dependency, so we need to put them in the correct order, + // from left to right + // the order is defined by the linkerStaticSortingRegexFlags, which is a list of strings in the form of + // type1: "order@regex&order@regex&..." + // type2: "--whole-archive" + // type3: "--use-group" + // start of the static libraries + // 1. use --whole-archive + // 2. use --start-group + +linkerStaticSortingRegexFlags.contains("--whole-archive").let { + if (it) listOf("--whole-archive")+libraries else if (linkerStaticSortingRegexFlags.contains("--use-group")) listOf("--start-group")+libraries else { + // get the regex rules sorted by order + val regexRules = toSortingRegex().sortedBy { it.first } + // collect all matched libraries, group by order + val matchedLibraries = regexRules.flatMap { (_/*order*/, regex) -> libraries.filter { it.matches(regex) } } + // collect unmatched libraries, keep the original order + val remainingLibraries = libraries.filterNot { lib -> matchedLibraries.contains(lib) } + // merge sorted and unmatched libraries + matchedLibraries + remainingLibraries + } + } + // +libraries commented out because it is already included in the linkerStaticSortingRegexFlags + // 1. use --no-whole-archive + // 2. use --end-group + +linkerStaticSortingRegexFlags.contains("--whole-archive").let { + if (it) listOf("--no-whole-archive") else if (linkerStaticSortingRegexFlags.contains("--use-group")) listOf("--end-group") else { + // in this case we don't need to do anything + emptyList() + } + } + // end of the static libraries +linkerArgs // See explanation about `-u__llvm_profile_runtime` here: // https://github.com/llvm/llvm-project/blob/21e270a479a24738d641e641115bce6af6ed360a/llvm/lib/Transforms/Instrumentation/InstrProfiling.cpp#L930