diff --git a/lld/Common/ErrorHandler.cpp b/lld/Common/ErrorHandler.cpp --- a/lld/Common/ErrorHandler.cpp +++ b/lld/Common/ErrorHandler.cpp @@ -16,6 +16,7 @@ #include "llvm/Support/ManagedStatic.h" #include "llvm/Support/raw_ostream.h" #include +#include #if !defined(_MSC_VER) && !defined(__MINGW32__) #include @@ -84,8 +85,27 @@ [&](ErrorInfoBase &EIB) { error(EIB.message()); }); } -void ErrorHandler::print(StringRef S, raw_ostream::Colors C) { - *ErrorOS << LogName << ": "; +static std::string getLocation(std::string Msg, std::string Default) { + static std::vector Regexes{ + std::regex(R"(^undefined symbol:.*\n>>> referenced by (\S+))"), + std::regex(R"(^duplicate symbol:.*\n>>> defined at (\S+))") + }; + + std::smatch Match; + for (std::regex &Re : Regexes) + if (std::regex_search(Msg, Match, Re)) + return Match.str(1); + return Default; +} + +void ErrorHandler::printHeader(StringRef S, raw_ostream::Colors C, const Twine &Msg) { + if (VsDiag) { + // Visual Studio-style error message starts with an error location. + *ErrorOS << getLocation(Msg.str(), LogName) << ": "; + } else { + *ErrorOS << LogName << ": "; + } + if (ColorDiagnostics) { ErrorOS->changeColor(C, true); *ErrorOS << S; @@ -116,7 +136,7 @@ std::lock_guard Lock(Mu); newline(ErrorOS, Msg); - print("warning: ", raw_ostream::MAGENTA); + printHeader("warning: ", raw_ostream::MAGENTA, Msg); *ErrorOS << Msg << "\n"; } @@ -125,10 +145,10 @@ newline(ErrorOS, Msg); if (ErrorLimit == 0 || ErrorCount < ErrorLimit) { - print("error: ", raw_ostream::RED); + printHeader("error: ", raw_ostream::RED, Msg); *ErrorOS << Msg << "\n"; } else if (ErrorCount == ErrorLimit) { - print("error: ", raw_ostream::RED); + printHeader("error: ", raw_ostream::RED, Msg); *ErrorOS << ErrorLimitExceededMsg << "\n"; if (ExitEarly) exitLld(1); diff --git a/lld/ELF/Driver.cpp b/lld/ELF/Driver.cpp --- a/lld/ELF/Driver.cpp +++ b/lld/ELF/Driver.cpp @@ -750,6 +750,8 @@ errorHandler().Verbose = Args.hasArg(OPT_verbose); errorHandler().FatalWarnings = Args.hasFlag(OPT_fatal_warnings, OPT_no_fatal_warnings, false); + errorHandler().VsDiag = Args.hasArg(OPT_vs_diagnostics); + ThreadsEnabled = Args.hasFlag(OPT_threads, OPT_no_threads, true); Config->AllowMultipleDefinition = diff --git a/lld/ELF/Options.td b/lld/ELF/Options.td --- a/lld/ELF/Options.td +++ b/lld/ELF/Options.td @@ -361,6 +361,9 @@ defm version_script: Eq<"version-script", "Read a version script">; +def vs_diagnostics: F<"vs-diagnostics">, + HelpText<"Changes diagnostic output format to better match Microsoft Visual Studio">; + defm warn_backrefs: B<"warn-backrefs", "Warn about backward symbol references to fetch archive members", "Do not warn about backward symbol references to fetch archive members (default)">; diff --git a/lld/include/lld/Common/ErrorHandler.h b/lld/include/lld/Common/ErrorHandler.h --- a/lld/include/lld/Common/ErrorHandler.h +++ b/lld/include/lld/Common/ErrorHandler.h @@ -91,6 +91,7 @@ bool ExitEarly = true; bool FatalWarnings = false; bool Verbose = false; + bool VsDiag = false; void error(const Twine &Msg); LLVM_ATTRIBUTE_NORETURN void fatal(const Twine &Msg); @@ -101,7 +102,7 @@ std::unique_ptr OutputBuffer; private: - void print(StringRef S, raw_ostream::Colors C); + void printHeader(StringRef S, raw_ostream::Colors C, const Twine &Msg); }; /// Returns the default error handler.