diff --git a/lld/MachO/Driver.cpp b/lld/MachO/Driver.cpp --- a/lld/MachO/Driver.cpp +++ b/lld/MachO/Driver.cpp @@ -1355,8 +1355,10 @@ } static void handleExplicitExports() { + static constexpr int kMaxWarnings = 3; if (config->hasExplicitExports) { - parallelForEach(symtab->getSymbols(), [](Symbol *sym) { + std::atomic warningsCount{0}; + parallelForEach(symtab->getSymbols(), [&warningsCount](Symbol *sym) { if (auto *defined = dyn_cast(sym)) { if (config->exportedSymbols.match(sym->getName())) { if (defined->privateExtern) { @@ -1367,8 +1369,12 @@ // The former can be exported but the latter cannot. defined->privateExtern = false; } else { - warn("cannot export hidden symbol " + toString(*defined) + - "\n>>> defined in " + toString(defined->getFile())); + // Only print the first 3 warnings verbosely, and + // shorten the rest to avoid crowding logs. + if (warningsCount.fetch_add(1, std::memory_order_relaxed) < + kMaxWarnings) + warn("cannot export hidden symbol " + toString(*defined) + + "\n>>> defined in " + toString(defined->getFile())); } } } else { @@ -1378,6 +1384,9 @@ dysym->shouldReexport = config->exportedSymbols.match(sym->getName()); } }); + if (warningsCount > kMaxWarnings) + warn("<... " + Twine(warningsCount - kMaxWarnings) + + " more similar warnings...>"); } else if (!config->unexportedSymbols.empty()) { parallelForEach(symtab->getSymbols(), [](Symbol *sym) { if (auto *defined = dyn_cast(sym)) diff --git a/lld/test/MachO/export-options.s b/lld/test/MachO/export-options.s --- a/lld/test/MachO/export-options.s +++ b/lld/test/MachO/export-options.s @@ -4,6 +4,7 @@ # RUN: echo "" | llvm-mc -filetype=obj -triple=x86_64-apple-macos -o %t/empty.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/default.s -o %t/default.o # RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/lazydef.s -o %t/lazydef.o +# RUN: llvm-mc -filetype=obj -triple=x86_64-apple-macos %t/too-many-warnings.s -o %t/too-many-warnings.o # RUN: llvm-ar --format=darwin rcs %t/lazydef.a %t/lazydef.o ## Check that mixing exported and unexported symbol options yields an error @@ -209,6 +210,17 @@ # RUN: llvm-objdump --macho --exports-trie %t/unexport-dylib | FileCheck %s \ # RUN: --check-prefix=EMPTY-TRIE +## Check that warnings are truncated to the first 3 only. +# RUN: %no-fatal-warnings-lld -dylib %t/too-many-warnings.o -o %t/too-many.out \ +# RUN: -exported_symbol "_private_extern*" 2>&1 | \ +# RUN: FileCheck --check-prefix=TRUNCATE %s + +# TRUNCATE: warning: cannot export hidden symbol _private_extern{{.+}} +# TRUNCATE: warning: cannot export hidden symbol _private_extern{{.+}} +# TRUNCATE: warning: cannot export hidden symbol _private_extern{{.+}} +# TRUNCATE: warning: <... 7 more similar warnings...> +# TRUNCATE-EMPTY: + #--- default.s .globl _keep_globl, _hide_globl, _tlv @@ -283,3 +295,45 @@ .private_extern _foo _foo: retq + +#--- too-many-warnings.s +.private_extern _private_extern1 +.private_extern _private_extern2 +.private_extern _private_extern3 +.private_extern _private_extern4 +.private_extern _private_extern5 +.private_extern _private_extern6 +.private_extern _private_extern7 +.private_extern _private_extern8 +.private_extern _private_extern9 +.private_extern _private_extern10 + +_private_extern1: + retq + +_private_extern2: + retq + +_private_extern3: + retq + +_private_extern4: + retq + +_private_extern5: + retq + +_private_extern6: + retq + +_private_extern7: + retq + +_private_extern8: + retq + +_private_extern9: + retq + +_private_extern10: + retq