Configuration *config;
LinkerDriver *driver;
-bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &diag) {
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
+ raw_ostream &stderrOS) {
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
- errorHandler().errorOS = &diag;
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now"
" (use /errorlimit:0 to see all errors)";
errorHandler().exitEarly = canExitEarly;
- enableColors(diag.has_colors());
+ enableColors(stderrOS.has_colors());
+
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
config = make<Configuration>();
symtab = make<SymbolTable>();
// because it doesn't start with "/", but we deliberately chose "--" to
// avoid conflict with /version and for compatibility with clang-cl.
if (args.hasArg(OPT_dash_dash_version)) {
- outs() << getLLDVersion() << "\n";
+ lld::outs() << getLLDVersion() << "\n";
return;
}
}
void printHelp(const char *argv0) {
- COFFOptTable().PrintHelp(outs(),
+ COFFOptTable().PrintHelp(lld::outs(),
(std::string(argv0) + " [options] file...").c_str(),
"LLVM Linker", false);
}
[](const Entry &a, const Entry &b) { return a.begin < b.begin; });
return;
}
- errs() << "warning: don't know how to handle .pdata.\n";
+ lld::errs() << "warning: don't know how to handle .pdata.\n";
}
// The CRT section contains, among other things, the array of function
using 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.
+// but lld::outs() or lld::errs() are not thread-safe. We protect them using a
+// mutex.
static std::mutex mu;
// We want to separate multi-line messages with a newline. `sep` is "\n"
return "";
}
+raw_ostream *lld::stdoutOS;
+raw_ostream *lld::stderrOS;
+
+raw_ostream &lld::outs() { return stdoutOS ? *stdoutOS : llvm::outs(); }
+raw_ostream &lld::errs() { return stderrOS ? *stderrOS : llvm::errs(); }
+
ErrorHandler &lld::errorHandler() {
static ErrorHandler handler;
return handler;
}
-void lld::enableColors(bool enable) {
- errorHandler().errorOS->enable_colors(enable);
-}
+void lld::enableColors(bool enable) { lld::errs().enable_colors(enable); }
void lld::exitLld(int val) {
// Delete any temporary file, while keeping the memory mapping open.
// build allows us to get the output of -time-passes.
llvm_shutdown();
- outs().flush();
- errs().flush();
+ lld::outs().flush();
+ lld::errs().flush();
_exit(val);
}
if (!verbose)
return;
std::lock_guard<std::mutex> lock(mu);
- *errorOS << logName << ": " << msg << "\n";
+ lld::errs() << logName << ": " << msg << "\n";
}
void ErrorHandler::message(const Twine &msg) {
std::lock_guard<std::mutex> lock(mu);
- outs() << msg << "\n";
- outs().flush();
+ lld::outs() << msg << "\n";
+ lld::outs().flush();
}
void ErrorHandler::warn(const Twine &msg) {
}
std::lock_guard<std::mutex> lock(mu);
- *errorOS << sep << getLocation(msg) << ": " << Colors::MAGENTA
- << "warning: " << Colors::RESET << msg << "\n";
+ lld::errs() << sep << getLocation(msg) << ": " << Colors::MAGENTA
+ << "warning: " << Colors::RESET << msg << "\n";
sep = getSeparator(msg);
}
std::lock_guard<std::mutex> lock(mu);
if (errorLimit == 0 || errorCount < errorLimit) {
- *errorOS << sep << getLocation(msg) << ": " << Colors::RED
- << "error: " << Colors::RESET << msg << "\n";
+ lld::errs() << sep << getLocation(msg) << ": " << Colors::RED
+ << "error: " << Colors::RESET << msg << "\n";
} else if (errorCount == errorLimit) {
- *errorOS << sep << getLocation(msg) << ": " << Colors::RED
- << "error: " << Colors::RESET << errorLimitExceededMsg << "\n";
+ lld::errs() << sep << getLocation(msg) << ": " << Colors::RED
+ << "error: " << Colors::RESET << errorLimitExceededMsg << "\n";
if (exitEarly)
exitLld(1);
}
static void setConfigs(opt::InputArgList &args);
static void readConfigs(opt::InputArgList &args);
-bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &error) {
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
+ raw_ostream &stderrOS) {
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
- errorHandler().errorOS = &error;
errorHandler().exitEarly = canExitEarly;
- enableColors(error.has_colors());
+ enableColors(stderrOS.has_colors());
+
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
inputSections.clear();
outputSections.clear();
void printHelp() {
ELFOptTable().PrintHelp(
- outs(), (config->progName + " [options] file...").str().c_str(), "lld",
- false /*ShowHidden*/, true /*ShowAllAliases*/);
- outs() << "\n";
+ lld::outs(), (config->progName + " [options] file...").str().c_str(),
+ "lld", false /*ShowHidden*/, true /*ShowAllAliases*/);
+ lld::outs() << "\n";
// Scripts generated by Libtool versions up to at least 2.4.6 (the most
// recent version as of March 2017) expect /: supported targets:.* elf/
// in a message for the -help option. If it doesn't match, the scripts
// assume that the linker doesn't support very basic features such as
// shared libraries. Therefore, we need to print out at least "elf".
- outs() << config->progName << ": supported targets: elf\n";
+ lld::outs() << config->progName << ": supported targets: elf\n";
}
static std::string rewritePath(StringRef s) {
}
static void print(StringRef a, StringRef b) {
- outs() << left_justify(a, 49) << " " << b << "\n";
+ lld::outs() << left_justify(a, 49) << " " << b << "\n";
}
// Output a cross reference table to stdout. This is for --cref.
}
// Print out a header.
- outs() << "Cross Reference Table\n\n";
+ lld::outs() << "Cross Reference Table\n\n";
print("Symbol", "File");
// Print out a table.
static void printHelp(const char *argv0) {
MinGWOptTable().PrintHelp(
- outs(), (std::string(argv0) + " [options] file...").c_str(), "lld",
+ lld::outs(), (std::string(argv0) + " [options] file...").c_str(), "lld",
false /*ShowHidden*/, true /*ShowAllAliases*/);
- outs() << "\n";
+ lld::outs() << "\n";
}
static cl::TokenizerCallback getQuotingStyle() {
// Convert Unix-ish command line arguments to Windows-ish ones and
// then call coff::link.
-bool mingw::link(ArrayRef<const char *> argsArr, raw_ostream &diag) {
- enableColors(diag.has_colors());
+bool mingw::link(ArrayRef<const char *> argsArr, bool canExitEarly,
+ raw_ostream &stdoutOS, raw_ostream &stderrOS) {
+ enableColors(stderrOS.has_colors());
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
MinGWOptTable parser;
opt::InputArgList args = parser.parse(argsArr.slice(1));
return false;
if (args.hasArg(OPT_verbose) || args.hasArg(OPT__HASH_HASH_HASH))
- outs() << llvm::join(linkArgs, " ") << "\n";
+ lld::outs() << llvm::join(linkArgs, " ") << "\n";
if (args.hasArg(OPT__HASH_HASH_HASH))
return true;
std::vector<const char *> vec;
for (const std::string &s : linkArgs)
vec.push_back(s.c_str());
- return coff::link(vec, true);
+ return coff::link(vec, true, stdoutOS, stderrOS);
}
namespace lld {
namespace coff {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
- llvm::raw_ostream &diag = llvm::errs());
+ llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
}
namespace mingw {
-bool link(llvm::ArrayRef<const char *> args,
- llvm::raw_ostream &diag = llvm::errs());
+bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
+ llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
}
namespace elf {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
- llvm::raw_ostream &diag = llvm::errs());
+ llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
}
namespace mach_o {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
- llvm::raw_ostream &diag = llvm::errs());
+ llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
}
namespace wasm {
bool link(llvm::ArrayRef<const char *> args, bool canExitEarly,
- llvm::raw_ostream &diag = llvm::errs());
+ llvm::raw_ostream &stdout, llvm::raw_ostream &stderr);
}
}
//
// warn() doesn't do anything but printing out a given message.
//
-// It is not recommended to use llvm::outs() or llvm::errs() directly in lld
+// It is not recommended to use llvm::outs() or lld::errs() directly in lld
// because they are not thread-safe. The functions declared in this file are
// thread-safe.
//
namespace llvm {
class DiagnosticInfo;
+class raw_ostream;
}
namespace lld {
+// We wrap stdout and stderr so that you can pass alternative stdout/stderr as
+// arguments to lld::*::link() functions.
+extern llvm::raw_ostream *stdoutOS;
+extern llvm::raw_ostream *stderrOS;
+
+llvm::raw_ostream &outs();
+llvm::raw_ostream &errs();
+
class ErrorHandler {
public:
uint64_t errorCount = 0;
uint64_t errorLimit = 20;
StringRef errorLimitExceededMsg = "too many errors emitted, stopping now";
StringRef logName = "lld";
- llvm::raw_ostream *errorOS = &llvm::errs();
bool exitEarly = true;
bool fatalWarnings = false;
bool verbose = false;
} // namespace llvm
namespace lld {
+llvm::raw_ostream &outs();
+llvm::raw_ostream &errs();
+
// Casting operators.
using llvm::cast;
using llvm::cast_or_null;
if (!file)
return true;
if (std::error_code ec = file->parse()) {
- llvm::errs() << "Cannot open " + file->path()
- << ": " << ec.message() << "\n";
+ lld::errs() << "Cannot open " + file->path() << ": " << ec.message()
+ << "\n";
return false;
}
DEBUG_WITH_TYPE("resolver",
if (auto EC = undefAddedOrError.takeError()) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- llvm::errs() << "Error in " + file->path() << ": ";
- logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ lld::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), lld::errs(), std::string());
return false;
}
undefAdded = undefAddedOrError.get();
if (auto EC = undefAddedOrError.takeError()) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- llvm::errs() << "Error in " + file->path() << ": ";
- logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ lld::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), lld::errs(), std::string());
return false;
}
undefAdded = undefAddedOrError.get();
if (auto EC = handleSharedLibrary(*file)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- llvm::errs() << "Error in " + file->path() << ": ";
- logAllUnhandledErrors(std::move(EC), llvm::errs(), std::string());
+ lld::errs() << "Error in " + file->path() << ": ";
+ logAllUnhandledErrors(std::move(EC), lld::errs(), std::string());
return false;
}
break;
// Seems like this symbol is undefined. Warn that.
foundUndefines = true;
if (_ctx.printRemainingUndefines()) {
- llvm::errs() << "Undefined symbol: " << undef->file().path()
- << ": " << _ctx.demangle(undef->name())
- << "\n";
+ lld::errs() << "Undefined symbol: " << undef->file().path() << ": "
+ << _ctx.demangle(undef->name()) << "\n";
}
}
if (!foundUndefines)
return false;
if (_ctx.printRemainingUndefines())
- llvm::errs() << "symbol(s) not found\n";
+ lld::errs() << "symbol(s) not found\n";
return true;
}
useNew = true;
break;
}
- llvm::errs() << "Size mismatch: "
- << existing->name() << " (" << existingSize << ") "
- << newAtom.name() << " (" << newSize << ")\n";
+ lld::errs() << "Size mismatch: " << existing->name() << " ("
+ << existingSize << ") " << newAtom.name() << " (" << newSize
+ << ")\n";
LLVM_FALLTHROUGH;
}
case MCR_Error:
- llvm::errs() << "Duplicate symbols: "
- << existing->name()
- << ":"
- << existing->file().path()
- << " and "
- << newAtom.name()
- << ":"
- << newAtom.file().path()
- << "\n";
+ lld::errs() << "Duplicate symbols: " << existing->name() << ":"
+ << existing->file().path() << " and " << newAtom.name() << ":"
+ << newAtom.file().path() << "\n";
llvm::report_fatal_error("duplicate symbol error");
break;
}
break;
}
case NCR_Error:
- llvm::errs() << "SymbolTable: error while merging " << name << "\n";
+ lld::errs() << "SymbolTable: error while merging " << name << "\n";
llvm::report_fatal_error("duplicate symbol error");
break;
}
sym = prefixAndSym.first;
if (!sym.empty()) {
ctx.appendOrderedSymbol(sym, prefix);
- //llvm::errs() << sym << ", prefix=" << prefix << "\n";
+ // lld::errs() << sym << ", prefix=" << prefix << "\n";
}
}
return std::error_code();
!parsedArgs.getLastArg(OPT_test_file_usage)) {
// If no -arch and no options at all, print usage message.
if (parsedArgs.size() == 0) {
- table.PrintHelp(llvm::outs(),
+ table.PrintHelp(lld::outs(),
(std::string(args[0]) + " [options] file...").c_str(),
"LLVM Linker", false);
} else {
/// This is where the link is actually performed.
bool link(llvm::ArrayRef<const char *> args, bool CanExitEarly,
- raw_ostream &Error) {
+ raw_ostream &StdoutOS, raw_ostream &StderrOS) {
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"'-error-limit 0' to see all errors)";
- errorHandler().errorOS = &Error;
errorHandler().exitEarly = CanExitEarly;
- enableColors(Error.has_colors());
+ enableColors(StderrOS.has_colors());
+
+ lld::stdoutOS = &StdoutOS;
+ lld::stderrOS = &StderrOS;
MachOLinkingContext ctx;
if (!parse(args, ctx))
if (auto ec = pm.runOnFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- *errorHandler().errorOS << "Failed to run passes on file '"
- << ctx.outputPath() << "': ";
- logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS,
- std::string());
+ lld::errs() << "Failed to run passes on file '" << ctx.outputPath()
+ << "': ";
+ logAllUnhandledErrors(std::move(ec), lld::errs(), std::string());
return false;
}
if (auto ec = ctx.writeFile(*merged)) {
// FIXME: This should be passed to logAllUnhandledErrors but it needs
// to be passed a Twine instead of a string.
- *errorHandler().errorOS << "Failed to write file '" << ctx.outputPath()
- << "': ";
- logAllUnhandledErrors(std::move(ec), *errorHandler().errorOS,
- std::string());
+ lld::errs() << "Failed to write file '" << ctx.outputPath() << "': ";
+ logAllUnhandledErrors(std::move(ec), lld::errs(), std::string());
return false;
}
+ mb.getBufferIdentifier() + ")").str();
if (_logLoading)
- llvm::errs() << memberPath << "\n";
+ lld::errs() << memberPath << "\n";
std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
mb.getBuffer(), mb.getBufferIdentifier(), false));
return leftOrdinal < rightOrdinal;
}
- llvm::errs() << "Unordered: <" << left->name() << "> <"
- << right->name() << ">\n";
+ lld::errs() << "Unordered: <" << left->name() << "> <" << right->name()
+ << ">\n";
llvm_unreachable("Atoms with Same Ordinal!");
}
void MachOLinkingContext::addExportSymbol(StringRef sym) {
// Support old crufty export lists with bogus entries.
if (sym.endswith(".eh") || sym.startswith(".objc_category_name_")) {
- llvm::errs() << "warning: ignoring " << sym << " in export list\n";
+ lld::errs() << "warning: ignoring " << sym << " in export list\n";
return;
}
// Only i386 MacOSX uses old ABI, so don't change those.
});
// Debug logging of symbols.
- //for (const Symbol *sym : symbols)
- // llvm::errs() << " sym: "
+ // for (const Symbol *sym : symbols)
+ // lld::errs() << " sym: "
// << llvm::format("0x%08llx ", (uint64_t)sym->value)
// << ", " << sym->name << "\n";
};
LLVM_ATTRIBUTE_NORETURN static void die(const Twine &s) {
- errs() << s << "\n";
+ llvm::errs() << s << "\n";
exit(1);
}
switch (parseFlavor(args)) {
case Gnu:
if (isPETarget(args))
- return !mingw::link(args);
- return !elf::link(args, canExitEarly());
+ return !mingw::link(args, canExitEarly(), llvm::outs(), llvm::errs());
+ return !elf::link(args, canExitEarly(), llvm::outs(), llvm::errs());
case WinLink:
- return !coff::link(args, canExitEarly());
+ return !coff::link(args, canExitEarly(), llvm::outs(), llvm::errs());
case Darwin:
- return !mach_o::link(args, canExitEarly());
+ return !mach_o::link(args, canExitEarly(), llvm::outs(), llvm::errs());
case Wasm:
- return !wasm::link(args, canExitEarly());
+ return !wasm::link(args, canExitEarly(), llvm::outs(), llvm::errs());
default:
die("lld is a generic driver.\n"
"Invoke ld.lld (Unix), ld64.lld (macOS), lld-link (Windows), wasm-ld"
EXPECT_EQ(tlv.isExtern, true);
EXPECT_EQ(tlv.symbol, 1U);
- //llvm::errs() << "temp = " << tmpFl << "\n";
+ // lld::errs() << "temp = " << tmpFl << "\n";
bufferOwner.reset(nullptr);
std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
EXPECT_FALSE(ec);
EXPECT_EQ(absPointer.isExtern, true);
EXPECT_EQ(absPointer.symbol, 2U);
- //llvm::errs() << "temp = " << tmpFl << "\n";
+ // lld::errs() << "temp = " << tmpFl << "\n";
bufferOwner.reset(nullptr);
std::error_code ec = llvm::sys::fs::remove(Twine(tmpFl));
EXPECT_FALSE(ec);
};
} // anonymous namespace
-bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &error) {
+bool link(ArrayRef<const char *> args, bool canExitEarly, raw_ostream &stdoutOS,
+ raw_ostream &stderrOS) {
errorHandler().logName = args::getFilenameWithoutExe(args[0]);
- errorHandler().errorOS = &error;
errorHandler().errorLimitExceededMsg =
"too many errors emitted, stopping now (use "
"-error-limit=0 to see all errors)";
- enableColors(error.has_colors());
+ enableColors(stderrOS.has_colors());
+
+ lld::stdoutOS = &stdoutOS;
+ lld::stderrOS = &stderrOS;
config = make<Configuration>();
symtab = make<SymbolTable>();
// Handle --help
if (args.hasArg(OPT_help)) {
- parser.PrintHelp(outs(),
+ parser.PrintHelp(lld::outs(),
(std::string(argsArr[0]) + " [options] file...").c_str(),
"LLVM Linker", false);
return;
// Handle --version
if (args.hasArg(OPT_version) || args.hasArg(OPT_v)) {
- outs() << getLLDVersion() << "\n";
+ lld::outs() << getLLDVersion() << "\n";
return;
}