Index: COFF/Config.h =================================================================== --- COFF/Config.h +++ COFF/Config.h @@ -80,8 +80,10 @@ SymbolBody *Entry = nullptr; bool NoEntry = false; std::string OutputFile; + bool ColorDiagnostics; bool DoGC = true; bool DoICF = true; + uint64_t ErrorLimit = 20; bool Relocatable = true; bool Force = false; bool Debug = false; Index: COFF/Driver.cpp =================================================================== --- COFF/Driver.cpp +++ COFF/Driver.cpp @@ -55,8 +55,13 @@ StringSaver Saver{BAlloc}; std::vector SpecificAllocBase::Instances; -bool link(ArrayRef Args) { +bool link(ArrayRef Args, raw_ostream &Diag) { + ErrorCount = 0; + ErrorOS = &Diag; + Argv0 = Args[0]; Config = make(); + Config->ColorDiagnostics = + (ErrorOS == &llvm::errs() && Process::StandardErrHasColors()); Driver = make(); Driver->link(Args); return true; Index: COFF/Error.h =================================================================== --- COFF/Error.h +++ COFF/Error.h @@ -16,6 +16,12 @@ namespace lld { namespace coff { +extern uint64_t ErrorCount; +extern llvm::raw_ostream *ErrorOS; +extern llvm::StringRef Argv0; + +void warn(const Twine &Msg); +void error(const Twine &Msg); LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); LLVM_ATTRIBUTE_NORETURN void fatal(std::error_code EC, const Twine &Prefix); LLVM_ATTRIBUTE_NORETURN void fatal(llvm::Error &Err, const Twine &Prefix); Index: COFF/Error.cpp =================================================================== --- COFF/Error.cpp +++ COFF/Error.cpp @@ -8,11 +8,14 @@ //===----------------------------------------------------------------------===// #include "Error.h" +#include "Config.h" #include "llvm/ADT/Twine.h" #include "llvm/Support/Error.h" +#include "llvm/Support/ManagedStatic.h" #include "llvm/Support/Process.h" #include "llvm/Support/raw_ostream.h" +#include #if !defined(_MSC_VER) && !defined(__MINGW32__) #include @@ -21,10 +24,55 @@ using namespace llvm; namespace lld { +// The functions defined in this file can be called from multiple threads, +// but outs() or errs() are not thread-safe. We protect them using a mutex. +static std::mutex Mu; + namespace coff { +StringRef Argv0; +uint64_t ErrorCount; +raw_ostream *ErrorOS; + +static LLVM_ATTRIBUTE_NORETURN void exitLld(int Val) { + // Dealloc/destroy ManagedStatic variables before calling + // _exit(). In a non-LTO build, this is a nop. In an LTO + // build allows us to get the output of -time-passes. + llvm_shutdown(); + + outs().flush(); + errs().flush(); + _exit(Val); +} + +static void print(StringRef S, raw_ostream::Colors C) { + *ErrorOS << Argv0 + ": "; + if (Config->ColorDiagnostics) { + ErrorOS->changeColor(C, true); + *ErrorOS << S; + ErrorOS->resetColor(); + } else { + *ErrorOS << S; + } +} + +void error(const Twine &Msg) { + std::lock_guard Lock(Mu); + + if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << Msg << "\n"; + } else if (ErrorCount == Config->ErrorLimit) { + print("error: ", raw_ostream::RED); + *ErrorOS << "too many errors emitted, stopping now" + << " (use -error-limit=0 to see all errors)\n"; + exitLld(1); + } + + ++ErrorCount; +} void fatal(const Twine &Msg) { - if (sys::Process::StandardErrHasColors()) { + if (Config->ColorDiagnostics) { errs().changeColor(raw_ostream::RED, /*bold=*/true); errs() << "error: "; errs().resetColor(); @@ -32,10 +80,7 @@ errs() << "error: "; } errs() << Msg << "\n"; - - outs().flush(); - errs().flush(); - _exit(1); + exitLld(1); } void fatal(std::error_code EC, const Twine &Msg) { @@ -46,5 +91,11 @@ fatal(errorToErrorCode(std::move(Err)), Msg); } +void warn(const Twine &Msg) { + std::lock_guard Lock(Mu); + print("warning: ", raw_ostream::MAGENTA); + *ErrorOS << Msg << "\n"; +} + } // namespace coff } // namespace lld Index: include/lld/Driver/Driver.h =================================================================== --- include/lld/Driver/Driver.h +++ include/lld/Driver/Driver.h @@ -15,7 +15,8 @@ namespace lld { namespace coff { -bool link(llvm::ArrayRef Args); +bool link(llvm::ArrayRef Args, + llvm::raw_ostream &Diag = llvm::errs()); } namespace elf {