// For --build-id.
enum class BuildIdKind { None, Fast, Md5, Sha1, Hexstring, Uuid };
+// For --color-diagnostics.
+enum class ColorPolicy { Auto, Always, Never };
+
// For --discard-{all,locals,none}.
enum class DiscardPolicy { Default, All, Locals, None };
bool ZRelro;
bool ExitEarly;
bool ZWxneeded;
+ ColorPolicy ColorDiagnostics = ColorPolicy::Auto;
DiscardPolicy Discard;
SortSectionPolicy SortSection;
StripPolicy Strip = StripPolicy::None;
return Default;
}
+// Parse -color-diagnostics={auto,always,never} or -no-color-diagnostics.
+static ColorPolicy getColorDiagnostics(opt::InputArgList &Args) {
+ auto *Arg = Args.getLastArg(OPT_color_diagnostics, OPT_no_color_diagnostics);
+ if (!Arg)
+ return ColorPolicy::Auto;
+ if (Arg->getOption().getID() == OPT_no_color_diagnostics)
+ return ColorPolicy::Never;
+
+ StringRef S = Arg->getValue();
+ if (S == "auto")
+ return ColorPolicy::Auto;
+ if (S == "always")
+ return ColorPolicy::Always;
+ if (S != "never")
+ error("unknown -color-diagnostics value: " + S);
+ return ColorPolicy::Never;
+}
+
static DiscardPolicy getDiscardOption(opt::InputArgList &Args) {
auto *Arg =
Args.getLastArg(OPT_discard_all, OPT_discard_locals, OPT_discard_none);
Config->AllowMultipleDefinition = Args.hasArg(OPT_allow_multiple_definition);
Config->Bsymbolic = Args.hasArg(OPT_Bsymbolic);
Config->BsymbolicFunctions = Args.hasArg(OPT_Bsymbolic_functions);
+ Config->ColorDiagnostics = getColorDiagnostics(Args);
Config->Demangle = getArg(Args, OPT_demangle, OPT_no_demangle, true);
Config->DisableVerify = Args.hasArg(OPT_disable_verify);
Config->Discard = getDiscardOption(Args);
#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 <mutex>
#include <unistd.h>
#endif
+using namespace lld::elf;
using namespace llvm;
namespace lld {
// but outs() or errs() are not thread-safe. We protect them using a mutex.
static std::mutex Mu;
+static bool useColor() {
+ if (Config->ColorDiagnostics == ColorPolicy::Always)
+ return true;
+ if (Config->ColorDiagnostics == ColorPolicy::Never)
+ return false;
+ return ErrorOS == &errs() && sys::Process::StandardErrHasColors();
+}
+
+static void print(StringRef S, raw_ostream::Colors C) {
+ if (useColor()) {
+ ErrorOS->changeColor(raw_ostream::WHITE, /*Bold=*/true);
+ *ErrorOS << Argv0 + ": ";
+ ErrorOS->changeColor(C, true);
+ *ErrorOS << S;
+ ErrorOS->resetColor();
+ } else {
+ *ErrorOS << Argv0 + ": " << S;
+ }
+}
+
void elf::log(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
if (Config->Verbose)
return;
}
std::lock_guard<std::mutex> Lock(Mu);
- *ErrorOS << Argv0 << ": warning: " << Msg << "\n";
+ print("warning: ", raw_ostream::MAGENTA);
+ *ErrorOS << Msg << "\n";
}
void elf::error(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
if (Config->ErrorLimit == 0 || ErrorCount < Config->ErrorLimit) {
- *ErrorOS << Argv0 << ": error: " << Msg << "\n";
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << Msg << "\n";
} else if (ErrorCount == Config->ErrorLimit) {
- *ErrorOS << Argv0 << ": error: too many errors emitted, stopping now"
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << "too many errors emitted, stopping now"
<< " (use -error-limit=0 to see all errors)\n";
if (Config->ExitEarly)
exitLld(1);
void elf::fatal(const Twine &Msg) {
std::lock_guard<std::mutex> Lock(Mu);
- *ErrorOS << Argv0 << ": error: " << Msg << "\n";
+ print("error: ", raw_ostream::RED);
+ *ErrorOS << Msg << "\n";
exitLld(1);
}
def as_needed: F<"as-needed">,
HelpText<"Only set DT_NEEDED for shared libraries if used">;
+def color_diagnostics: S<"color-diagnostics">,
+ HelpText<"Use colors in diagnostics">;
+
def disable_new_dtags: F<"disable-new-dtags">,
HelpText<"Disable new dynamic tags">;
def no_as_needed: F<"no-as-needed">,
HelpText<"Always DT_NEEDED for shared libraries">;
+def no_color_diagnostics: F<"no-color-diagnostics">,
+ HelpText<"Do not use colors in diagnostics">;
+
def no_demangle: F<"no-demangle">,
HelpText<"Do not demangle symbol names">;
def alias_Bstatic_non_shared: F<"non_shared">, Alias<Bstatic>;
def alias_Bstatic_static: F<"static">, Alias<Bstatic>;
def alias_L__library_path: J<"library-path=">, Alias<L>;
+def alias_color_diagnostics: J<"color-diagnostics=">, Alias<color_diagnostics>;
def alias_discard_all_x: Flag<["-"], "x">, Alias<discard_all>;
def alias_discard_locals_X: Flag<["-"], "X">, Alias<discard_locals>;
def alias_dynamic_list: J<"dynamic-list=">, Alias<dynamic_list>;
--- /dev/null
+# Windows command prompt doesn't support ANSI escape sequences.
+# REQUIRES: shell
+
+# RUN: not ld.lld -color-diagnostics=always /nosuchfile 2>&1 \
+# RUN: | FileCheck -check-prefix=COLOR %s
+
+# COLOR: {{^.\[0;1;37m.*/ld.lld: .\[0;1;31merror: .\[0mcannot open /nosuchfile}}
+
+# RUN: not ld.lld -color-diagnostics=always -no-color-diagnostics /nosuchfile 2>&1 \
+# RUN: | FileCheck -check-prefix=NOCOLOR %s
+
+# NOCOLOR: ld.lld: error: cannot open /nosuchfile